libclamunrar/hash.cpp
01eebc13
 #include "rar.hpp"
 
 void HashValue::Init(HASH_TYPE Type)
 {
   HashValue::Type=Type;
 
   // Zero length data CRC32 is 0. It is important to set it when creating
   // headers with no following data like directories or symlinks.
   if (Type==HASH_RAR14 || Type==HASH_CRC32)
     CRC32=0;
   if (Type==HASH_BLAKE2)
   {
     // dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f
     // is BLAKE2sp hash of empty data. We init the structure to this value,
     // so if we create a file or service header with no following data like
     // "file copy" or "symlink", we set the checksum to proper value avoiding
     // additional header type or size checks when extracting.
     static byte EmptyHash[32]={
       0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43,
       0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25,
       0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1,
       0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f
     };
     memcpy(Digest,EmptyHash,sizeof(Digest));
   }
 }
 
 
 bool HashValue::operator == (const HashValue &cmp)
 {
   if (Type==HASH_NONE || cmp.Type==HASH_NONE)
     return true;
   if (Type==HASH_RAR14 && cmp.Type==HASH_RAR14 || 
       Type==HASH_CRC32 && cmp.Type==HASH_CRC32)
     return CRC32==cmp.CRC32;
   if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2)
     return memcmp(Digest,cmp.Digest,sizeof(Digest))==0;
   return false;
 }
 
 
 DataHash::DataHash()
 {
   blake2ctx=NULL;
   HashType=HASH_NONE;
 #ifdef RAR_SMP
   ThPool=NULL;
   MaxThreads=0;
 #endif
 }
 
 
 DataHash::~DataHash()
 {
 #ifdef RAR_SMP
   DestroyThreadPool(ThPool);
 #endif
   cleandata(&CurCRC32, sizeof(CurCRC32));
   if (blake2ctx!=NULL)
   {
     cleandata(blake2ctx, sizeof(blake2sp_state));
     delete blake2ctx;
   }
 }
 
 
 void DataHash::Init(HASH_TYPE Type,uint MaxThreads)
 {
   if (blake2ctx==NULL)
     blake2ctx=new blake2sp_state;
   HashType=Type;
   if (Type==HASH_RAR14)
     CurCRC32=0;
   if (Type==HASH_CRC32)
     CurCRC32=0xffffffff; // Initial CRC32 value.
   if (Type==HASH_BLAKE2)
     blake2sp_init(blake2ctx);
 #ifdef RAR_SMP
   DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads);
 #endif
 }
 
 
 void DataHash::Update(const void *Data,size_t DataSize)
 {
 #ifndef SFX_MODULE
   if (HashType==HASH_RAR14)
     CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize);
 #endif
   if (HashType==HASH_CRC32)
     CurCRC32=CRC32(CurCRC32,Data,DataSize);
 
   if (HashType==HASH_BLAKE2)
   {
 #ifdef RAR_SMP
     if (MaxThreads>1 && ThPool==NULL)
       ThPool=CreateThreadPool();
     blake2ctx->ThPool=ThPool;
     blake2ctx->MaxThreads=MaxThreads;
 #endif
     blake2sp_update( blake2ctx, (byte *)Data, DataSize);
   }
 }
 
 
 void DataHash::Result(HashValue *Result)
 {
   Result->Type=HashType;
   if (HashType==HASH_RAR14)
     Result->CRC32=CurCRC32;
   if (HashType==HASH_CRC32)
     Result->CRC32=CurCRC32^0xffffffff;
   if (HashType==HASH_BLAKE2)
   {
     // Preserve the original context, so we can continue hashing if necessary.
     blake2sp_state res=*blake2ctx;
     blake2sp_final(&res,Result->Digest);
   }
 }
 
 
 uint DataHash::GetCRC32()
 {
   return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0;
 }
 
 
 bool DataHash::Cmp(HashValue *CmpValue,byte *Key)
 {
   HashValue Final;
   Result(&Final);
   if (Key!=NULL)
     ConvertHashToMAC(&Final,Key);
   return Final==*CmpValue;
 }