Projekt

Allgemein

Profil

Herunterladen (14,3 KB) Statistiken
| Zweig: | Markierung: | Revision:
/***************************************************************************
$RCSfile$
-------------------
cvs : $Id$
begin : Mon Jan 05 2004
copyright : (C) 2004 by Martin Preuss
email : martin@libchipcard.de

***************************************************************************
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
* *
***************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "padd_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/error.h>
#include <gwenhywfar/cryptdefs.h>
#include <string.h>
#include <stdlib.h>




/*
* This code has been taken from OpenHBCI (rsakey.cpp, written by Fabian
* Kaiser)
*/
unsigned char GWEN_Padd_permutate(unsigned char input) {
unsigned char leftNibble;
unsigned char rightNibble;
static const unsigned char lookUp[2][16] =
{{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
{14,3,5,8,9,4,2,15,0,13,11,6,7,10,12,1}};

rightNibble = input & 15;
leftNibble = input & 240;
leftNibble = leftNibble / 16;
rightNibble = lookUp[1][rightNibble];
leftNibble = lookUp[1][leftNibble];
leftNibble = leftNibble * 16;

return leftNibble + rightNibble;
}



/*
* The original code (in C++) has been written by Fabian Kaiser for OpenHBCI
* (file rsakey.cpp). Translated to C by Martin Preuss
*/
int GWEN_Padd_PaddWithISO9796(GWEN_BUFFER *src) {
unsigned char *p;
unsigned int l;
unsigned int i;
unsigned char buffer[GWEN_PADD_ISO9796_KEYSIZE];
unsigned char hash[20];
unsigned char c;

p=(unsigned char*)GWEN_Buffer_GetStart(src);
l=GWEN_Buffer_GetUsedBytes(src);
memmove(hash, p, l);

/* src+src+src */
if (GWEN_Buffer_AppendBytes(src, (const char*)hash, l)) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return -1;
}

if (GWEN_Buffer_AppendBytes(src, (const char*)hash, l)) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return -1;
}

/* src=src(20,40) */
if (GWEN_Buffer_Crop(src, 20, 40)) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return -1;
}

memset(buffer, 0, sizeof(buffer));

/* append redundancy */
p=(unsigned char*)GWEN_Buffer_GetStart(src);
for (i=0; i<=47; i++) {
int j1, j2, j3;

j1=1 + sizeof(buffer) - (2*i);
j2=40-i;
j3=sizeof(buffer) - (2*i);

if (j1>=0 && j1<(int)sizeof(buffer) && j2>=0) {
buffer[j1]=p[j2];
}
if (j3>=0 && j3<(int)sizeof(buffer) && j2>=0) {
buffer[j3]=GWEN_Padd_permutate(p[j2]);
}
} /* for */

/* copy last 16 bytes to the beginning */
memmove(buffer, buffer+(sizeof(buffer)-16), 16);

p=buffer;
/* finish */
c=p[sizeof(buffer)-1];
c = (c & 15) * 16;
c += 6;
p[sizeof(buffer)-1]=c;
p[0] = p[0] & 127;
p[0] = p[0] | 64;
p[sizeof(buffer) - 40] = p[sizeof(buffer) - 40] ^ 1;

GWEN_Buffer_Reset(src);
if (GWEN_Buffer_AppendBytes(src, (const char*)buffer, sizeof(buffer))) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return -1;
}

return 0;
}


#if 0
int GWEN_Padd_PaddWithIso9796_2(GWEN_BUFFER *buf, int dstSize){
unsigned int diff;
char *p;
int i;

if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)+31) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
return GWEN_ERROR_INVALID;
}

/* add trailer */
GWEN_Buffer_AppendByte(buf, 0xbc);

/* reset position to 0 */
GWEN_Buffer_Rewind(buf);

/* insert room for header */
diff=dstSize-31;
if (GWEN_Buffer_InsertRoom(buf, 1+diff+1+8)) {
DBG_ERROR(GWEN_LOGDOMAIN,
"Could not insert room for %d bytes",
1+diff+1+8);
return GWEN_ERROR_GENERIC;
}

/* insert header and more-data-bit */
p=GWEN_Buffer_GetStart(buf);
*(p++)=0x60;

/* insert padding field */
for (i=0; i<diff; i++)
*(p++)=0x0;
*(p++)=0x01;

