"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/crypt5.cpp" (4 May 2022, 8021 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "crypt5.cpp" see the
Fossies "Dox" file reference documentation.
1 static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
2 size_t DataLength,byte *ResDigest,
3 sha256_context *ICtxOpt,bool *SetIOpt,
4 sha256_context *RCtxOpt,bool *SetROpt)
5 {
6 const size_t Sha256BlockSize=64; // As defined in RFC 4868.
7
8 byte KeyHash[SHA256_DIGEST_SIZE];
9 if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash.
10 {
11 sha256_context KCtx;
12 sha256_init(&KCtx);
13 sha256_process(&KCtx, Key, KeyLength);
14 sha256_done(&KCtx, KeyHash);
15
16 Key = KeyHash;
17 KeyLength = SHA256_DIGEST_SIZE;
18 }
19
20 byte KeyBuf[Sha256BlockSize]; // Store the padded key here.
21 sha256_context ICtx;
22
23 if (ICtxOpt!=NULL && *SetIOpt)
24 ICtx=*ICtxOpt; // Use already calculated first block context.
25 else
26 {
27 // This calculation is the same for all iterations with same password.
28 // So for PBKDF2 we can calculate it only for first block and then reuse
29 // to improve performance.
30
31 for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest.
32 KeyBuf[I] = Key[I] ^ 0x36;
33 for (size_t I = KeyLength; I < Sha256BlockSize; I++)
34 KeyBuf[I] = 0x36;
35
36 sha256_init(&ICtx);
37 sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key.
38 }
39
40 if (ICtxOpt!=NULL && !*SetIOpt) // Store constant context for further reuse.
41 {
42 *ICtxOpt=ICtx;
43 *SetIOpt=true;
44 }
45
46 sha256_process(&ICtx, Data, DataLength); // Hash data.
47
48 byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data.
49 sha256_done(&ICtx, IDig);
50
51 sha256_context RCtx;
52
53 if (RCtxOpt!=NULL && *SetROpt)
54 RCtx=*RCtxOpt; // Use already calculated first block context.
55 else
56 {
57 // This calculation is the same for all iterations with same password.
58 // So for PBKDF2 we can calculate it only for first block and then reuse
59 // to improve performance.
60
61 for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding.
62 KeyBuf[I] = Key[I] ^ 0x5c;
63 for (size_t I = KeyLength; I < Sha256BlockSize; I++)
64 KeyBuf[I] = 0x5c;
65
66 sha256_init(&RCtx);
67 sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key.
68 }
69
70 if (RCtxOpt!=NULL && !*SetROpt) // Store constant context for further reuse.
71 {
72 *RCtxOpt=RCtx;
73 *SetROpt=true;
74 }
75
76 sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest.
77
78 sha256_done(&RCtx, ResDigest);
79 }
80
81
82 // PBKDF2 for 32 byte key length. We generate the key for specified number
83 // of iteration count also as two supplementary values (key for checksums
84 // and password verification) for iterations+16 and iterations+32.
85 void pbkdf2(const byte *Pwd, size_t PwdLength,
86 const byte *Salt, size_t SaltLength,
87 byte *Key, byte *V1, byte *V2, uint Count)
88 {
89 const size_t MaxSalt=64;
90 byte SaltData[MaxSalt+4];
91 memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
92
93 SaltData[SaltLength + 0] = 0; // Salt concatenated to 1.
94 SaltData[SaltLength + 1] = 0;
95 SaltData[SaltLength + 2] = 0;
96 SaltData[SaltLength + 3] = 1;
97
98 // First iteration: HMAC of password, salt and block index (1).
99 byte U1[SHA256_DIGEST_SIZE];
100 hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1, NULL, NULL, NULL, NULL);
101 byte Fn[SHA256_DIGEST_SIZE]; // Current function value.
102 memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration.
103
104 uint CurCount[] = { Count-1, 16, 16 };
105 byte *CurValue[] = { Key , V1, V2 };
106
107 sha256_context ICtxOpt,RCtxOpt;
108 bool SetIOpt=false,SetROpt=false;
109
110 byte U2[SHA256_DIGEST_SIZE];
111 for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values.
112 {
113 for (uint J = 0; J < CurCount[I]; J++)
114 {
115 // U2 = PRF (P, U1).
116 hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2, &ICtxOpt, &SetIOpt, &RCtxOpt, &SetROpt);
117 memcpy(U1, U2, sizeof(U1));
118 for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U.
119 Fn[K] ^= U1[K];
120 }
121 memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE);
122 }
123
124 cleandata(SaltData, sizeof(SaltData));
125 cleandata(Fn, sizeof(Fn));
126 cleandata(U1, sizeof(U1));
127 cleandata(U2, sizeof(U2));
128 }
129
130
131 void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
132 const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
133 byte *PswCheck)
134 {
135 if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
136 return;
137
138 byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
139 bool Found=false;
140 for (uint I=0;I<ASIZE(KDF5Cache);I++)
141 {
142 KDF5CacheItem *Item=KDF5Cache+I;
143 if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
144 memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
145 {
146 memcpy(Key,Item->Key,sizeof(Key));
147 SecHideData(Key,sizeof(Key),false,false);
148
149 memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue));
150 memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue));
151 Found=true;
152 break;
153 }
154 }
155
156 if (!Found)
157 {
158 char PwdUtf[MAXPASSWORD*4];
159 WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf));
160
161 pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<<Lg2Cnt));
162 cleandata(PwdUtf,sizeof(PwdUtf));
163
164 KDF5CacheItem *Item=KDF5Cache+(KDF5CachePos++ % ASIZE(KDF5Cache));
165 Item->Lg2Count=Lg2Cnt;
166 Item->Pwd=*Password;
167 memcpy(Item->Salt,Salt,SIZE_SALT50);
168 memcpy(Item->Key,Key,sizeof(Item->Key));
169 memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue));
170 memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue));
171 SecHideData(Item->Key,sizeof(Item->Key),true,false);
172 }
173 if (HashKey!=NULL)
174 memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE);
175 if (PswCheck!=NULL)
176 {
177 memset(PswCheck,0,SIZE_PSWCHECK);
178 for (uint I=0;I<SHA256_DIGEST_SIZE;I++)
179 PswCheck[I%SIZE_PSWCHECK]^=PswCheckValue[I];
180 cleandata(PswCheckValue,sizeof(PswCheckValue));
181 }
182
183 // NULL initialization vector is possible if we only need the password
184 // check value for archive encryption header.
185 if (InitV!=NULL)
186 rin.Init(Encrypt, Key, 256, InitV);
187
188 cleandata(Key,sizeof(Key));
189 }
190
191
192 void ConvertHashToMAC(HashValue *Value,byte *Key)
193 {
194 if (Value->Type==HASH_CRC32)
195 {
196 byte RawCRC[4];
197 RawPut4(Value->CRC32,RawCRC);
198 byte Digest[SHA256_DIGEST_SIZE];
199 hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest,NULL,NULL,NULL,NULL);
200 Value->CRC32=0;
201 for (uint I=0;I<ASIZE(Digest);I++)
202 Value->CRC32^=Digest[I] << ((I & 3) * 8);
203 }
204 if (Value->Type==HASH_BLAKE2)
205 {
206 byte Digest[BLAKE2_DIGEST_SIZE];
207 hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest,NULL,NULL,NULL,NULL);
208 memcpy(Value->Digest,Digest,sizeof(Value->Digest));
209 }
210 }
211
212
213 #if 0
214 static void TestPBKDF2();
215 struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF;
216
217 void TestPBKDF2() // Test PBKDF2 HMAC-SHA256
218 {
219 byte Key[32],V1[32],V2[32];
220
221 pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1);
222 byte Res1[32]={0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b };
223 mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed");
224
225 pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096);
226 byte Res2[32]={0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a };
227 mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed");
228
229 pbkdf2((byte *)"just some long string pretending to be a password", 49, (byte *)"salt, salt, salt, a lot of salt", 31, Key, V1, V2, 65536);
230 byte Res3[32]={0x08, 0x0f, 0xa3, 0x1d, 0x42, 0x2d, 0xb0, 0x47, 0x83, 0x9b, 0xce, 0x3a, 0x3b, 0xce, 0x49, 0x51, 0xe2, 0x62, 0xb9, 0xff, 0x76, 0x2f, 0x57, 0xe9, 0xc4, 0x71, 0x96, 0xce, 0x4b, 0x6b, 0x6e, 0xbf};
231 mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed");
232 }
233 #endif