Coverage Report

Created: 2025-04-22 06:30

/src/unrar/crypt5.cpp
Line
Count
Source (jump to first uncovered line)
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
0
{
6
0
  const size_t Sha256BlockSize=64; // As defined in RFC 4868.
7
8
0
  byte KeyHash[SHA256_DIGEST_SIZE];
9
0
  if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash.
10
0
  {
11
0
    sha256_context KCtx;
12
0
    sha256_init(&KCtx);
13
0
    sha256_process(&KCtx, Key, KeyLength);
14
0
    sha256_done(&KCtx, KeyHash);
15
16
0
    Key = KeyHash;
17
0
    KeyLength = SHA256_DIGEST_SIZE;
18
0
  }
19
20
0
  byte KeyBuf[Sha256BlockSize]; // Store the padded key here.
21
0
  sha256_context ICtx;
22
23
0
  if (ICtxOpt!=NULL && *SetIOpt)
24
0
    ICtx=*ICtxOpt; // Use already calculated the first block context.
25
0
  else
26
0
  {
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
0
    for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest.
32
0
      KeyBuf[I] = Key[I] ^ 0x36;
33
0
    for (size_t I = KeyLength; I < Sha256BlockSize; I++)
34
0
      KeyBuf[I] = 0x36;
35
36
0
    sha256_init(&ICtx);
37
0
    sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key.
38
0
  }
39
40
0
  if (ICtxOpt!=NULL && !*SetIOpt) // Store constant context for further reuse.
41
0
  {
42
0
    *ICtxOpt=ICtx;
43
0
    *SetIOpt=true;
44
0
  }
45
46
0
  sha256_process(&ICtx, Data, DataLength); // Hash data.
47
48
0
  byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data.
49
0
  sha256_done(&ICtx, IDig);
50
51
0
  sha256_context RCtx;
52
53
0
  if (RCtxOpt!=NULL && *SetROpt)
54
0
    RCtx=*RCtxOpt; // Use already calculated first block context.
55
0
  else
56
0
  {
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
0
    for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding.
62
0
      KeyBuf[I] = Key[I] ^ 0x5c;
63
0
    for (size_t I = KeyLength; I < Sha256BlockSize; I++)
64
0
      KeyBuf[I] = 0x5c;
65
66
0
    sha256_init(&RCtx);
67
0
    sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key.
68
0
  }
69
70
0
  if (RCtxOpt!=NULL && !*SetROpt) // Store constant context for further reuse.
71
0
  {
72
0
    *RCtxOpt=RCtx;
73
0
    *SetROpt=true;
74
0
  }
75
76
0
  sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest.
77
78
0
  sha256_done(&RCtx, ResDigest);
79
0
}
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
0
{
89
0
  const size_t MaxSalt=64;
90
0
  byte SaltData[MaxSalt+4];
91
0
  memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
92
93
0
  SaltData[SaltLength + 0] = 0; // Block index appened to salt.
94
0
  SaltData[SaltLength + 1] = 0; //
95
0
  SaltData[SaltLength + 2] = 0; // Since we do not request the key width
96
0
  SaltData[SaltLength + 3] = 1; // exceeding HMAC width, it is always 1.
97
98
  // First iteration: HMAC of password, salt and block index (1).
99
0
  byte U1[SHA256_DIGEST_SIZE];
100
0
  hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1, NULL, NULL, NULL, NULL);
101
0
  byte Fn[SHA256_DIGEST_SIZE]; // Current function value.
102
0
  memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration.
103
104
0
  uint  CurCount[] = { Count-1, 16, 16 };
105
0
  byte *CurValue[] = { Key    , V1, V2 };
106
  
107
0
  sha256_context ICtxOpt,RCtxOpt;
108
0
  bool SetIOpt=false,SetROpt=false;
109
  
110
0
  byte U2[SHA256_DIGEST_SIZE];
111
0
  for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values.
112
0
  {
113
0
    for (uint J = 0; J < CurCount[I]; J++) 
114
0
    {
115
      // U2 = PRF (P, U1).
116
0
      hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2, &ICtxOpt, &SetIOpt, &RCtxOpt, &SetROpt);
117
0
      memcpy(U1, U2, sizeof(U1));
118
0
      for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U.
119
0
        Fn[K] ^= U1[K];
120
0
    }
