gwenhywfar  4.3.1
mdigest.c
Go to the documentation of this file.
00001 /***************************************************************************
00002     begin       : Wed Mar 16 2005
00003     copyright   : (C) 2005-2010 by Martin Preuss
00004     email       : martin@libchipcard.de
00005 
00006  ***************************************************************************
00007  *          Please see toplevel file COPYING for license details           *
00008  ***************************************************************************/
00009 
00010 #ifdef HAVE_CONFIG_H
00011 # include <config.h>
00012 #endif
00013 
00014 #define DISABLE_DEBUGLOG
00015 
00016 
00017 #include "mdigest_p.h"
00018 #include "i18n_l.h"
00019 
00020 #include <gwenhywfar/misc.h>
00021 #include <gwenhywfar/debug.h>
00022 #include <gwenhywfar/directory.h>
00023 #include <gwenhywfar/text.h>
00024 #include <gwenhywfar/syncio.h>
00025 #include <gwenhywfar/syncio_file.h>
00026 #include <gwenhywfar/gui.h>
00027 
00028 
00029 
00030 
00031 GWEN_INHERIT_FUNCTIONS(GWEN_MDIGEST)
00032 GWEN_LIST_FUNCTIONS(GWEN_MDIGEST, GWEN_MDigest)
00033 GWEN_LIST2_FUNCTIONS(GWEN_MDIGEST, GWEN_MDigest)
00034 
00035 
00036 
00037 
00038 
00039 GWEN_MDIGEST *GWEN_MDigest_new(GWEN_CRYPT_HASHALGOID a) {
00040   GWEN_MDIGEST *md;
00041 
00042   GWEN_NEW_OBJECT(GWEN_MDIGEST, md)
00043   md->refCount=1;
00044   GWEN_INHERIT_INIT(GWEN_MDIGEST, md)
00045   GWEN_LIST_INIT(GWEN_MDIGEST, md)
00046 
00047   md->hashAlgoId=a;
00048   return md;
00049 }
00050 
00051 
00052 
00053 void GWEN_MDigest_free(GWEN_MDIGEST *md) {
00054   if (md) {
00055     assert(md->refCount);
00056     if (md->refCount==1) {
00057       free(md->pDigest);
00058       md->refCount=0;
00059       GWEN_FREE_OBJECT(md);
00060     }
00061     else
00062       md->refCount--;
00063   }
00064 }
00065 
00066 
00067 
00068 GWEN_CRYPT_HASHALGOID GWEN_MDigest_GetHashAlgoId(const GWEN_MDIGEST *md) {
00069   assert(md);
00070   assert(md->refCount);
00071   return md->hashAlgoId;
00072 }
00073 
00074 
00075 
00076 uint8_t *GWEN_MDigest_GetDigestPtr(GWEN_MDIGEST *md) {
00077   assert(md);
00078   assert(md->refCount);
00079   return md->pDigest;
00080 }
00081 
00082 
00083 
00084 unsigned int GWEN_MDigest_GetDigestSize(GWEN_MDIGEST *md) {
00085   assert(md);
00086   assert(md->refCount);
00087   return md->lDigest;
00088 }
00089 
00090 
00091 
00092 void GWEN_MDigest_SetDigestBuffer(GWEN_MDIGEST *md, uint8_t *buf, unsigned int l) {
00093   assert(md);
00094   assert(md->refCount);
00095 
00096   if (l) {
00097     assert(buf);
00098   }
00099 
00100   if (md->pDigest && md->lDigest)
00101     free(md->pDigest);
00102   md->pDigest=buf;
00103   md->lDigest=l;
00104 }
00105 
00106 
00107 
00108 void GWEN_MDigest_SetDigestLen(GWEN_MDIGEST *md, unsigned int l) {
00109   assert(md);
00110   assert(md->refCount);
00111 
00112   if (md->pDigest && md->lDigest)
00113     free(md->pDigest);
00114   md->pDigest=NULL;
00115   md->lDigest=l;
00116 }
00117 
00118 
00119 
00120 int GWEN_MDigest_Begin(GWEN_MDIGEST *md) {
00121   assert(md);
00122   assert(md->refCount);
00123   if (md->beginFn)
00124     return md->beginFn(md);
00125   else
00126     return GWEN_ERROR_NOT_IMPLEMENTED;
00127 }
00128 
00129 
00130 
00131 int GWEN_MDigest_End(GWEN_MDIGEST *md) {
00132   assert(md);
00133   assert(md->refCount);
00134   if (md->endFn)
00135     return md->endFn(md);
00136   else
00137     return GWEN_ERROR_NOT_IMPLEMENTED;
00138 }
00139 
00140 
00141 
00142 int GWEN_MDigest_Update(GWEN_MDIGEST *md, const uint8_t *buf, unsigned int l) {
00143   assert(md);
00144   assert(md->refCount);
00145   if (md->updateFn)
00146     return md->updateFn(md, buf, l);
00147   else
00148     return GWEN_ERROR_NOT_IMPLEMENTED;
00149 }
00150 
00151 
00152 
00153 GWEN_MDIGEST_BEGIN_FN GWEN_MDigest_SetBeginFn(GWEN_MDIGEST *md, GWEN_MDIGEST_BEGIN_FN f) {
00154   GWEN_MDIGEST_BEGIN_FN of;
00155 
00156   assert(md);
00157   assert(md->refCount);
00158   of=md->beginFn;
00159   md->beginFn=f;
00160 
00161   return of;
00162 }
00163 
00164 
00165 
00166 GWEN_MDIGEST_END_FN GWEN_MDigest_SetEndFn(GWEN_MDIGEST *md, GWEN_MDIGEST_END_FN f) {
00167   GWEN_MDIGEST_END_FN of;
00168 
00169   assert(md);
00170   assert(md->refCount);
00171   of=md->endFn;
00172   md->endFn=f;
00173 
00174   return of;
00175 }
00176 
00177 
00178 
00179 GWEN_MDIGEST_UPDATE_FN GWEN_MDigest_SetUpdateFn(GWEN_MDIGEST *md, GWEN_MDIGEST_UPDATE_FN f) {
00180   GWEN_MDIGEST_UPDATE_FN of;
00181 
00182   assert(md);
00183   assert(md->refCount);
00184   of=md->updateFn;
00185   md->updateFn=f;
00186 
00187   return of;
00188 }
00189 
00190 
00191 
00192 int GWEN_MDigest_PBKDF2(GWEN_MDIGEST *md,
00193                         const char *password,
00194                         const uint8_t *pSalt,
00195                         uint32_t lSalt,
00196                         uint8_t *pKey,
00197                         uint32_t lKey,
00198                         uint32_t iterations) {
00199   int rv;
00200   uint8_t hash[128];
00201   uint32_t hsize;
00202   uint32_t i;
00203 
00204   hsize=GWEN_MDigest_GetDigestSize(md);
00205   if (lKey>hsize || lKey>sizeof(hash)) {
00206     DBG_ERROR(GWEN_LOGDOMAIN, "Derived key too long");
00207     return GWEN_ERROR_INVALID;
00208   }
00209 
00210   rv=GWEN_MDigest_Begin(md);
00211   if (rv<0) {
00212     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00213     GWEN_MDigest_End(md);
00214     return rv;
00215   }
00216 
00217   /* hash password */
00218   rv=GWEN_MDigest_Update(md, (const uint8_t*) password, strlen(password));
00219   if (rv<0) {
00220     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00221     GWEN_MDigest_End(md);
00222     return rv;
00223   }
00224 
00225   /* hash salt */
00226   rv=GWEN_MDigest_Update(md, pSalt, lSalt);
00227   if (rv<0) {
00228     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00229     GWEN_MDigest_End(md);
00230     return rv;
00231   }
00232 
00233   rv=GWEN_MDigest_End(md);
00234   if (rv<0) {
00235     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00236     GWEN_MDigest_End(md);
00237     return rv;
00238   }
00239 
00240   /* use that hash now for the iterations */
00241   memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize);
00242 
00243   for (i=2; i<iterations; i++) {
00244     rv=GWEN_MDigest_Begin(md);
00245     if (rv<0) {
00246       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00247       GWEN_MDigest_End(md);
00248       return rv;
00249     }
00250     rv=GWEN_MDigest_Update(md, hash, hsize);
00251     if (rv<0) {
00252       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00253       GWEN_MDigest_End(md);
00254       return rv;
00255     }
00256 
00257     rv=GWEN_MDigest_End(md);
00258     if (rv<0) {
00259       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00260       GWEN_MDigest_End(md);
00261       return rv;
00262     }
00263 
00264     /* use that hash now for the next iteration */
00265     memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize);
00266   }
00267 
00268   /* done, copy key */
00269   memmove(pKey, hash, lKey);
00270   memset(hash, 0, sizeof(hash));
00271 
00272   return 0;
00273 }
00274 
00275 
00276 
00277 static int GWEN_MDigest__HashFile(GWEN_MDIGEST *md,
00278                                   const char *fname,
00279                                   GWEN_BUFFER *hbuf) {
00280   GWEN_SYNCIO *sio;
00281   int rv;
00282   uint8_t buffer[1024];
00283 
00284   sio=GWEN_SyncIo_File_new(fname, GWEN_SyncIo_File_CreationMode_OpenExisting);
00285   GWEN_SyncIo_SetFlags(sio, GWEN_SYNCIO_FILE_FLAGS_READ);
00286   rv=GWEN_SyncIo_Connect(sio);
00287   if (rv<0) {
00288     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00289     GWEN_SyncIo_free(sio);
00290     return rv;
00291   }
00292 
00293   rv=GWEN_MDigest_Begin(md);
00294   if (rv<0) {
00295     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00296     GWEN_SyncIo_Disconnect(sio);
00297     GWEN_SyncIo_free(sio);
00298     return rv;
00299   }
00300 
00301   while(1) {
00302     rv=GWEN_SyncIo_Read(sio, buffer, sizeof(buffer));
00303     if (rv<0) {
00304       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00305       GWEN_SyncIo_Disconnect(sio);
00306       GWEN_SyncIo_free(sio);
00307       return rv;
00308     }
00309     else if (rv==0)
00310       break;
00311     else {
00312       rv=GWEN_MDigest_Update(md, (const uint8_t*) buffer, rv);
00313       if (rv<0) {
00314         DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00315         GWEN_SyncIo_Disconnect(sio);
00316         GWEN_SyncIo_free(sio);
00317         return rv;
00318       }
00319     }
00320   }
00321 
00322   rv=GWEN_MDigest_End(md);
00323   if (rv<0) {
00324     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00325     GWEN_SyncIo_Disconnect(sio);
00326     GWEN_SyncIo_free(sio);
00327     return rv;
00328   }
00329 
00330   GWEN_SyncIo_Disconnect(sio);
00331   GWEN_SyncIo_free(sio);
00332 
00333   rv=GWEN_Text_ToHexBuffer((const char*) GWEN_MDigest_GetDigestPtr(md),
00334                            GWEN_MDigest_GetDigestSize(md),
00335                            hbuf, 0, 0, 0);
00336   if (rv<0) {
00337     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00338     return rv;
00339   }
00340 
00341   return 0;
00342 }
00343 
00344 
00345 
00346 static int GWEN_MDigest__HashFileTree(GWEN_MDIGEST *md,
00347                                       const char *baseFolder,
00348                                       const char *relFolder,
00349                                       const char *ignoreFile,
00350                                       GWEN_STRINGLIST *sl) {
00351   GWEN_STRINGLIST *files;
00352   GWEN_STRINGLISTENTRY *se;
00353   GWEN_BUFFER *pbuf;
00354   uint32_t ppos;
00355   uint32_t rpos;
00356   int rv;
00357 
00358   files=GWEN_StringList_new();
00359   pbuf=GWEN_Buffer_new(0, 256, 0, 1);
00360   GWEN_Buffer_AppendString(pbuf, baseFolder);
00361   GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S);
00362   rpos=GWEN_Buffer_GetPos(pbuf);
00363   if (relFolder) {
00364     GWEN_Buffer_AppendString(pbuf, relFolder);
00365     GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S);
00366   }
00367   ppos=GWEN_Buffer_GetPos(pbuf);
00368 
00369   rv=GWEN_Directory_GetFileEntriesWithType(GWEN_Buffer_GetStart(pbuf), files, NULL);
00370   if (rv<0) {
00371     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00372     GWEN_Buffer_free(pbuf);
00373     GWEN_StringList_free(files);
00374     return rv;
00375   }
00376 
00377   se=GWEN_StringList_FirstEntry(files);
00378   while(se) {
00379     const char *s;
00380 
00381     s=GWEN_StringListEntry_Data(se);
00382     if (s && *s) {
00383       GWEN_Buffer_AppendString(pbuf, s+1);
00384       if (*s=='d') {
00385         if (strcasecmp(s+1, ".")!=0 && strcasecmp(s+1, "..")!=0) {
00386           rv=GWEN_MDigest__HashFileTree(md,
00387                                         baseFolder,
00388                                         GWEN_Buffer_GetStart(pbuf)+rpos,
00389                                         ignoreFile,
00390                                         sl);
00391           if (rv<0) {
00392             DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00393             GWEN_Buffer_free(pbuf);
00394             GWEN_StringList_free(files);
00395             return rv;
00396           }
00397         }
00398       }
00399       else if (*s=='f') {
00400         if (!(ignoreFile && strcasecmp(ignoreFile, s+1)==0)) {
00401           GWEN_BUFFER *tbuf;
00402           GWEN_BUFFER *xbuf;
00403           char *p;
00404 
00405           xbuf=GWEN_Buffer_new(0, 256, 0, 1);
00406           GWEN_Buffer_AppendString(xbuf, GWEN_Buffer_GetStart(pbuf)+rpos);
00407           p=GWEN_Buffer_GetStart(xbuf);
00408           while(*p) {
00409             if (*p=='\\')
00410               *p='/';
00411             p++;
00412           }
00413 
00414           tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00415 
00416           /* add relative path to line buffer */
00417           GWEN_Buffer_AppendString(tbuf, "F");
00418           rv=GWEN_Text_EscapeToBuffer(GWEN_Buffer_GetStart(xbuf), tbuf);
00419           GWEN_Buffer_free(xbuf);
00420           if (rv<0) {
00421             DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00422             GWEN_Buffer_free(tbuf);
00423             GWEN_Buffer_free(pbuf);
00424             GWEN_StringList_free(files);
00425             return rv;
00426           }
00427           GWEN_Buffer_AppendString(tbuf, ":");
00428 
00429           /* hash file */
00430           rv=GWEN_MDigest__HashFile(md, GWEN_Buffer_GetStart(pbuf), tbuf);
00431           if (rv<0) {
00432             DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00433             GWEN_Buffer_free(tbuf);
00434             GWEN_Buffer_free(pbuf);
00435             GWEN_StringList_free(files);
00436             return rv;
00437           }
00438 
00439           /* append line to stringlist */
00440           GWEN_StringList_AppendString(sl, GWEN_Buffer_GetStart(tbuf), 0, 0);
00441           GWEN_Buffer_free(tbuf);
00442         }
00443       }
00444       else {
00445         DBG_INFO(GWEN_LOGDOMAIN, "Unknown file type in [%s]", s);
00446       }
00447       GWEN_Buffer_Crop(pbuf, 0, ppos);
00448     }
00449     se=GWEN_StringListEntry_Next(se);
00450   }
00451 
00452   GWEN_Buffer_free(pbuf);
00453   GWEN_StringList_free(files);
00454   return 0;
00455 }
00456 
00457 
00458 
00459 int GWEN_MDigest_HashFileTree(GWEN_MDIGEST *md,
00460                               const char *folder,
00461                               const char *ignoreFile,
00462                               GWEN_STRINGLIST *sl) {
00463   int rv;
00464 
00465   rv=GWEN_MDigest__HashFileTree(md, folder, NULL, ignoreFile, sl);
00466   if (rv<0) {
00467     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00468     return rv;
00469   }
00470 
00471   return 0;
00472 }
00473 
00474 
00475 
00476 int GWEN_MDigest_CheckFileTree(GWEN_MDIGEST *md,
00477                                const char *folder,
00478                                const char *checksumFile,
00479                                int strictCheck,
00480                                uint32_t pid) {
00481   GWEN_STRINGLIST *sl;
00482   GWEN_STRINGLIST *savedList;
00483   GWEN_BUFFER *tbuf;
00484   GWEN_STRINGLISTENTRY *se;
00485   int rv;
00486   int allHashesOk=1;
00487   int validLines=0;
00488 
00489   sl=GWEN_StringList_new();
00490 
00491   /* generate hash list */
00492   rv=GWEN_MDigest_HashFileTree(md, folder, checksumFile, sl);
00493   if (rv<0) {
00494     GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00495                           I18N("Error unpacking program (%d)"), rv);
00496     GWEN_StringList_free(sl);
00497     return rv;
00498   }
00499 
00500   savedList=GWEN_StringList_new();
00501 
00502   /* read checksums from file */
00503   tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00504   GWEN_Buffer_AppendString(tbuf, folder);
00505   GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S);
00506   GWEN_Buffer_AppendString(tbuf, checksumFile);
00507   rv=GWEN_SyncIo_Helper_ReadFileToStringList(GWEN_Buffer_GetStart(tbuf),
00508                                              -1,
00509                                              savedList);
00510   if (rv<0) {
00511     GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00512                           I18N("Error loading checksum file (%d)"), rv);
00513     GWEN_Buffer_free(tbuf);
00514     GWEN_StringList_free(savedList);
00515     GWEN_StringList_free(sl);
00516     return rv;
00517   }
00518   GWEN_Buffer_free(tbuf);
00519 
00520   /* check checksums */
00521   se=GWEN_StringList_FirstEntry(savedList);
00522   while(se) {
00523     const char *s;
00524 
00525     s=GWEN_StringListEntry_Data(se);
00526     if (s && *s) {
00527       validLines++;
00528       if (0==GWEN_StringList_RemoveString(sl, s)) {
00529         DBG_ERROR(0, "Hash not found: %s", s);
00530         allHashesOk=0;
00531       }
00532     }
00533     se=GWEN_StringListEntry_Next(se);
00534   }
00535 
00536   if (validLines==0) {
00537     GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00538                           I18N("Checksum file does not contain valid lines"));
00539     GWEN_StringList_free(savedList);
00540     GWEN_StringList_free(sl);
00541     return GWEN_ERROR_VERIFY;
00542   }
00543 
00544   if (allHashesOk==0) {
00545     GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00546                           I18N("Integrity check on folder failed"));
00547     GWEN_StringList_free(savedList);
00548     GWEN_StringList_free(sl);
00549     return GWEN_ERROR_VERIFY;
00550   }
00551 
00552   /* check for additional files */
00553   if (GWEN_StringList_Count(sl)) {
00554     if (strictCheck) {
00555       GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00556                             I18N("Folder contains %d files without checksum"),
00557                             GWEN_StringList_Count(sl));
00558       GWEN_StringList_free(savedList);
00559       GWEN_StringList_free(sl);
00560     }
00561     else
00562       GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Warning,
00563                             I18N("Folder contains %d files without checksum"),
00564                             GWEN_StringList_Count(sl));
00565   }
00566   GWEN_StringList_free(savedList);
00567   GWEN_StringList_free(sl);
00568 
00569   return 0;
00570 }
00571 
00572 
00573 
00574 
00575 
00576