/* insert 8 random bytes */
GWEN_Crypt_Random(2, (uint8_t*)p, 8);
for (i=0; i<8; i++) {
if (*p==0)
/* TODO: Need to find a better but yet fast way */
*p=0xff;
p++;
}
*(p++)=0x01;

return 0;
}



int GWEN_Padd_UnpaddWithIso9796_2(GWEN_BUFFER *buf){
uint32_t l;

l=GWEN_Buffer_GetUsedBytes(buf);
if (l<31) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too few bytes");
return GWEN_ERROR_INVALID;
}

GWEN_Buffer_Crop(buf, l-21, 20);

return 0;
}

#else
int GWEN_Padd_PaddWithIso9796_2(GWEN_BUFFER *buf, int dstSize){
unsigned int diff;
char *p;
int i;

if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)+12) {
/*DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");*/
return GWEN_ERROR_INVALID;
}

/* add trailer */
GWEN_Buffer_AppendByte(buf, 0xbc);

/* reset position to 0 */
GWEN_Buffer_Rewind(buf);

/* insert room for header */
diff=dstSize-GWEN_Buffer_GetUsedBytes(buf)-11+1;
if (GWEN_Buffer_InsertRoom(buf, 1+diff+1+8)) {
DBG_ERROR(GWEN_LOGDOMAIN,
"Could not insert room for %d bytes",
1+diff+1+8);
return GWEN_ERROR_GENERIC;
}

/* insert header and more-data-bit */
p=GWEN_Buffer_GetStart(buf);
*(p++)=0x60;

/* insert padding field */
for (i=0; i<diff; i++)
*(p++)=0x0;
*(p++)=0x01;

/* insert 8 random bytes */
GWEN_Crypt_Random(2, (uint8_t*)p, 8);
for (i=0; i<8; i++) {
if (*p==0)
/* TODO: Need to find a better but yet fast way */
*p=0xff;
p++;
}

return 0;
}


int GWEN_Padd_UnpaddWithIso9796_2(GWEN_BUFFER *buf){
uint32_t l;
uint32_t realSize;
const uint8_t *p;

l=GWEN_Buffer_GetUsedBytes(buf);
if (l<11) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too few bytes");
return GWEN_ERROR_INVALID;
}

p=(const uint8_t*)GWEN_Buffer_GetStart(buf);
if (*p!=0x60) {
DBG_ERROR(GWEN_LOGDOMAIN, "First byte is not a 0x60");
return GWEN_ERROR_BAD_DATA;
}
p++;
l=0;
while(*p==0x00) {
l++;
p++;
}
if (*p!=0x01) {
/*DBG_ERROR(GWEN_LOGDOMAIN, "First byte after padding is not a 0x01");*/
return GWEN_ERROR_BAD_DATA;
}

realSize=GWEN_Buffer_GetUsedBytes(buf)-11-l;
GWEN_Buffer_Crop(buf, 10+l, realSize);

return 0;
}
#endif




int GWEN_Padd_PaddWithAnsiX9_23(GWEN_BUFFER *src) {
unsigned char paddLength;
unsigned int i;

paddLength=8-(GWEN_Buffer_GetUsedBytes(src) % 8);
for (i=0; i<paddLength; i++)
GWEN_Buffer_AppendByte(src, paddLength);
return 0;
}



int GWEN_Padd_UnpaddWithAnsiX9_23(GWEN_BUFFER *src) {
const char *p;
unsigned int lastpos;
unsigned char paddLength;

lastpos=GWEN_Buffer_GetUsedBytes(src);
if (lastpos<8) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
lastpos--;

p=GWEN_Buffer_GetStart(src)+lastpos;
paddLength=*p;
if (paddLength<1 || paddLength>8) {
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid padding (%d bytes ?)", paddLength);
return -1;
}
GWEN_Buffer_Crop(src, 0, GWEN_Buffer_GetUsedBytes(src)-paddLength);
GWEN_Buffer_SetPos(src, lastpos-paddLength);
return 0;
}



int GWEN_Padd_PaddWithPkcs1Bt1(GWEN_BUFFER *buf, int dstSize){
unsigned int diff;
char *p;

if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
return GWEN_ERROR_INVALID;
}
diff=dstSize-GWEN_Buffer_GetUsedBytes(buf);
if (diff<11) {
/* honour minimum padding length for BT 1 of 8 bytes, plus the
* leading and the trailing zero and the block type identifier */
DBG_ERROR(GWEN_LOGDOMAIN,
"Buffer contains too many bytes (diff is <11)");
return GWEN_ERROR_INVALID;
}

