padd.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  $RCSfile$
00003  -------------------
00004  cvs         : $Id: padd.c 1414 2008-03-08 11:52:53Z martin $
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 
00143 int GWEN_Padd_PaddWithIso9796_2(GWEN_BUFFER *buf, int dstSize){
00144   unsigned int diff;
00145   char *p;
00146   int i;
00147 
00148   if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)+31) {
00149     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
00150     return GWEN_ERROR_INVALID;
00151   }
00152 
00153   /* add trailer */
00154   GWEN_Buffer_AppendByte(buf, 0xbc);
00155 
00156   /* reset position to 0 */
00157   GWEN_Buffer_Rewind(buf);
00158 
00159   /* insert room for header */
00160   diff=dstSize-31;
00161   if (GWEN_Buffer_InsertRoom(buf, 1+diff+1+8)) {
00162     DBG_ERROR(GWEN_LOGDOMAIN,
00163               "Could not insert room for %d bytes",
00164               1+diff+1+8);
00165     return GWEN_ERROR_GENERIC;
00166   }
00167 
00168   /* insert header and more-data-bit */
00169   p=GWEN_Buffer_GetStart(buf);
00170   *(p++)=0x60;
00171 
00172   /* insert padding field */
00173   for (i=0; i<diff; i++)
00174     *(p++)=0x0;
00175   *(p++)=0x01;
00176 
00177   /* insert 8 random bytes */
00178   GWEN_Crypt_Random(2, (uint8_t*)p, 8);
00179   for (i=0; i<8; i++) {
00180     if (*p==0)
00181       /* TODO: Need to find a better but yet fast way */
00182       *p=0xff;
00183     p++;
00184   }
00185   *(p++)=0x01;
00186 
00187   return 0;
00188 }
00189 
00190 
00191 
00192 int GWEN_Padd_UnpaddWithIso9796_2(GWEN_BUFFER *buf){
00193   uint32_t l;
00194 
00195   l=GWEN_Buffer_GetUsedBytes(buf);
00196   if (l<31) {
00197     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too few bytes");
00198     return GWEN_ERROR_INVALID;
00199   }
00200 
00201   GWEN_Buffer_Crop(buf, l-21, 20);
00202 
00203   return 0;
00204 }
00205 
00206 
00207 
00208 
00209 int GWEN_Padd_PaddWithAnsiX9_23(GWEN_BUFFER *src) {
00210   unsigned char paddLength;
00211   unsigned int i;
00212 
00213   paddLength=8-(GWEN_Buffer_GetUsedBytes(src) % 8);
00214   for (i=0; i<paddLength; i++)
00215     GWEN_Buffer_AppendByte(src, paddLength);
00216   return 0;
00217 }
00218 
00219 
00220 
00221 int GWEN_Padd_UnpaddWithAnsiX9_23(GWEN_BUFFER *src) {
00222   const char *p;
00223   unsigned int lastpos;
00224   unsigned char paddLength;
00225 
00226   lastpos=GWEN_Buffer_GetUsedBytes(src);
00227   if (lastpos<8) {
00228     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
00229     return -1;
00230   }
00231   lastpos--;
00232 
00233   p=GWEN_Buffer_GetStart(src)+lastpos;
00234   paddLength=*p;
00235   if (paddLength<1 || paddLength>8) {
00236     DBG_ERROR(GWEN_LOGDOMAIN, "Invalid padding (%d bytes ?)", paddLength);
00237     return -1;
00238   }
00239   GWEN_Buffer_Crop(src, 0, GWEN_Buffer_GetUsedBytes(src)-paddLength);
00240   GWEN_Buffer_SetPos(src, lastpos-paddLength);
00241   return 0;
00242 }
00243 
00244 
00245 
00246 int GWEN_Padd_PaddWithPkcs1Bt1(GWEN_BUFFER *buf, int dstSize){
00247   unsigned int diff;
00248   char *p;
00249 
00250   if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)) {
00251     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
00252     return GWEN_ERROR_INVALID;
00253   }
00254   diff=dstSize-GWEN_Buffer_GetUsedBytes(buf);
00255   if (diff<11) {
00256     /* honour minimum padding length for BT 1 of 8 bytes, plus the
00257      * leading and the trailing zero and the block type identifier */
00258     DBG_ERROR(GWEN_LOGDOMAIN,
00259               "Buffer contains too many bytes (diff is <11)");
00260     return GWEN_ERROR_INVALID;
00261   }
00262 
00263   /* reset position to 0 */
00264   GWEN_Buffer_Rewind(buf);
00265   if (GWEN_Buffer_InsertRoom(buf, diff)) {
00266     DBG_ERROR(GWEN_LOGDOMAIN, "Could not insert room for %d bytes", diff);
00267     return GWEN_ERROR_GENERIC;
00268   }
00269 
00270   p=GWEN_Buffer_GetStart(buf);
00271   *(p++)=0x00;
00272   *(p++)=0x01; /* block type 01 */
00273   if (diff>3) {
00274     memset(p, 0xff, diff-3);
00275     p+=diff-3;
00276   }
00277   *(p++)=0x00;
00278 
00279   return 0;
00280 }
00281 
00282 
00283 
00284 int GWEN_Padd_PaddWithPkcs1Bt2(GWEN_BUFFER *buf, int dstSize){
00285   unsigned int diff;
00286   char *p;
00287   int i;
00288 
00289   if ((unsigned int)dstSize<GWEN_Buffer_GetUsedBytes(buf)) {
00290     DBG_ERROR(GWEN_LOGDOMAIN, "Buffer contains too much data");
00291     return GWEN_ERROR_INVALID;
00292   }
00293   diff=dstSize-GWEN_Buffer_GetUsedBytes(buf);
00294   if (diff<11) {
00295     /* honour minimum padding length for BT 1 of 8 bytes, plus the
00296      * leading and the trailing zero and the block type identifier */
00297     DBG_ERROR(GWEN_LOGDOMAIN,
00298               "Buffer contains too many bytes (diff is <11)");
00299     return GWEN_ERROR_INVALID;
00300   }
00301 
00302   /* reset position to 0 */
00303   GWEN_Buffer_Rewind(buf);
00304   if (GWEN_Buffer_InsertRoom(buf, diff)) {
00305     DBG_ERROR(GWEN_LOGDOMAIN, "Could not insert room for %d bytes", diff);
00306     return GWEN_ERROR_GENERIC;
00307   }
00308 
00309   p=GWEN_Buffer_GetStart(buf);
00310   *(p++)=0x00;
00311   *(p++)=0x02; /* block type 02 */
00312   GWEN_Crypt_Random(2, (uint8_t*)p, diff-3);
00313   for (i=0; i<diff-3; i++) {
00314     if (*p==0)
00315       /* TODO: Need to find a better but yet fast way */
00316       *p=0xff;
00317     p++;
00318   }
00319   *(p++)=0x00;
00320 
00321   return 0;
00322 }
00323 
00324 
00325 
00326 int GWEN_Padd__UnpaddWithPkcs1Bt1Or2(GWEN_BUFFER *buf) {
00327   char *p;
00328   uint32_t len;
00329   uint32_t paddBytes;
00330 
00331   assert(buf);
00332   len=GWEN_Buffer_GetUsedBytes(buf);
00333   assert(len);
00334 
00335   p=GWEN_Buffer_GetStart(buf);
00336   if  (*p==0) {
00337     p++;
00338     len--;
00339   }
00340   if (len<11) {
00341     DBG_ERROR(GWEN_LOGDOMAIN, "Too few bytes left (%d)", len);
00342     return GWEN_ERROR_INVALID;
00343   }
00344 
00345   if (*p!=0x01 && *p!=0x02) {
00346     DBG_ERROR(GWEN_LOGDOMAIN, "Unsupported block type %02x", *p);
00347     return GWEN_ERROR_INVALID;
00348   }
00349   p++; len--;
00350 
00351   /* skip padding bytes */
00352   paddBytes=0;
00353   while(*p!=0x00 && len) {
00354     p++; len--;
00355     paddBytes++;
00356   }
00357 
00358   if (*p!=0x00) {
00359     DBG_ERROR(GWEN_LOGDOMAIN, "Bad padding");
00360     return GWEN_ERROR_INVALID;
00361   }
00362   p++; len--;
00363 
00364   if (paddBytes<8) {
00365     /* at least 8 padding bytes are needed */
00366     DBG_ERROR(GWEN_LOGDOMAIN, "Bad padding (too few padding bytes)");
00367     return GWEN_ERROR_INVALID;
00368   }
00369 
00370   GWEN_Buffer_Crop(buf, GWEN_Buffer_GetUsedBytes(buf)-len, len);
00371 
00372   return 0;
00373 }
00374 
00375 
00376 
00377 int GWEN_Padd_UnpaddWithPkcs1Bt1(GWEN_BUFFER *src){
00378   return GWEN_Padd__UnpaddWithPkcs1Bt1Or2(src);
00379 }
00380 
00381 
00382 
00383 int GWEN_Padd_UnpaddWithPkcs1Bt2(GWEN_BUFFER *src){
00384   return GWEN_Padd__UnpaddWithPkcs1Bt1Or2(src);
00385 }
00386 
00387 
00388 
00389 int GWEN_Padd_ApplyPaddAlgo(const GWEN_CRYPT_PADDALGO *a, GWEN_BUFFER *buf) {
00390   int rv;
00391   unsigned int diff;
00392   unsigned int bsize;
00393   unsigned int dstSize;
00394   unsigned int chunkSize;
00395   GWEN_CRYPT_PADDALGOID aid;
00396 
00397   assert(a);
00398   assert(buf);
00399 
00400   aid=GWEN_Crypt_PaddAlgo_GetId(a);
00401   if (aid==GWEN_Crypt_PaddAlgoId_None)
00402     /* short return if there is no padding to be done */
00403     return 0;
00404 
00405   chunkSize=GWEN_Crypt_PaddAlgo_GetPaddSize(a);
00406   if (chunkSize==0) {
00407     DBG_ERROR(GWEN_LOGDOMAIN, "Invalid chunk size (0)");
00408     return GWEN_ERROR_INVALID;
00409   }
00410 
00411   bsize=GWEN_Buffer_GetUsedBytes(buf);
00412   dstSize=bsize+(chunkSize-1);
00413   dstSize=(dstSize/chunkSize)*chunkSize;
00414   diff=dstSize-bsize;
00415 
00416   DBG_INFO(GWEN_LOGDOMAIN, "Padding with algo \"%s\"",
00417            GWEN_Crypt_PaddAlgoId_toString(aid));
00418 
00419   switch(aid) {
00420   case GWEN_Crypt_PaddAlgoId_None:
00421     rv=0;
00422     break;
00423 
00424   case GWEN_Crypt_PaddAlgoId_Iso9796_1A4:
00425     if (dstSize>96) {
00426       DBG_ERROR(GWEN_LOGDOMAIN,
00427                 "Padding size must be <=96 bytes (is %d)",
00428                 dstSize);
00429       return GWEN_ERROR_INVALID;
00430     }
00431     rv=GWEN_Padd_PaddWithISO9796(buf);
00432     break;
00433 
00434   case GWEN_Crypt_PaddAlgoId_Pkcs1_1:
00435     rv=GWEN_Padd_PaddWithPkcs1Bt1(buf, dstSize);
00436     break;
00437 
00438   case GWEN_Crypt_PaddAlgoId_Pkcs1_2:
00439     rv=GWEN_Padd_PaddWithPkcs1Bt2(buf, dstSize);
00440     break;
00441 
00442   case GWEN_Crypt_PaddAlgoId_LeftZero:
00443     rv=GWEN_Buffer_FillLeftWithBytes(buf, 0, diff);
00444     break;
00445 
00446   case GWEN_Crypt_PaddAlgoId_RightZero:
00447     rv=GWEN_Buffer_FillWithBytes(buf, 0, diff);
00448     break;
00449 
00450   case GWEN_Crypt_PaddAlgoId_AnsiX9_23:
00451     return GWEN_Padd_PaddWithAnsiX9_23(buf);
00452 
00453   case GWEN_Crypt_PaddAlgoId_Iso9796_2:
00454     return GWEN_Padd_PaddWithIso9796_2(buf, dstSize);
00455 
00456   case GWEN_Crypt_PaddAlgoId_Iso9796_1:
00457   default:
00458     DBG_INFO(GWEN_LOGDOMAIN, "Algo-Type %d (%s) not supported",
00459              aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00460     return GWEN_ERROR_NOT_AVAILABLE;
00461   }
00462 
00463   if (rv) {
00464     DBG_ERROR(GWEN_LOGDOMAIN, "Error padding with algo %d (%s)",
00465               aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00466     return GWEN_ERROR_GENERIC;
00467   }
00468 
00469   return rv;
00470 }
00471 
00472 
00473 
00474 int GWEN_Padd_UnapplyPaddAlgo(const GWEN_CRYPT_PADDALGO *a, GWEN_BUFFER *buf){
00475   int rv;
00476   GWEN_CRYPT_PADDALGOID aid;
00477 
00478   assert(a);
00479   assert(buf);
00480 
00481   aid=GWEN_Crypt_PaddAlgo_GetId(a);
00482   DBG_INFO(GWEN_LOGDOMAIN, "Unpadding with algo \"%s\"",
00483            GWEN_Crypt_PaddAlgoId_toString(aid));
00484 
00485   switch(aid) {
00486   case GWEN_Crypt_PaddAlgoId_None:
00487     rv=0;
00488     break;
00489 
00490   case GWEN_Crypt_PaddAlgoId_Pkcs1_1:
00491     rv=GWEN_Padd_UnpaddWithPkcs1Bt1(buf);
00492     break;
00493 
00494   case GWEN_Crypt_PaddAlgoId_Pkcs1_2:
00495     rv=GWEN_Padd_UnpaddWithPkcs1Bt2(buf);
00496     break;
00497 
00498   case GWEN_Crypt_PaddAlgoId_AnsiX9_23:
00499     return GWEN_Padd_UnpaddWithAnsiX9_23(buf);
00500 
00501   case GWEN_Crypt_PaddAlgoId_Iso9796_2:
00502     return GWEN_Padd_UnpaddWithIso9796_2(buf);
00503 
00504   case GWEN_Crypt_PaddAlgoId_Iso9796_1:
00505   case GWEN_Crypt_PaddAlgoId_LeftZero:
00506   case GWEN_Crypt_PaddAlgoId_RightZero:
00507   case GWEN_Crypt_PaddAlgoId_Iso9796_1A4:
00508   default:
00509     DBG_INFO(GWEN_LOGDOMAIN, "Algo-Type %d (%s) not supported",
00510              aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00511     return GWEN_ERROR_NOT_AVAILABLE;
00512   }
00513 
00514   if (rv) {
00515     DBG_ERROR(GWEN_LOGDOMAIN, "Error padding with algo %d (%s)",
00516               aid, GWEN_Crypt_PaddAlgoId_toString(aid));
00517     return GWEN_ERROR_GENERIC;
00518   }
00519 
00520   return rv;
00521 }
00522 
00523 
00524 
00525 
00526 
00527 

Generated on Fri Apr 11 01:53:47 2008 for gwenhywfar by  doxygen 1.5.5