1 #include "rar.hpp"
2 
Init(HASH_TYPE Type)3 void HashValue::Init(HASH_TYPE Type)
4 {
5   HashValue::Type=Type;
6 
7   // Zero length data CRC32 is 0. It is important to set it when creating
8   // headers with no following data like directories or symlinks.
9   if (Type==HASH_RAR14 || Type==HASH_CRC32)
10     CRC32=0;
11   if (Type==HASH_BLAKE2)
12   {
13     // dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f
14     // is BLAKE2sp hash of empty data. We init the structure to this value,
15     // so if we create a file or service header with no following data like
16     // "file copy" or "symlink", we set the checksum to proper value avoiding
17     // additional header type or size checks when extracting.
18     static byte EmptyHash[32]={
19       0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43,
20       0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25,
21       0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1,
22       0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f
23     };
24     memcpy(Digest,EmptyHash,sizeof(Digest));
25   }
26 }
27 
28 
operator ==(const HashValue & cmp)29 bool HashValue::operator == (const HashValue &cmp)
30 {
31   if (Type==HASH_NONE || cmp.Type==HASH_NONE)
32     return true;
33   if (Type==HASH_RAR14 && cmp.Type==HASH_RAR14 ||
34       Type==HASH_CRC32 && cmp.Type==HASH_CRC32)
35     return CRC32==cmp.CRC32;
36   if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2)
37     return memcmp(Digest,cmp.Digest,sizeof(Digest))==0;
38   return false;
39 }
40 
41 
DataHash()42 DataHash::DataHash()
43 {
44   blake2ctx=NULL;
45   HashType=HASH_NONE;
46 #ifdef RAR_SMP
47   ThPool=NULL;
48   MaxThreads=0;
49 #endif
50 }
51 
52 
~DataHash()53 DataHash::~DataHash()
54 {
55 #ifdef RAR_SMP
56   delete ThPool;
57 #endif
58   cleandata(&CurCRC32, sizeof(CurCRC32));
59   if (blake2ctx!=NULL)
60   {
61     cleandata(blake2ctx, sizeof(blake2sp_state));
62     delete blake2ctx;
63   }
64 }
65 
66 
Init(HASH_TYPE Type,uint MaxThreads)67 void DataHash::Init(HASH_TYPE Type,uint MaxThreads)
68 {
69   if (blake2ctx==NULL)
70     blake2ctx=new blake2sp_state;
71   HashType=Type;
72   if (Type==HASH_RAR14)
73     CurCRC32=0;
74   if (Type==HASH_CRC32)
75     CurCRC32=0xffffffff; // Initial CRC32 value.
76   if (Type==HASH_BLAKE2)
77     blake2sp_init(blake2ctx);
78 #ifdef RAR_SMP
79   DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads);
80 #endif
81 }
82 
83 
Update(const void * Data,size_t DataSize)84 void DataHash::Update(const void *Data,size_t DataSize)
85 {
86 #ifndef SFX_MODULE
87   if (HashType==HASH_RAR14)
88     CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize);
89 #endif
90   if (HashType==HASH_CRC32)
91     CurCRC32=CRC32(CurCRC32,Data,DataSize);
92 
93   if (HashType==HASH_BLAKE2)
94   {
95 #ifdef RAR_SMP
96     if (MaxThreads>1 && ThPool==NULL)
97       ThPool=new ThreadPool(BLAKE2_THREADS_NUMBER);
98     blake2ctx->ThPool=ThPool;
99     blake2ctx->MaxThreads=MaxThreads;
100 #endif
101     blake2sp_update( blake2ctx, (byte *)Data, DataSize);
102   }
103 }
104 
105 
Result(HashValue * Result)106 void DataHash::Result(HashValue *Result)
107 {
108   Result->Type=HashType;
109   if (HashType==HASH_RAR14)
110     Result->CRC32=CurCRC32;
111   if (HashType==HASH_CRC32)
112     Result->CRC32=CurCRC32^0xffffffff;
113   if (HashType==HASH_BLAKE2)
114   {
115     // Preserve the original context, so we can continue hashing if necessary.
116     blake2sp_state res=*blake2ctx;
117     blake2sp_final(&res,Result->Digest);
118   }
119 }
120 
121 
GetCRC32()122 uint DataHash::GetCRC32()
123 {
124   return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0;
125 }
126 
127 
Cmp(HashValue * CmpValue,byte * Key)128 bool DataHash::Cmp(HashValue *CmpValue,byte *Key)
129 {
130   HashValue Final;
131   Result(&Final);
132   if (Key!=NULL)
133     ConvertHashToMAC(&Final,Key);
134   return Final==*CmpValue;
135 }
136