/* reset position to 0 */
GWEN_Buffer_Rewind(buf);
if (GWEN_Buffer_InsertRoom(buf, diff)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Could not insert room for %d bytes", diff);
return GWEN_ERROR_GENERIC;
}

p=GWEN_Buffer_GetStart(buf);
*(p++)=0x00;
*(p++)=0x01; /* block type 01 */
if (diff>3) {
memset(p, 0xff, diff-3);
p+=diff-3;
}
*(p++)=0x00;

return 0;
}



int GWEN_Padd_PaddWithPkcs1Bt2(GWEN_BUFFER *buf, int dstSize){
unsigned int diff;
char *p;
int i;

if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
return GWEN_ERROR_INVALID;
}
diff=dstSize-GWEN_Buffer_GetUsedBytes(buf);
if (diff<11) {
/* honour minimum padding length for BT 1 of 8 bytes, plus the
* leading and the trailing zero and the block type identifier */
DBG_ERROR(GWEN_LOGDOMAIN,
"Buffer contains too many bytes (diff is <11)");
return GWEN_ERROR_INVALID;
}

/* reset position to 0 */
GWEN_Buffer_Rewind(buf);
if (GWEN_Buffer_InsertRoom(buf, diff)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Could not insert room for %d bytes", diff);
return GWEN_ERROR_GENERIC;
}

p=GWEN_Buffer_GetStart(buf);
*(p++)=0x00;
*(p++)=0x02; /* block type 02 */
GWEN_Crypt_Random(2, (uint8_t*)p, diff-3);
for (i=0; i<diff-3; i++) {
if (*p==0)
/* TODO: Need to find a better but yet fast way */
*p=0xff;
p++;
}
*(p++)=0x00;

return 0;
}



int GWEN_Padd__UnpaddWithPkcs1Bt1Or2(GWEN_BUFFER *buf) {
char *p;
uint32_t len;
uint32_t paddBytes;

assert(buf);
len=GWEN_Buffer_GetUsedBytes(buf);
assert(len);

p=GWEN_Buffer_GetStart(buf);
if (*p==0) {
p++;
len--;
}
if (len<11) {
DBG_ERROR(GWEN_LOGDOMAIN, "Too few bytes left (%d)", len);
return GWEN_ERROR_INVALID;
}

if (*p!=0x01 && *p!=0x02) {
DBG_ERROR(GWEN_LOGDOMAIN, "Unsupported block type %02x", *p);
return GWEN_ERROR_INVALID;
}
p++; len--;

/* skip padding bytes */
paddBytes=0;
while(*p!=0x00 && len) {
p++; len--;
paddBytes++;
}

if (*p!=0x00) {
DBG_ERROR(GWEN_LOGDOMAIN, "Bad padding");
return GWEN_ERROR_INVALID;
}
p++; len--;

if (paddBytes<8) {
/* at least 8 padding bytes are needed */
DBG_ERROR(GWEN_LOGDOMAIN, "Bad padding (too few padding bytes)");
return GWEN_ERROR_INVALID;
}

GWEN_Buffer_Crop(buf, GWEN_Buffer_GetUsedBytes(buf)-len, len);

return 0;
}



int GWEN_Padd_UnpaddWithPkcs1Bt1(GWEN_BUFFER *src){
return GWEN_Padd__UnpaddWithPkcs1Bt1Or2(src);
}



int GWEN_Padd_UnpaddWithPkcs1Bt2(GWEN_BUFFER *src){
return GWEN_Padd__UnpaddWithPkcs1Bt1Or2(src);
}