121
0
    memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE);
122
0
  }
123
124
0
  cleandata(SaltData, sizeof(SaltData));
125
0
  cleandata(Fn, sizeof(Fn));
126
0
  cleandata(U1, sizeof(U1));
127
0
  cleandata(U2, sizeof(U2));
128
0
}
129
130
131
bool CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
132
     const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
133
     byte *PswCheck)
134
0
{
135
0
  if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
136
0
    return false;
137
138
0
  byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
139
0
  bool Found=false;
140
0
  for (uint I=0;I<ASIZE(KDF5Cache);I++)
141
0
  {
142
0
    KDF5CacheItem *Item=KDF5Cache+I;
143
0
    if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt && 
144
0
        memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
145
0
    {
146
0
      memcpy(Key,Item->Key,sizeof(Key));
147
0
      SecHideData(Key,sizeof(Key),false,false);
148
149
0
      memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue));
150
0
      memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue));
151
0
      Found=true;
152
0
      break;
153
0
    }
154
0
  }
155
156
0
  if (!Found)
157
0
  {
158
0
    char PwdUtf[MAXPASSWORD*4];
159
0
    WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf));
160
    
161
0
    pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<<Lg2Cnt));
162
0
    cleandata(PwdUtf,sizeof(PwdUtf));
163
164
0
    KDF5CacheItem *Item=KDF5Cache+(KDF5CachePos++ % ASIZE(KDF5Cache));
165
0
    Item->Lg2Count=Lg2Cnt;
166
0
    Item->Pwd=*Password;
167
0
    memcpy(Item->Salt,Salt,SIZE_SALT50);
168
0
    memcpy(Item->Key,Key,sizeof(Item->Key));
169
0
    memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue));
170
0
    memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue));
171
0
    SecHideData(Item->Key,sizeof(Item->Key),true,false);
172
0
  }
173
0
  if (HashKey!=NULL)
174
0
    memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE);
175
0
  if (PswCheck!=NULL)
176
0
  {
177
0
    memset(PswCheck,0,SIZE_PSWCHECK);
178
0
    for (uint I=0;I<SHA256_DIGEST_SIZE;I++)
179
0
      PswCheck[I%SIZE_PSWCHECK]^=PswCheckValue[I];
180
0
    cleandata(PswCheckValue,sizeof(PswCheckValue));
181
0
  }
182
183
  // NULL initialization vector is possible if we only need the password
184
  // check value for archive encryption header.
185
0
  if (InitV!=NULL)
186
0
    rin.Init(Encrypt, Key, 256, InitV);
187
188
0
  cleandata(Key,sizeof(Key));
189
0
  return true;
190
0
}
191
192
193
void ConvertHashToMAC(HashValue *Value,byte *Key)
194
0
{
195
0
  if (Value->Type==HASH_CRC32)
196
0
  {
197
0
    byte RawCRC[4];
198
0
    RawPut4(Value->CRC32,RawCRC);
199
0
    byte Digest[SHA256_DIGEST_SIZE];
200
0
    hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest,NULL,NULL,NULL,NULL);
201
0
    Value->CRC32=0;
202
0
    for (uint I=0;I<ASIZE(Digest);I++)
203
0
      Value->CRC32^=Digest[I] << ((I & 3) * 8);
204
0
    Value->CRC32&=0xffffffff; // In case the variable size is larger than 32-bit.
205
0
  }
206
0
  if (Value->Type==HASH_BLAKE2)
207
0
  {
208
0
    byte Digest[BLAKE2_DIGEST_SIZE];
209
0
    hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest,NULL,NULL,NULL,NULL);
210
0
    memcpy(Value->Digest,Digest,sizeof(Value->Digest));
211
0
  }
212
0
}
213
214
215
#if 0
216
static void TestPBKDF2();
217
struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF;
218
219
void TestPBKDF2() // Test PBKDF2 HMAC-SHA256
220
{
221
  byte Key[32],V1[32],V2[32];
222
223
  pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1);
224
  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 };
225
  mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed");
226
227
  pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096);
228
  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 };
229
  mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed");
230
231
  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);
232
  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};
233
  mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed");
234
}
235
#endif