padd.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  $RCSfile$
00003  -------------------
00004  cvs         : $Id$
00005  begin       : Mon Jan 05 2004
00006  copyright   : (C) 2004 by Martin Preuss
00007  email       : martin@libchipcard.de
00008 
00009  ***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00024  *   MA  02111-1307  USA                                                   *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 
00029 #ifdef HAVE_CONFIG_H
00030 # include <config.h>
00031 #endif
00032 
00033 #include "padd_p.h"
00034 #include <gwenhywfar/misc.h>
00035 #include <gwenhywfar/debug.h>
00036 #include <gwenhywfar/error.h>
00037 #include <gwenhywfar/cryptdefs.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 
00041 
00042 
00043 
00044 /*
00045  * This code has been taken from OpenHBCI (rsakey.cpp, written by Fabian
00046  * Kaiser)
00047  */
00048 unsigned char GWEN_Padd_permutate(unsigned char input) {
00049   unsigned char leftNibble;
00050   unsigned char rightNibble;
00051   static const unsigned char lookUp[2][16] =
00052     {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
00053     {14,3,5,8,9,4,2,15,0,13,11,6,7,10,12,1}};
00054 
00055   rightNibble = input & 15;
00056   leftNibble = input & 240;
00057   leftNibble = leftNibble / 16;
00058   rightNibble = lookUp[1][rightNibble];
00059   leftNibble = lookUp[1][leftNibble];
00060   leftNibble = leftNibble * 16;
00061 
00062   return leftNibble + rightNibble;
00063 }
00064 
00065 
00066 
00067 /*
00068  * The original code (in C++) has been written by Fabian Kaiser for OpenHBCI
00069  * (file rsakey.cpp). Translated to C by Martin Preuss
00070  */
00071 int GWEN_Padd_PaddWithISO9796(GWEN_BUFFER *src) {
00072   unsigned char *p;
00073   unsigned int l;
00074   unsigned int i;
00075   unsigned char buffer[GWEN_PADD_ISO9796_KEYSIZE];
00076   unsigned char hash[20];
00077   unsigned char c;
00078 
00079   p=(unsigned char*)GWEN_Buffer_GetStart(src);
00080   l=GWEN_Buffer_GetUsedBytes(src);
00081   memmove(hash, p, l);
00082 
00083   /* src+src+src */
00084   if (GWEN_Buffer_AppendBytes(src, (const char*)hash, l)) {
00085     DBG_INFO(GWEN_LOGDOMAIN, "here");
00086     return -1;
00087   }
00088 
00089   if (GWEN_Buffer_AppendBytes(src, (const char*)hash, l)) {
00090     DBG_INFO(GWEN_LOGDOMAIN, "here");
00091     return -1;
00092   }
00093 
00094   /* src=src(20,40) */
00095   if (GWEN_Buffer_Crop(src, 20, 40)) {
00096     DBG_INFO(GWEN_LOGDOMAIN, "here");
00097     return -1;
00098   }
00099 
00100   memset(buffer, 0, sizeof(buffer));
00101 
00102   /* append redundancy */
00103   p=(unsigned char*)GWEN_Buffer_GetStart(src);
00104   for (i=0; i<=47; i++) {
00105     int j1, j2, j3;
00106 
00107     j1=1 + sizeof(buffer) - (2*i);
00108     j2=40-i;
00109     j3=sizeof(buffer) - (2*i);
00110 
00111     if (j1>=0 && j1<(int)sizeof(buffer) && j2>=0) {
00112       buffer[j1]=p[j2];
00113     }
00114     if (j3>=0 && j3<(int)sizeof(buffer) && j2>=0) {
00115       buffer[j3]=GWEN_Padd_permutate(p[j2]);
00116     }
00117   } /* for */
00118 
00119   /* copy last 16 bytes to the beginning */
00120   memmove(buffer, buffer+(sizeof(buffer)-16), 16);
00121 
00122   p=buffer;
00123   /* finish */
00124   c=p[sizeof(buffer)-1];
00125   c = (c & 15) * 16;
00126   c += 6;
00127   p[sizeof(buffer)-1]=c;
00128   p[0] = p[0] & 127;
00129   p[0] = p[0] | 64;
00130   p[sizeof(buffer) - 40] = p[sizeof(buffer) - 40] ^ 1;
00131 
00132   GWEN_Buffer_Reset(src);
00133   if (GWEN_Buffer_AppendBytes(src, (const char*)buffer, sizeof(buffer))) {
00134     DBG_INFO(GWEN_LOGDOMAIN, "here");
00135     return -1;
00136   }
00137 
00138   return 0;
00139 }
00140 
00141 
00142 int GWEN_Padd_PaddWithIso9796_2(GWEN_BUFFER *buf, int dstSize){
00143   unsigned int diff;
00144   char *p;
00145   int i;
00146 
00147   if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)+12) {
00148     /*DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");*/
00149     return GWEN_ERROR_INVALID;
00150   }
00151 
00152   /* add trailer */
00153   GWEN_Buffer_AppendByte(buf, 0xbc);
00154 
00155   /* reset position to 0 */
00156   GWEN_Buffer_Rewind(buf);
00157 
00158   /* insert room for header */
00159   diff=dstSize-GWEN_Buffer_GetUsedBytes(buf)-11+1;
00160   if (GWEN_Buffer_InsertRoom(buf, 1+diff+1+8)) {
00161     DBG_ERROR(GWEN_LOGDOMAIN,
00162               "Could not insert room for %d bytes",
00163               1+diff+1+8);
00164     return GWEN_ERROR_GENERIC;
00165   }
00166 
00167   /* insert header and more-data-bit */
00168   p=GWEN_Buffer_GetStart(buf);
00169   *(p++)=0x60;
00170 
00171   /* insert padding field */
00172   for (i=0; i<diff; i++)
00173     *(p++)=0x0;
00174   *(p++)=0x01;
00175 
00176   /* insert 8 random bytes */
00177   GWEN_Crypt_Random(2, (uint8_t*)p, 8);
00178   for (i=0; i<8; i++) {
00179     if (*p==0)
00180       /* TODO: Need to find a better but yet fast way */
00181       *p=0xff;
00182     p++;
00183   }
00184 
00185   return 0;
00186 }
00187 
00188 
00189 int GWEN_Padd_UnpaddWithIso9796_2(GWEN_BUFFER *buf){
00190   uint32_t l;
00191   uint32_t realSize;
00192   const uint8_t *p;
00193 
00194   l=GWEN_Buffer_GetUsedBytes(buf);
00195   if (l<11) {
00196     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too few bytes");
00197     return GWEN_ERROR_INVALID;
00198   }
00199 
00200   p=(const uint8_t*)GWEN_Buffer_GetStart(buf);
00201   if (*p!=0x60) {
00202     DBG_ERROR(GWEN_LOGDOMAIN, "First byte is not a 0x60");
00203     return GWEN_ERROR_BAD_DATA;
00204   }
00205   p++;
00206   l=0;
00207   while(*p==0x00) {
00208     l++;
00209     p++;
00210   }
00211   if (*p!=0x01) {
00212     /*DBG_ERROR(GWEN_LOGDOMAIN, "First byte after padding is not a 0x01");*/
00213     return GWEN_ERROR_BAD_DATA;
00214   }
00215 
00216   realSize=GWEN_Buffer_GetUsedBytes(buf)-11-l;
00217   GWEN_Buffer_Crop(buf, 10+l, realSize);
00218 
00219   return 0;
00220 }
00221 
00222 
00223 
00224 int GWEN_Padd_PaddWithAnsiX9_23(GWEN_BUFFER *src) {
00225   unsigned char paddLength;
00226   unsigned int i;
00227 
00228   paddLength=8-(GWEN_Buffer_GetUsedBytes(src) % 8);
00229   for (i=0; i<paddLength; i++)
00230     GWEN_Buffer_AppendByte(src, paddLength);
00231   return 0;
00232 }
00233 
00234 
00235 
00236 int GWEN_Padd_UnpaddWithAnsiX9_23(GWEN_BUFFER *src) {
00237   const char *p;
00238   unsigned int lastpos;
00239   unsigned char paddLength;
00240 
00241   lastpos=GWEN_Buffer_GetUsedBytes(src);
00242   if (lastpos<8) {
00243     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
00244     return -1;
00245   }
00246   lastpos--;
00247 
00248   p=GWEN_Buffer_GetStart(src)+lastpos;
00249   paddLength=*p;
00250   if (paddLength<1 || paddLength>8) {
00251     DBG_ERROR(GWEN_LOGDOMAIN, "Invalid padding (%d bytes ?)", paddLength);
00252     return -1;
00253   }
00254   GWEN_Buffer_Crop(src, 0, GWEN_Buffer_GetUsedBytes(src)-paddLength);
00255   GWEN_Buffer_SetPos(src, lastpos-paddLength);
00256   return 0;
00257 }
00258 
00259 
00260 
00261 int GWEN_Padd_PaddWithPkcs1Bt1(GWEN_BUFFER *buf, int dstSize){
00262   unsigned int diff;
00263   char *p;
00264 
00265   if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)) {
00266     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
00267     return GWEN_ERROR_INVALID;
00268   }
00269   diff=dstSize-GWEN_Buffer_GetUsedBytes(buf);
00270   if (diff<11) {
00271     /* honour minimum padding length for BT 1 of 8 bytes, plus the
00272      * leading and the trailing zero and the block type identifier */
00273     DBG_ERROR(GWEN_LOGDOMAIN,
00274               "Buffer contains too many bytes (diff is <11)");
00275     return GWEN_ERROR_INVALID;
00276   }
00277 
00278   /* reset position to 0 */
00279   GWEN_Buffer_Rewind(buf);
00280   if (GWEN_Buffer_InsertRoom(buf, diff)) {
00281     DBG_ERROR(GWEN_LOGDOMAIN, "Could not insert room for %d bytes", diff);
00282     return GWEN_ERROR_GENERIC;
00283   }
00284 
00285   p=GWEN_Buffer_GetStart(buf);
00286   *(p++)=0x00;
00287   *(p++)=0x01; /* block type 01 */
00288   if (diff>3) {
00289     memset(p, 0xff, diff-3);
00290     p+=diff-3;
00291   }
00292   *(p++)=0x00;
00293 
00294   return 0;
00295 }
00296 
00297 
00298 
00299 int GWEN_Padd_PaddWithPkcs1Bt2(GWEN_BUFFER *buf, int dstSize){
00300   unsigned int diff;
00301   char *p;
00302   int i;
00303 
00304   if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)) {
00305     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
00306     return GWEN_ERROR_INVALID;
00307   }
00308   diff=dstSize-GWEN_Buffer_GetUsedBytes(buf);
00309   if (diff<11) {
00310     /* honour minimum padding length for BT 1 of 8 bytes, plus the
00311      * leading and the trailing zero and the block type identifier */
00312     DBG_ERROR(GWEN_LOGDOMAIN,
00313               "Buffer contains too many bytes (diff is <11)");
00314     return GWEN_ERROR_INVALID;
00315   }
00316 
00317   /* reset position to 0 */
00318   GWEN_Buffer_Rewind(buf);
00319   if (GWEN_Buffer_InsertRoom(buf, diff)) {
00320     DBG_ERROR(GWEN_LOGDOMAIN, "Could not insert room for %d bytes", diff);
00321     return GWEN_ERROR_GENERIC;
00322   }
00323 
00324   p=GWEN_Buffer_GetStart(buf);
00325   *(p++)=0x00;
00326   *(p++)=0x02; /* block type 02 */
00327   GWEN_Crypt_Random(2, (uint8_t*)p, diff-3);
00328   for (i=0; i<diff-3; i++) {
00329     if (*p==0)
00330       /* TODO: Need to find a better but yet fast way */
00331       *p=0xff;
00332     p++;
00333   }
00334   *(p++)=0x00;
00335 
00336   return 0;
00337 }
00338 
00339 
00340 
00341 int GWEN_Padd__UnpaddWithPkcs1Bt1Or2(GWEN_BUFFER *buf) {
00342   char *p;
00343   uint32_t len;
00344   uint32_t paddBytes;
00345 
00346   assert(buf);
00347   len=GWEN_Buffer_GetUsedBytes(buf);
00348   assert(len);
00349 
00350   p=GWEN_Buffer_GetStart(buf);
00351   if  (*p==0) {
00352     p++;
00353     len--;
00354   }
00355   if (len<11) {
00356     DBG_ERROR(GWEN_LOGDOMAIN, "Too few bytes left (%d)", len);
00357     return GWEN_ERROR_INVALID;
00358   }
00359 
00360   if (*p!=0x01 && *p!=0x02) {
00361     DBG_ERROR(GWEN_LOGDOMAIN, "Unsupported block type %02x", *p);
00362     return GWEN_ERROR_INVALID;
00363   }
00364   p++; len--;
00365 
00366   /* skip padding bytes */
00367   paddBytes=0;
00368   while(*p!=0x00 && len) {
00369     p++; len--;
00370     paddBytes++;
00371   }
00372 
00373   if (*p!=0x00) {
00374     DBG_ERROR(GWEN_LOGDOMAIN, "Bad padding");
00375     return GWEN_ERROR_INVALID;
00376   }
00377   p++; len--;
00378 
00379   if (paddBytes<8) {
00380     /* at least 8 padding bytes are needed */
00381     DBG_ERROR(GWEN_LOGDOMAIN, "Bad padding (too few padding bytes)");
00382     return GWEN_ERROR_INVALID;
00383   }
00384 
00385   GWEN_Buffer_Crop(buf, GWEN_Buffer_GetUsedBytes(buf)-len, len);
00386 
00387   return 0;
00388 }
00389 
00390 
00391 
00392 int GWEN_Padd_UnpaddWithPkcs1Bt1(GWEN_BUFFER *src){
00393   return GWEN_Padd__UnpaddWithPkcs1Bt1Or2(src);
00394 }
00395 
00396 
00397 
00398 int GWEN_Padd_UnpaddWithPkcs1Bt2(GWEN_BUFFER *src){
00399   return GWEN_Padd__UnpaddWithPkcs1Bt1Or2(src);
00400 }
00401 
00402 
00403 
00404 int GWEN_Padd_ApplyPaddAlgo(const GWEN_CRYPT_PADDALGO *a, GWEN_BUFFER *buf) {
00405   int rv;
00406   unsigned int diff;
00407   unsigned int bsize;
00408   unsigned int dstSize;
00409   unsigned int chunkSize;
00410   GWEN_CRYPT_PADDALGOID aid;
00411 
00412   assert(a);
00413   assert(buf);
00414 
00415   aid=GWEN_Crypt_PaddAlgo_GetId(a);
00416   if (aid==GWEN_Crypt_PaddAlgoId_None)
00417     /* short return if there is no padding to be done */
00418     return 0;
00419 
00420   chunkSize=GWEN_Crypt_PaddAlgo_GetPaddSize(a);
00421   if (chunkSize==0) {
00422     DBG_ERROR(GWEN_LOGDOMAIN, "Invalid chunk size (0)");
00423     return GWEN_ERROR_INVALID;
00424   }
00425 
00426   bsize=GWEN_Buffer_GetUsedBytes(buf);
00427   dstSize=bsize+(chunkSize-1);
00428   dstSize=(dstSize/chunkSize)*chunkSize;
00429   diff=dstSize-bsize;
00430 
00431   DBG_INFO(GWEN_LOGDOMAIN, "Padding with algo \"%s\"",
00432            GWEN_Crypt_PaddAlgoId_toString(aid));
00433 
00434   switch(aid) {
00435   case GWEN_Crypt_PaddAlgoId_None:
00436     rv=0;
00437     break;
00438 
00439   case GWEN_Crypt_PaddAlgoId_Iso9796_1A4:
00440     if (dstSize>96) {
00441       DBG_ERROR(GWEN_LOGDOMAIN,
00442                 "Padding size must be <=96 bytes (is %d)",
00443                 dstSize);
00444       return GWEN_ERROR_INVALID;
00445     }
00446     rv=GWEN_Padd_PaddWithISO9796(buf);
00447     break;
00448 
00449   case GWEN_Crypt_PaddAlgoId_Pkcs1_1:
00450     rv=GWEN_Padd_PaddWithPkcs1Bt1(buf, dstSize);
00451     break;
00452 
00453   case GWEN_Crypt_PaddAlgoId_Pkcs1_2:
00454     rv=GWEN_Padd_PaddWithPkcs1Bt2(buf, dstSize);
00455     break;
00456 
00457   case GWEN_Crypt_PaddAlgoId_LeftZero:
00458     rv=GWEN_Buffer_FillLeftWithBytes(buf, 0, diff);
00459     break;
00460 
00461   case GWEN_Crypt_PaddAlgoId_RightZero:
00462     rv=GWEN_Buffer_FillWithBytes(buf, 0, diff);
00463     break;
00464 
00465   case GWEN_Crypt_PaddAlgoId_AnsiX9_23:
00466     return GWEN_Padd_PaddWithAnsiX9_23(buf);
00467 
00468   case GWEN_Crypt_PaddAlgoId_Iso9796_2:
00469     return GWEN_Padd_PaddWithIso9796_2(buf, dstSize);
00470 
00471   case GWEN_Crypt_PaddAlgoId_Iso9796_1:
00472   default:
00473     DBG_INFO(GWEN_LOGDOMAIN, "Algo-Type %d (%s) not supported",
00474              aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00475     return GWEN_ERROR_NOT_AVAILABLE;
00476   }
00477 
00478   if (rv) {
00479     DBG_ERROR(GWEN_LOGDOMAIN, "Error padding with algo %d (%s)",
00480               aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00481     return GWEN_ERROR_GENERIC;
00482   }
00483 
00484   return rv;
00485 }
00486 
00487 
00488 
00489 int GWEN_Padd_UnapplyPaddAlgo(const GWEN_CRYPT_PADDALGO *a, GWEN_BUFFER *buf){
00490   int rv;
00491   GWEN_CRYPT_PADDALGOID aid;
00492 
00493   assert(a);
00494   assert(buf);
00495 
00496   aid=GWEN_Crypt_PaddAlgo_GetId(a);
00497   DBG_INFO(GWEN_LOGDOMAIN, "Unpadding with algo \"%s\"",
00498            GWEN_Crypt_PaddAlgoId_toString(aid));
00499 
00500   switch(aid) {
00501   case GWEN_Crypt_PaddAlgoId_None:
00502     rv=0;
00503     break;
00504 
00505   case GWEN_Crypt_PaddAlgoId_Pkcs1_1:
00506     rv=GWEN_Padd_UnpaddWithPkcs1Bt1(buf);
00507     break;
00508 
00509   case GWEN_Crypt_PaddAlgoId_Pkcs1_2:
00510     rv=GWEN_Padd_UnpaddWithPkcs1Bt2(buf);
00511     break;
00512 
00513   case GWEN_Crypt_PaddAlgoId_AnsiX9_23:
00514     return GWEN_Padd_UnpaddWithAnsiX9_23(buf);
00515 
00516   case GWEN_Crypt_PaddAlgoId_Iso9796_2:
00517     return GWEN_Padd_UnpaddWithIso9796_2(buf);
00518 
00519   case GWEN_Crypt_PaddAlgoId_Iso9796_1:
00520   case GWEN_Crypt_PaddAlgoId_LeftZero:
00521   case GWEN_Crypt_PaddAlgoId_RightZero:
00522   case GWEN_Crypt_PaddAlgoId_Iso9796_1A4:
00523   default:
00524     DBG_INFO(GWEN_LOGDOMAIN, "Algo-Type %d (%s) not supported",
00525              aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00526     return GWEN_ERROR_NOT_AVAILABLE;
00527   }
00528 
00529   if (rv) {
00530     DBG_ERROR(GWEN_LOGDOMAIN, "Error padding with algo %d (%s)",
00531               aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00532     return GWEN_ERROR_GENERIC;
00533   }
00534 
00535   return rv;
00536 }
00537 
00538 
00539 
00540 
00541 
00542 

Generated on Wed Sep 3 15:21:59 2008 for gwenhywfar by  doxygen 1.5.6