int GWEN_Padd_ApplyPaddAlgo(const GWEN_CRYPT_PADDALGO *a, GWEN_BUFFER *buf) {
int rv;
unsigned int diff;
unsigned int bsize;
unsigned int dstSize;
unsigned int chunkSize;
GWEN_CRYPT_PADDALGOID aid;

assert(a);
assert(buf);

aid=GWEN_Crypt_PaddAlgo_GetId(a);
if (aid==GWEN_Crypt_PaddAlgoId_None)
/* short return if there is no padding to be done */
return 0;

chunkSize=GWEN_Crypt_PaddAlgo_GetPaddSize(a);
if (chunkSize==0) {
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid chunk size (0)");
return GWEN_ERROR_INVALID;
}

bsize=GWEN_Buffer_GetUsedBytes(buf);
dstSize=bsize+(chunkSize-1);
dstSize=(dstSize/chunkSize)*chunkSize;
diff=dstSize-bsize;

DBG_INFO(GWEN_LOGDOMAIN, "Padding with algo \"%s\"",
GWEN_Crypt_PaddAlgoId_toString(aid));

switch(aid) {
case GWEN_Crypt_PaddAlgoId_None:
rv=0;
break;

case GWEN_Crypt_PaddAlgoId_Iso9796_1A4:
if (dstSize>96) {
DBG_ERROR(GWEN_LOGDOMAIN,
"Padding size must be <=96 bytes (is %d)",
dstSize);
return GWEN_ERROR_INVALID;
}
rv=GWEN_Padd_PaddWithISO9796(buf);
break;

case GWEN_Crypt_PaddAlgoId_Pkcs1_1:
rv=GWEN_Padd_PaddWithPkcs1Bt1(buf, dstSize);
break;

case GWEN_Crypt_PaddAlgoId_Pkcs1_2:
rv=GWEN_Padd_PaddWithPkcs1Bt2(buf, dstSize);
break;

case GWEN_Crypt_PaddAlgoId_LeftZero:
rv=GWEN_Buffer_FillLeftWithBytes(buf, 0, diff);
break;

case GWEN_Crypt_PaddAlgoId_RightZero:
rv=GWEN_Buffer_FillWithBytes(buf, 0, diff);
break;

case GWEN_Crypt_PaddAlgoId_AnsiX9_23:
return GWEN_Padd_PaddWithAnsiX9_23(buf);

case GWEN_Crypt_PaddAlgoId_Iso9796_2:
return GWEN_Padd_PaddWithIso9796_2(buf, dstSize);

case GWEN_Crypt_PaddAlgoId_Iso9796_1:
default:
DBG_INFO(GWEN_LOGDOMAIN, "Algo-Type %d (%s) not supported",
aid, GWEN_Crypt_PaddAlgoId_toString(aid));
return GWEN_ERROR_NOT_AVAILABLE;
}

if (rv) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error padding with algo %d (%s)",
aid, GWEN_Crypt_PaddAlgoId_toString(aid));
return GWEN_ERROR_GENERIC;
}

return rv;
}



int GWEN_Padd_UnapplyPaddAlgo(const GWEN_CRYPT_PADDALGO *a, GWEN_BUFFER *buf){
int rv;
GWEN_CRYPT_PADDALGOID aid;

assert(a);
assert(buf);

aid=GWEN_Crypt_PaddAlgo_GetId(a);
DBG_INFO(GWEN_LOGDOMAIN, "Unpadding with algo \"%s\"",
GWEN_Crypt_PaddAlgoId_toString(aid));

switch(aid) {
case GWEN_Crypt_PaddAlgoId_None:
rv=0;
break;

case GWEN_Crypt_PaddAlgoId_Pkcs1_1:
rv=GWEN_Padd_UnpaddWithPkcs1Bt1(buf);
break;

case GWEN_Crypt_PaddAlgoId_Pkcs1_2:
rv=GWEN_Padd_UnpaddWithPkcs1Bt2(buf);
break;

case GWEN_Crypt_PaddAlgoId_AnsiX9_23:
return GWEN_Padd_UnpaddWithAnsiX9_23(buf);

case GWEN_Crypt_PaddAlgoId_Iso9796_2:
return GWEN_Padd_UnpaddWithIso9796_2(buf);

case GWEN_Crypt_PaddAlgoId_Iso9796_1:
case GWEN_Crypt_PaddAlgoId_LeftZero:
case GWEN_Crypt_PaddAlgoId_RightZero:
case GWEN_Crypt_PaddAlgoId_Iso9796_1A4:
default:
DBG_INFO(GWEN_LOGDOMAIN, "Algo-Type %d (%s) not supported",
aid, GWEN_Crypt_PaddAlgoId_toString(aid));
return GWEN_ERROR_NOT_AVAILABLE;
}

if (rv) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error padding with algo %d (%s)",
aid, GWEN_Crypt_PaddAlgoId_toString(aid));
return GWEN_ERROR_GENERIC;
}

return rv;
}






(28-28/33)