/src/SymCrypt/lib/rsa_padding.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // rsa_padding.c RSA padding algorithms |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | #include "precomp.h" |
8 | | |
9 | 0 | #define ASN1_SEQUENCE_BYTE (0x30) |
10 | 0 | #define ASN1_OCTET_STRING_BYTE (0x04) |
11 | | |
12 | | #define PKCS_BLOCKTYPE_1 (0x01) // This is not used, added here for completeness |
13 | 0 | #define PKCS_BLOCKTYPE_2 (0x02) |
14 | | |
15 | | // |
16 | | // Note: we could optimize these OID lists by using the same byte sequence for |
17 | | // the long and short versions. |
18 | | // |
19 | | const SYMCRYPT_OID SymCryptMd5OidList[] = |
20 | | { |
21 | | {12, (BYTE *)"\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00"}, |
22 | | {10, (BYTE *)"\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05"}, |
23 | | }; |
24 | | |
25 | | const SYMCRYPT_OID SymCryptSha1OidList[] = |
26 | | { |
27 | | {9, (BYTE *)"\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00"}, |
28 | | {7, (BYTE *)"\x06\x05\x2b\x0e\x03\x02\x1a"} |
29 | | }; |
30 | | |
31 | | const SYMCRYPT_OID SymCryptSha256OidList[] = |
32 | | { |
33 | | {13, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00"}, |
34 | | {11, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01"} |
35 | | }; |
36 | | |
37 | | const SYMCRYPT_OID SymCryptSha384OidList[] = |
38 | | { |
39 | | {13, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00"}, |
40 | | {11, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02"} |
41 | | }; |
42 | | |
43 | | const SYMCRYPT_OID SymCryptSha512OidList[] = |
44 | | { |
45 | | {13, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00"}, |
46 | | {11, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03"} |
47 | | }; |
48 | | |
49 | | const SYMCRYPT_OID SymCryptSha3_256OidList[] = |
50 | | { |
51 | | {13, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00"}, |
52 | | {11, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08"} |
53 | | }; |
54 | | |
55 | | const SYMCRYPT_OID SymCryptSha3_384OidList[] = |
56 | | { |
57 | | {13, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00"}, |
58 | | {11, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09"} |
59 | | }; |
60 | | |
61 | | const SYMCRYPT_OID SymCryptSha3_512OidList[] = |
62 | | { |
63 | | {13, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a\x05\x00"}, |
64 | | {11, (BYTE *)"\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a"} |
65 | | }; |
66 | | |
67 | | |
68 | | VOID |
69 | | SYMCRYPT_CALL |
70 | | SymCryptRsaPaddingMaskGeneration( |
71 | | _In_ PCSYMCRYPT_HASH hashAlgorithm, |
72 | | _In_ PVOID pHashState, |
73 | | _In_reads_bytes_( cbSrc ) PCBYTE pbSrc, |
74 | | SIZE_T cbSrc, |
75 | | _Out_writes_bytes_( cbDst ) PBYTE pbDst, |
76 | | SIZE_T cbDst ) |
77 | 0 | { |
78 | 0 | SIZE_T cIterations = 0; |
79 | |
|
80 | 0 | BYTE rgbHash[SYMCRYPT_HASH_MAX_RESULT_SIZE] = { 0 }; |
81 | 0 | BYTE rgbCount[sizeof(UINT32)] = { 0 }; |
82 | 0 | PBYTE pbCount = NULL; |
83 | 0 | SIZE_T cbMaskRemaining = cbDst; |
84 | 0 | PBYTE pbMaskIndex = pbDst; |
85 | |
|
86 | 0 | BOOLEAN fAvoidDWORDReverse = FALSE; |
87 | |
|
88 | 0 | SIZE_T cbHashAlg = SymCryptHashResultSize( hashAlgorithm ); |
89 | |
|
90 | 0 | cIterations = (cbDst + (cbHashAlg - 1)) / cbHashAlg; |
91 | 0 | if (cIterations < 256) |
92 | 0 | { |
93 | 0 | fAvoidDWORDReverse = TRUE; |
94 | 0 | } |
95 | |
|
96 | 0 | for (UINT32 i = 0; i < cIterations; i++) |
97 | 0 | { |
98 | 0 | SymCryptHashInit( hashAlgorithm, pHashState ); |
99 | | |
100 | | // hash the seed |
101 | 0 | SymCryptHashAppend( hashAlgorithm, pHashState, pbSrc, cbSrc ); |
102 | | |
103 | | // Reverse the count bytes |
104 | 0 | pbCount = (BYTE*)&i; |
105 | 0 | if (fAvoidDWORDReverse) |
106 | 0 | { |
107 | 0 | rgbCount[3] = pbCount[0]; |
108 | 0 | } |
109 | 0 | else |
110 | 0 | { |
111 | 0 | for (UINT32 j = 0; j < sizeof(UINT32); j++) |
112 | 0 | { |
113 | 0 | rgbCount[j] = pbCount[sizeof(UINT32) - j - 1]; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | // hash the count |
118 | 0 | SymCryptHashAppend( hashAlgorithm, pHashState, rgbCount, sizeof(UINT32) ); |
119 | | |
120 | | // copy the bytes from this hash into the mask buffer |
121 | 0 | if (cbMaskRemaining >= cbHashAlg) |
122 | 0 | { |
123 | 0 | SymCryptHashResult( hashAlgorithm, pHashState, pbMaskIndex, cbHashAlg ); |
124 | |
|
125 | 0 | cbMaskRemaining -= cbHashAlg; |
126 | 0 | pbMaskIndex += cbHashAlg; |
127 | 0 | } |
128 | 0 | else |
129 | 0 | { |
130 | 0 | SymCryptHashResult( hashAlgorithm, pHashState, rgbHash, cbHashAlg ); |
131 | |
|
132 | 0 | memcpy( pbMaskIndex, rgbHash, cbMaskRemaining); |
133 | 0 | break; |
134 | 0 | } |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | | // |
139 | | // PKCS1 Encryption Format: |
140 | | // 0x00 || 0x02 || PS || 0x00 || M |
141 | | // |
142 | | // |
143 | | SYMCRYPT_ERROR |
144 | | SYMCRYPT_CALL |
145 | | SymCryptRsaPkcs1ApplyEncryptionPadding( |
146 | | _In_reads_bytes_( cbPlaintext ) PCBYTE pbPlaintext, |
147 | | SIZE_T cbPlaintext, |
148 | | _Out_writes_bytes_( cbPkcs1Format ) PBYTE pbPkcs1Format, |
149 | | SIZE_T cbPkcs1Format ) |
150 | 0 | { |
151 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
152 | | |
153 | | // Format: 00 02 <PS> 00 <M> |
154 | | // <PS> 8 or more padding bytes, random, all nonzero |
155 | | // <M> message, length between 0 and cbPKCS1Format - 11. |
156 | | // See RFC 3447 for more details. |
157 | |
|
158 | 0 | SIZE_T cbPS; |
159 | 0 | SIZE_T i; |
160 | | |
161 | | // ensure output buffer is big enough (padding has 11 bytes overhead) |
162 | 0 | if( cbPkcs1Format < (cbPlaintext + 11) ) |
163 | 0 | { |
164 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
165 | 0 | goto cleanup; |
166 | 0 | } |
167 | | |
168 | 0 | cbPS = cbPkcs1Format - (cbPlaintext + 3); |
169 | |
|
170 | 0 | pbPkcs1Format[0] = 0x00; |
171 | 0 | pbPkcs1Format[1] = PKCS_BLOCKTYPE_2; |
172 | |
|
173 | 0 | scError = SymCryptCallbackRandom( &pbPkcs1Format[2], cbPS ); |
174 | 0 | if( scError != SYMCRYPT_NO_ERROR ) |
175 | 0 | { |
176 | 0 | goto cleanup; |
177 | 0 | } |
178 | | |
179 | | // Make sure that none of the bytes in PS is zero (as per specs) |
180 | 0 | for( i = 0; i < cbPS; i++ ) |
181 | 0 | { |
182 | 0 | while( pbPkcs1Format[2 + i] == 0x00 ) |
183 | 0 | { |
184 | 0 | scError = SymCryptCallbackRandom( &pbPkcs1Format[2+i], 1 ); |
185 | 0 | if( scError != SYMCRYPT_NO_ERROR ) |
186 | 0 | { |
187 | 0 | goto cleanup; |
188 | 0 | } |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | 0 | pbPkcs1Format[2 + cbPS] = 0x00; |
193 | |
|
194 | 0 | memcpy(pbPkcs1Format + 3 + cbPS, pbPlaintext, cbPlaintext); |
195 | |
|
196 | 0 | cleanup: |
197 | 0 | return scError; |
198 | 0 | } |
199 | | |
200 | | SYMCRYPT_ERROR |
201 | | SYMCRYPT_CALL |
202 | | SymCryptRsaPkcs1RemoveEncryptionPadding( |
203 | | _Inout_updates_bytes_( cbPkcs1Buffer ) PBYTE pbPkcs1Format, |
204 | | SIZE_T cbPkcs1Format, |
205 | | SIZE_T cbPkcs1Buffer, |
206 | | _Out_writes_bytes_opt_( cbPlaintext ) PBYTE pbPlaintext, |
207 | | SIZE_T cbPlaintext, |
208 | | _Out_ SIZE_T *pcbPlaintext ) |
209 | 0 | { |
210 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
211 | 0 | UINT32 mPaddingError = 0; |
212 | 0 | UINT32 mBufferSizeError = 0; |
213 | |
|
214 | 0 | UINT32 cbPlaintextResult = 0; |
215 | 0 | UINT32 i; |
216 | 0 | UINT32 mByteIsZero; |
217 | 0 | UINT32 mLengthFound; |
218 | 0 | UINT32 iFirstZero; |
219 | 0 | UINT32 cbPlaintextTruncated; |
220 | |
|
221 | 0 | SYMCRYPT_ASSERT( cbPkcs1Buffer >= cbPkcs1Format ); |
222 | 0 | SYMCRYPT_ASSERT( cbPkcs1Buffer >= 32 ); // Requirements for SymcryptScsRotateBuffer |
223 | 0 | SYMCRYPT_ASSERT( (cbPkcs1Buffer & (cbPkcs1Buffer - 1)) == 0 ); // must be a power of 2 |
224 | 0 | SYMCRYPT_ASSERT( cbPkcs1Buffer <= (1 << 30 )); // Ensure we can use 31-bit masking operations |
225 | | |
226 | | // Format: 00 02 <PS> 00 <M> |
227 | | // <PS> 8 or more padding bytes, random, all nonzero |
228 | | // <M> message, length between 0 and cbPKCS1Format - 11. |
229 | | // See RFC 3447 for more details. |
230 | | // We do not reveal the buffer contents through side-channels to avoid Bleichenbacher-style attacks |
231 | | // This includes the plaintext length, which is determined by the location of the 00 byte |
232 | |
|
233 | 0 | if ( cbPkcs1Format < 11 ) |
234 | 0 | { |
235 | | // cbPKCS1Format is public, so the if() is safe. 11 is the total overhead |
236 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
237 | 0 | goto cleanup; |
238 | 0 | } |
239 | | // this also implies that cbPkcs1Buffer >= 16 |
240 | | |
241 | | // Check the leading bytes |
242 | 0 | mPaddingError |= SymCryptMask32IsNonzeroU31( pbPkcs1Format[0] ); // First byte must be = 0 |
243 | 0 | mPaddingError |= SymCryptMask32NeqU31( pbPkcs1Format[1], PKCS_BLOCKTYPE_2 ); // Second byte must be = 2 |
244 | |
|
245 | 0 | iFirstZero = 0; |
246 | 0 | mLengthFound = 0; |
247 | 0 | for (i = 2; i < cbPkcs1Format; i++) |
248 | 0 | { |
249 | 0 | mByteIsZero = SymCryptMask32IsZeroU31( pbPkcs1Format[i] ); |
250 | | |
251 | | // remember the index of the first zero byte |
252 | 0 | iFirstZero |= i & mByteIsZero & ~mLengthFound; |
253 | 0 | mLengthFound |= mByteIsZero; |
254 | 0 | } |
255 | 0 | mPaddingError |= ~mLengthFound; |
256 | | |
257 | | // At this point: |
258 | | // - iFirstZero points to the first zero byte, or is 0 if there is no zero byte |
259 | | // - mPaddingError is set if no zero byte was found |
260 | | |
261 | | // It is an error if the first zero is at index < 10 as <PS> needs to be at least 8 bytes |
262 | 0 | mPaddingError |= SymCryptMask32LtU31( iFirstZero, 10 ); |
263 | | |
264 | | // Compute the # bytes of the message; 0 if there was a padding error |
265 | 0 | cbPlaintextResult = ~mPaddingError & (cbPkcs1Format - iFirstZero - 1); |
266 | | |
267 | | // We're done if the caller didn't want the actual message, but only the size. |
268 | | // We do that before checking the size of the plaintext buffer so that callers who |
269 | | // only want the size do not get an error. |
270 | 0 | if( pbPlaintext == NULL ) |
271 | 0 | { |
272 | | // Condition is public. |
273 | 0 | goto cleanup; |
274 | 0 | } |
275 | | |
276 | | // Checking that the output buffer is large enough is a bit tricky as we have a SIZE_T as |
277 | | // buffer size, but we like to work on 31-bit integers as they have better mask algorithm perf. |
278 | | // We can truncate the SIZE_T and check for equality, which is side-channel safe. |
279 | 0 | cbPlaintextTruncated = ((UINT32) cbPlaintext) & 0x7fffffff; // Truncate to 31 bits |
280 | 0 | if( cbPlaintextTruncated == cbPlaintext ) |
281 | 0 | { |
282 | | // Condition is public as we write the whole plaintext buffer anyway. |
283 | 0 | mBufferSizeError = SymCryptMask32LtU31( cbPlaintextTruncated, cbPlaintextResult ); |
284 | 0 | } |
285 | | |
286 | | // The message starts at iFirstZero + 1, which is a variable location so we can't just memcpy it without |
287 | | // revealing information through side channels. |
288 | | // Instead we rotate the buffer left (side-channel safe) so that the message appears at the front. |
289 | | // Rotation constant is such that the message appears at the start. |
290 | 0 | SymCryptScsRotateBuffer( pbPkcs1Format, cbPkcs1Buffer, (iFirstZero + 1) & (cbPkcs1Buffer - 1) ); |
291 | | |
292 | | // The ScsCopy function can copy the data to the destination buffer, but the input buffer must be |
293 | | // as long as the output buffer. We can't just use cbPlaintext as the output buffer size, as it is |
294 | | // unbounded. But we can limit it to cbPkcs1Format as that is the public key size and is public. |
295 | 0 | SymCryptScsCopy( pbPkcs1Format, cbPlaintextResult, pbPlaintext, SYMCRYPT_MIN( cbPlaintext, cbPkcs1Format ) ); |
296 | |
|
297 | 0 | cleanup: |
298 | | // Update scError with the two error masks. Padding error given highest priority. |
299 | 0 | scError ^= mBufferSizeError & (scError ^ SYMCRYPT_BUFFER_TOO_SMALL); |
300 | 0 | scError ^= mPaddingError & (scError ^ SYMCRYPT_INVALID_ARGUMENT); |
301 | |
|
302 | 0 | *pcbPlaintext = cbPlaintextResult; |
303 | 0 | return scError; |
304 | 0 | } |
305 | | |
306 | | // |
307 | | // OAEP Encryption Format: |
308 | | // +----------+---------+-------+ |
309 | | // DB = | lHash | PS | M | |
310 | | // +----------+---------+-------+ |
311 | | // | |
312 | | // +----------+ V |
313 | | // | seed |--> MGF ---> xor |
314 | | // +----------+ | |
315 | | // | | |
316 | | // +--+ V | |
317 | | // |00| xor <----- MGF <-----| |
318 | | // +--+ | | |
319 | | // | | | |
320 | | // V V V |
321 | | // +--+----------+----------------------------+ |
322 | | // EM = |00|maskedSeed| maskedDB | |
323 | | // +--+----------+----------------------------+ |
324 | | // |
325 | | // PS = zero or more bytes 0x00 || 0x01 |
326 | | // |
327 | | SYMCRYPT_ERROR |
328 | | SYMCRYPT_CALL |
329 | | SymCryptRsaOaepApplyEncryptionPadding( |
330 | | _In_reads_bytes_( cbPlaintext ) PCBYTE pbPlaintext, |
331 | | SIZE_T cbPlaintext, |
332 | | _In_ PCSYMCRYPT_HASH hashAlgorithm, |
333 | | _In_reads_bytes_( cbLabel ) PCBYTE pbLabel, |
334 | | SIZE_T cbLabel, |
335 | | _In_reads_bytes_opt_( cbSeed ) PCBYTE pbSeed, |
336 | | SIZE_T cbSeed, |
337 | | _Out_writes_bytes_( cbOaepFormat ) PBYTE pbOaepFormat, |
338 | | SIZE_T cbOaepFormat, |
339 | | _Out_writes_bytes_( cbScratch ) PBYTE pbScratch, |
340 | | SIZE_T cbScratch ) |
341 | 0 | { |
342 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
343 | |
|
344 | 0 | PVOID pHashState; |
345 | |
|
346 | 0 | PBYTE pbSeedInternal; |
347 | 0 | PBYTE pbSeedMask; |
348 | 0 | PBYTE pbDB; |
349 | 0 | PBYTE pbDBMask; |
350 | |
|
351 | 0 | SIZE_T cbDB; |
352 | 0 | SIZE_T cbPS; |
353 | |
|
354 | 0 | SIZE_T cbHash = SymCryptHashResultSize( hashAlgorithm ); |
355 | 0 | SIZE_T cbHashState = SymCryptHashStateSize( hashAlgorithm ); |
356 | |
|
357 | 0 | UNREFERENCED_PARAMETER( cbScratch ); |
358 | | |
359 | | // OAEP overhead is 2 + 2 * size of hash result |
360 | 0 | if( cbOaepFormat < (cbPlaintext + (cbHash * 2) + 2) || |
361 | 0 | ((pbSeed!=NULL) && (cbSeed>cbHash)) || |
362 | 0 | ((pbSeed==NULL) && (cbSeed!=0)) ) |
363 | 0 | { |
364 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
365 | 0 | goto cleanup; |
366 | 0 | } |
367 | | |
368 | 0 | cbPS = cbOaepFormat - (cbPlaintext + (cbHash * 2) + 2); |
369 | 0 | cbDB = cbOaepFormat - (cbHash + 1); |
370 | |
|
371 | 0 | SYMCRYPT_ASSERT( cbScratch >= cbHashState + (cbHash * 2) + (cbDB * 2) ); |
372 | |
|
373 | 0 | pHashState = (PVOID) pbScratch; |
374 | 0 | pbSeedInternal = pbScratch + cbHashState; |
375 | 0 | pbSeedMask = pbSeedInternal + cbHash; |
376 | 0 | pbDB = pbSeedMask + cbHash; |
377 | 0 | pbDBMask = pbDB + cbDB; |
378 | | |
379 | | // hash the label |
380 | 0 | SymCryptHash( hashAlgorithm, pbLabel, cbLabel, pbDB, cbHash ); |
381 | |
|
382 | 0 | SymCryptWipe(pbDB + cbHash, cbPS); |
383 | 0 | pbDB[cbHash + cbPS] = 0x01; |
384 | | |
385 | | // dcl - are we quite sure that none of these numbers are under attacker control? |
386 | 0 | memcpy(pbDB + cbHash + cbPS + 1, pbPlaintext, cbPlaintext); |
387 | |
|
388 | 0 | if (NULL == pbSeed) |
389 | 0 | { |
390 | | // generate the random seed (same length as the hash result) |
391 | 0 | scError = SymCryptCallbackRandom( pbSeedInternal, cbHash ); |
392 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
393 | 0 | { |
394 | 0 | goto cleanup; |
395 | 0 | } |
396 | 0 | } |
397 | 0 | else |
398 | 0 | { |
399 | 0 | SymCryptWipe( pbSeedInternal, cbHash ); |
400 | 0 | memcpy(pbSeedInternal, pbSeed, cbSeed); |
401 | 0 | } |
402 | | |
403 | | // MGF(seed) |
404 | 0 | SymCryptRsaPaddingMaskGeneration( |
405 | 0 | hashAlgorithm, |
406 | 0 | pHashState, |
407 | 0 | pbSeedInternal, |
408 | 0 | cbHash, |
409 | 0 | pbDBMask, |
410 | 0 | cbDB); |
411 | | |
412 | | // set the most significant byte to 0x00 |
413 | 0 | pbOaepFormat[0] = 0x00; |
414 | | |
415 | | // XOR the DB and the mask MGF(seed) |
416 | 0 | for (UINT32 i = 0; i < cbDB; i++) |
417 | 0 | { |
418 | 0 | pbOaepFormat[cbHash + 1 + i] = pbDB[i] ^ pbDBMask[i]; |
419 | 0 | } |
420 | | |
421 | | // MGF(masked DB) |
422 | 0 | SymCryptRsaPaddingMaskGeneration( |
423 | 0 | hashAlgorithm, |
424 | 0 | pHashState, |
425 | 0 | pbOaepFormat + cbHash + 1, |
426 | 0 | cbDB, |
427 | 0 | pbSeedMask, |
428 | 0 | cbHash); |
429 | | |
430 | | // XOR the seed and the seed mask MGF(masked DB) |
431 | 0 | for (UINT32 i = 0; i < cbHash; i++) |
432 | 0 | { |
433 | 0 | pbOaepFormat[1 + i] = pbSeedInternal[i] ^ pbSeedMask[i]; |
434 | 0 | } |
435 | |
|
436 | 0 | scError = SYMCRYPT_NO_ERROR; |
437 | |
|
438 | 0 | cleanup: |
439 | |
|
440 | 0 | return scError; |
441 | 0 | } |
442 | | |
443 | | SYMCRYPT_ERROR |
444 | | SYMCRYPT_CALL |
445 | | SymCryptRsaOaepRemoveEncryptionPadding( |
446 | | _In_reads_bytes_( cbOAEPFormat ) |
447 | | PCBYTE pbOAEPFormat, |
448 | | SIZE_T cbOAEPFormat, |
449 | | _In_ PCSYMCRYPT_HASH hashAlgorithm, |
450 | | _In_reads_bytes_( cbLabel ) PCBYTE pbLabel, |
451 | | SIZE_T cbLabel, |
452 | | UINT32 flags, |
453 | | _Out_writes_bytes_( cbPlaintext ) |
454 | | PBYTE pbPlaintext, |
455 | | SIZE_T cbPlaintext, |
456 | | _Out_ SIZE_T *pcbPlaintext, |
457 | | _Out_writes_bytes_( cbScratch ) |
458 | | PBYTE pbScratch, |
459 | | SIZE_T cbScratch ) |
460 | 0 | { |
461 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
462 | |
|
463 | 0 | PVOID pHashState; |
464 | |
|
465 | 0 | PBYTE pbSeedMask; |
466 | 0 | PBYTE pbSeed; |
467 | 0 | PBYTE pbDBMask; |
468 | 0 | PBYTE pbDB; |
469 | 0 | PBYTE pbLabelHash; |
470 | 0 | UINT32 mPaddingError; |
471 | |
|
472 | 0 | SIZE_T cbDB; |
473 | |
|
474 | 0 | SIZE_T cnt = 0; |
475 | |
|
476 | 0 | SIZE_T cbHashAlg = SymCryptHashResultSize( hashAlgorithm ); |
477 | 0 | SIZE_T cbHashState = SymCryptHashStateSize( hashAlgorithm ); |
478 | |
|
479 | 0 | UNREFERENCED_PARAMETER( cbScratch ); |
480 | |
|
481 | 0 | if (flags != 0) |
482 | 0 | { |
483 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
484 | 0 | goto cleanup; |
485 | 0 | } |
486 | | |
487 | | // check if the most significant byte is set to 0x00 |
488 | 0 | mPaddingError = SymCryptMask32IsNonzeroU31( pbOAEPFormat[0] ); |
489 | | |
490 | | // Padding overhead is 2 hash values plus 2 bytes |
491 | 0 | if( cbOAEPFormat < (2*cbHashAlg + 2) ) |
492 | 0 | { |
493 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
494 | 0 | goto cleanup; |
495 | 0 | } |
496 | | |
497 | 0 | cbDB = cbOAEPFormat - (cbHashAlg + 1); |
498 | |
|
499 | 0 | SYMCRYPT_ASSERT( cbScratch >= cbHashState + (cbHashAlg * 3) + (cbDB * 2) ); |
500 | |
|
501 | 0 | pHashState = (PVOID) pbScratch; |
502 | 0 | pbSeedMask = pbScratch + cbHashState; |
503 | 0 | pbSeed = pbSeedMask + cbHashAlg; |
504 | 0 | pbDBMask = pbSeed + cbHashAlg; |
505 | 0 | pbDB = pbDBMask + cbDB; |
506 | 0 | pbLabelHash = pbDB + cbDB; |
507 | | |
508 | | // MGF(masked DB) |
509 | 0 | SymCryptRsaPaddingMaskGeneration( |
510 | 0 | hashAlgorithm, |
511 | 0 | pHashState, |
512 | 0 | pbOAEPFormat + cbHashAlg + 1, |
513 | 0 | cbDB, |
514 | 0 | pbSeedMask, |
515 | 0 | cbHashAlg); |
516 | | |
517 | | // XOR the masked seed and the seed mask MGF(masked DB) |
518 | 0 | for (UINT32 i = 0; i < cbHashAlg; i++) |
519 | 0 | { |
520 | 0 | pbSeed[i] = pbOAEPFormat[1 + i] ^ pbSeedMask[i]; |
521 | 0 | } |
522 | | |
523 | | // MGF(seed) |
524 | 0 | SymCryptRsaPaddingMaskGeneration( |
525 | 0 | hashAlgorithm, |
526 | 0 | pHashState, |
527 | 0 | pbSeed, |
528 | 0 | cbHashAlg, |
529 | 0 | pbDBMask, |
530 | 0 | cbDB); |
531 | | |
532 | | // XOR the masked DB and the mask MGF(seed) |
533 | 0 | for (UINT32 i = 0; i < cbDB; i++) |
534 | 0 | { |
535 | 0 | pbDB[i] = pbOAEPFormat[cbHashAlg + 1 + i] ^ pbDBMask[i]; |
536 | 0 | } |
537 | | |
538 | | // hash the label |
539 | 0 | SymCryptHash( hashAlgorithm, pbLabel, cbLabel, pbLabelHash, cbHashAlg ); |
540 | | |
541 | | // check the label hash |
542 | 0 | mPaddingError |= SymCryptMask32IsZeroU31( SymCryptEqual( pbLabelHash, pbDB, cbHashAlg ) ); |
543 | | |
544 | | // |
545 | | // At this point we have verified the leading 0 byte and the label hash, with any |
546 | | // errors in mPaddingError. We could continue to make the entire padding removal |
547 | | // side-channel safe like we do in the PKCS1 padding case, but that is not necessary. |
548 | | // The side-channel only leaks data if the attacker can trigger two different behaviours |
549 | | // and derive information from the difference. |
550 | | // This is relatively easy to do with something like a match on 1 or 2 bytes because the |
551 | | // chance of satisfying the check on a random input is still useful. But here we have |
552 | | // matched 33 bytes (assuming a 32-byte hash) and the Bleichenbacher style attacks don't |
553 | | // work beyond this point. Basically, these attacks produce ciphertexts without knowing |
554 | | // the corresponding plaintext, and the chance of the label hash matching is something |
555 | | // like 2^{-256}. So these ciphertexts will always fail right here, and there is no |
556 | | // difference of behaviour that leaks data to the attacker. |
557 | | // Thus, we can switch back to normal processing of the errors here. |
558 | | // |
559 | |
|
560 | 0 | if( mPaddingError != 0 ) |
561 | 0 | { |
562 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
563 | 0 | goto cleanup; |
564 | 0 | } |
565 | | |
566 | | // check the PS |
567 | 0 | for (cnt = cbHashAlg; cnt < cbDB; cnt++) |
568 | 0 | { |
569 | 0 | if (pbDB[cnt] == 0x01) |
570 | 0 | { |
571 | 0 | cnt++; |
572 | 0 | break; |
573 | 0 | } |
574 | 0 | else if (pbDB[cnt] != 0x00) |
575 | 0 | { |
576 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
577 | 0 | goto cleanup; |
578 | 0 | } |
579 | 0 | } |
580 | | |
581 | | // the rest is data |
582 | 0 | *pcbPlaintext = cbDB - cnt; |
583 | |
|
584 | 0 | if(NULL == pbPlaintext) |
585 | 0 | { |
586 | 0 | scError = SYMCRYPT_NO_ERROR; |
587 | 0 | goto cleanup; |
588 | 0 | } |
589 | | |
590 | 0 | if (cbPlaintext < *pcbPlaintext) |
591 | 0 | { |
592 | 0 | scError = SYMCRYPT_BUFFER_TOO_SMALL; |
593 | 0 | goto cleanup; |
594 | 0 | } |
595 | | |
596 | 0 | memcpy(pbPlaintext, pbDB + cnt, *pcbPlaintext); |
597 | |
|
598 | 0 | scError = SYMCRYPT_NO_ERROR; |
599 | |
|
600 | 0 | cleanup: |
601 | |
|
602 | 0 | return scError; |
603 | 0 | } |
604 | | |
605 | | // |
606 | | // PKCS1 Signature Format: |
607 | | // |
608 | | SYMCRYPT_ERROR |
609 | | SYMCRYPT_CALL |
610 | | SymCryptRsaPkcs1ApplySignaturePadding( |
611 | | _In_reads_bytes_( cbHash ) PCBYTE pbHash, |
612 | | SIZE_T cbHash, |
613 | | _In_reads_bytes_( cbHashOid ) |
614 | | PCBYTE pbHashOid, |
615 | | SIZE_T cbHashOid, |
616 | | UINT32 flags, |
617 | | _Out_writes_bytes_( cbPKCS1Format ) |
618 | | PBYTE pbPKCS1Format, |
619 | | SIZE_T cbPKCS1Format ) |
620 | 0 | { |
621 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
622 | |
|
623 | 0 | SIZE_T cbEncoding; |
624 | 0 | SIZE_T cbPadding; |
625 | 0 | SIZE_T cbOidOffset; |
626 | |
|
627 | 0 | BOOLEAN fInsertASN1 = TRUE; |
628 | |
|
629 | 0 | if ((flags & ~SYMCRYPT_FLAG_RSA_PKCS1_NO_ASN1) != 0) |
630 | 0 | { |
631 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
632 | 0 | goto cleanup; |
633 | 0 | } |
634 | | |
635 | 0 | fInsertASN1 = ((flags & SYMCRYPT_FLAG_RSA_PKCS1_NO_ASN1) == 0); |
636 | |
|
637 | 0 | if (fInsertASN1) |
638 | 0 | { |
639 | 0 | if ( (pbHashOid!=NULL) && (cbHashOid>0) ) |
640 | 0 | { |
641 | | // determine the length of the ASN1 Encoding |
642 | | // 2 sequence bytes, 1 id byte and 3 length bytes |
643 | 0 | cbEncoding = 6 + cbHashOid + cbHash; |
644 | 0 | } |
645 | 0 | else |
646 | 0 | { |
647 | 0 | if (cbHashOid > 0) |
648 | 0 | { |
649 | | // The caller has passed a NULL hash and a non 0 size for it. |
650 | | // We can't guess the intent, hence we fail |
651 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
652 | 0 | goto cleanup; |
653 | 0 | } |
654 | | |
655 | | // special case for MD5 hash without OID |
656 | 0 | cbEncoding = 2 + cbHash; |
657 | 0 | } |
658 | 0 | } |
659 | 0 | else |
660 | 0 | { |
661 | 0 | cbEncoding = cbHash; |
662 | 0 | } |
663 | | |
664 | | // we don't support encodings longer than 128 bytes, |
665 | | // with this check we know that the length of the OID as |
666 | | // well as the length of the hash value will each fit in |
667 | | // one byte |
668 | 0 | if (cbEncoding > 0x80) |
669 | 0 | { |
670 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
671 | 0 | goto cleanup; |
672 | 0 | } |
673 | | |
674 | | // In a few scenarios (involving small RSA keys), the new large SHA |
675 | | // hashes are too big to be signed by the specified key. |
676 | | // There must be at least 8 bytes of 0xff. |
677 | 0 | if (3 + 8 + cbEncoding > cbPKCS1Format) |
678 | 0 | { |
679 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
680 | 0 | goto cleanup; |
681 | 0 | } |
682 | | |
683 | 0 | cbPadding = cbPKCS1Format - 3 - cbEncoding; |
684 | | |
685 | | |
686 | | // insert the block type and delimiters |
687 | 0 | pbPKCS1Format[0] = 0x00; |
688 | 0 | pbPKCS1Format[1] = 0x01; |
689 | 0 | pbPKCS1Format[2 + cbPadding] = 0x00; |
690 | | |
691 | | // insert the type 1 padding |
692 | 0 | memset(pbPKCS1Format + 2, 0xff, cbPadding); |
693 | |
|
694 | 0 | if (fInsertASN1) |
695 | 0 | { |
696 | 0 | cbOidOffset = 1; |
697 | 0 | if ( (pbHashOid!=NULL) && (cbHashOid>0) ) |
698 | 0 | { |
699 | | // insert the algorithm encoding |
700 | 0 | pbPKCS1Format[2 + cbPadding + 1] = ASN1_SEQUENCE_BYTE; |
701 | 0 | pbPKCS1Format[2 + cbPadding + 2] = (BYTE)cbEncoding - 2; |
702 | | |
703 | | // insert the sequence string byte, length of the hash and the hash value |
704 | 0 | pbPKCS1Format[2 + cbPadding + 3] = ASN1_SEQUENCE_BYTE; |
705 | 0 | pbPKCS1Format[2 + cbPadding + 4] = (BYTE)cbHashOid; |
706 | 0 | cbOidOffset += 4; |
707 | 0 | memcpy(pbPKCS1Format + 2 + cbPadding + cbOidOffset, pbHashOid, cbHashOid); |
708 | 0 | } |
709 | | |
710 | | // insert the octet string byte, length of the hash and the hash value |
711 | 0 | pbPKCS1Format[2 + cbPadding + cbOidOffset + cbHashOid] = ASN1_OCTET_STRING_BYTE; |
712 | 0 | pbPKCS1Format[2 + cbPadding + cbOidOffset + cbHashOid + 1] = (BYTE)cbHash; |
713 | 0 | memcpy(pbPKCS1Format + 2 + cbPadding + cbOidOffset + cbHashOid + 2, pbHash, cbHash); |
714 | 0 | } |
715 | 0 | else |
716 | 0 | { |
717 | 0 | memcpy(pbPKCS1Format + 3 + cbPadding, pbHash, cbHash); |
718 | 0 | } |
719 | |
|
720 | 0 | scError = SYMCRYPT_NO_ERROR; |
721 | |
|
722 | 0 | cleanup: |
723 | |
|
724 | 0 | return scError; |
725 | 0 | } |
726 | | |
727 | | // |
728 | | // Check if a PKCS1 padding is valid with regard to a hash oid |
729 | | // |
730 | | SYMCRYPT_ERROR |
731 | | SYMCRYPT_CALL |
732 | | SymCryptRsaPkcs1CheckSignaturePadding( |
733 | | _In_reads_bytes_( cbHash ) PCBYTE pbHash, |
734 | | SIZE_T cbHash, |
735 | | _In_reads_bytes_( cbHashOid ) |
736 | | PCBYTE pbHashOid, |
737 | | SIZE_T cbHashOid, |
738 | | _In_reads_bytes_( cbPKCS1Format ) |
739 | | PCBYTE pbPKCS1Format, |
740 | | UINT32 flags, |
741 | | _Out_writes_bytes_( cbPKCS1Format ) |
742 | | PBYTE pbScratch, |
743 | | SIZE_T cbPKCS1Format) |
744 | 0 | { |
745 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
746 | |
|
747 | 0 | SymCryptWipe(pbScratch, cbPKCS1Format); |
748 | |
|
749 | 0 | scError = SymCryptRsaPkcs1ApplySignaturePadding( |
750 | 0 | pbHash, |
751 | 0 | cbHash, |
752 | 0 | pbHashOid, |
753 | 0 | cbHashOid, |
754 | 0 | flags, |
755 | 0 | pbScratch, |
756 | 0 | cbPKCS1Format ); |
757 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
758 | 0 | { |
759 | 0 | goto cleanup; |
760 | 0 | } |
761 | | |
762 | 0 | if ( SymCryptEqual(pbScratch, pbPKCS1Format, cbPKCS1Format) ) |
763 | 0 | { |
764 | 0 | scError = SYMCRYPT_NO_ERROR; |
765 | 0 | } |
766 | 0 | else |
767 | 0 | { |
768 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
769 | 0 | } |
770 | |
|
771 | 0 | cleanup: |
772 | |
|
773 | 0 | return scError; |
774 | 0 | } |
775 | | |
776 | | |
777 | | SYMCRYPT_ERROR |
778 | | SYMCRYPT_CALL |
779 | | SymCryptRsaPkcs1VerifySignaturePadding( |
780 | | _In_reads_bytes_( cbHash ) PCBYTE pbHash, |
781 | | SIZE_T cbHash, |
782 | | _In_reads_( nOIDCount ) PCSYMCRYPT_OID pHashOIDs, |
783 | | _In_ SIZE_T nOIDCount, |
784 | | _In_reads_bytes_( cbPKCS1Format ) |
785 | | PCBYTE pbPKCS1Format, |
786 | | SIZE_T cbPKCS1Format, |
787 | | UINT32 flags, |
788 | | _Out_writes_bytes_( cbScratch ) |
789 | | PBYTE pbScratch, |
790 | | SIZE_T cbScratch ) |
791 | 0 | { |
792 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
793 | 0 | UINT32 i = 0; |
794 | |
|
795 | 0 | UNREFERENCED_PARAMETER( cbScratch ); |
796 | 0 | SYMCRYPT_ASSERT( cbScratch >= cbPKCS1Format ); |
797 | |
|
798 | 0 | if ((flags & ~SYMCRYPT_FLAG_RSA_PKCS1_OPTIONAL_HASH_OID) != 0) |
799 | 0 | { |
800 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
801 | 0 | goto cleanup; |
802 | 0 | } |
803 | | |
804 | | // |
805 | | // Verify padding and the hash value |
806 | | // |
807 | 0 | if (pHashOIDs) |
808 | 0 | { |
809 | 0 | for (i = 0; i < nOIDCount; i++) |
810 | 0 | { |
811 | 0 | scError = SymCryptRsaPkcs1CheckSignaturePadding( |
812 | 0 | pbHash, |
813 | 0 | cbHash, |
814 | 0 | pHashOIDs[i].pbOID, |
815 | 0 | pHashOIDs[i].cbOID, |
816 | 0 | pbPKCS1Format, |
817 | 0 | 0, |
818 | 0 | pbScratch, |
819 | 0 | cbPKCS1Format ); |
820 | 0 | if (scError == SYMCRYPT_NO_ERROR) |
821 | 0 | { |
822 | 0 | break; |
823 | 0 | } |
824 | 0 | } |
825 | 0 | } |
826 | |
|
827 | 0 | if ((pHashOIDs == NULL ) || |
828 | 0 | (scError != SYMCRYPT_NO_ERROR && |
829 | 0 | flags & SYMCRYPT_FLAG_RSA_PKCS1_OPTIONAL_HASH_OID)) |
830 | 0 | { |
831 | | // if no OID is passed in, or |
832 | | // OID is passed in but failed verification, but OID is optional |
833 | 0 | scError = SymCryptRsaPkcs1CheckSignaturePadding( |
834 | 0 | pbHash, |
835 | 0 | cbHash, |
836 | 0 | NULL, |
837 | 0 | 0, |
838 | 0 | pbPKCS1Format, |
839 | 0 | SYMCRYPT_FLAG_RSA_PKCS1_NO_ASN1, |
840 | 0 | pbScratch, |
841 | 0 | cbPKCS1Format ); |
842 | 0 | } |
843 | |
|
844 | 0 | cleanup: |
845 | |
|
846 | 0 | return scError; |
847 | 0 | } |
848 | | |
849 | | // |
850 | | // PSS Signature Format: |
851 | | // +--------+----------+----------+ |
852 | | // M' = |Padding1| Hash M | salt | |
853 | | // +--------+----------+----------+ |
854 | | // | |
855 | | // +--------+----------+ V |
856 | | // DB = |Padding2| salt | Hash |
857 | | // +--------+----------+ | |
858 | | // | | |
859 | | // V | +--+ |
860 | | // xor <--- MGF <---| |bc| |
861 | | // | | +--+ |
862 | | // | | | |
863 | | // V V V |
864 | | // +-------------------+----------+--+ |
865 | | // EM = | maskedDB | H |bc| |
866 | | // +-------------------+----------+--+ |
867 | | // |
868 | | SYMCRYPT_ERROR |
869 | | SYMCRYPT_CALL |
870 | | SymCryptRsaPssApplySignaturePadding( |
871 | | _In_reads_bytes_( cbHash ) PCBYTE pbHash, |
872 | | SIZE_T cbHash, |
873 | | _In_ PCSYMCRYPT_HASH hashAlgorithm, |
874 | | _In_reads_bytes_opt_( cbSalt ) |
875 | | PCBYTE pbSalt, |
876 | | _In_range_(0, cbPSSFormat) SIZE_T cbSalt, |
877 | | UINT32 nBitsOfModulus, |
878 | | UINT32 flags, |
879 | | _Out_writes_bytes_( cbPSSFormat ) |
880 | | PBYTE pbPSSFormat, |
881 | | SIZE_T cbPSSFormat, |
882 | | _Out_writes_bytes_( cbScratch ) |
883 | | PBYTE pbScratch, |
884 | | SIZE_T cbScratch ) |
885 | 0 | { |
886 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
887 | |
|
888 | 0 | PVOID pHashState; |
889 | |
|
890 | 0 | PBYTE pbMPrime; |
891 | 0 | PBYTE pbDB; |
892 | 0 | PBYTE pbDBMask; |
893 | |
|
894 | 0 | SIZE_T cbDB; |
895 | 0 | SIZE_T cbMPrime; |
896 | 0 | SIZE_T cbPadding2; |
897 | |
|
898 | 0 | SIZE_T dwZeroBits = 0; // Number of bits of the leftmost bit to be zeroed |
899 | |
|
900 | 0 | SIZE_T cbHashAlg = SymCryptHashResultSize( hashAlgorithm ); |
901 | 0 | SIZE_T cbHashState = SymCryptHashStateSize( hashAlgorithm ); |
902 | |
|
903 | 0 | UNREFERENCED_PARAMETER( cbScratch ); |
904 | |
|
905 | 0 | if ((cbPSSFormat == 0) || (pbPSSFormat == NULL)) |
906 | 0 | { |
907 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
908 | 0 | goto cleanup; |
909 | 0 | } |
910 | | |
911 | | // Corner case of RFC 3447 for PSS: |
912 | | // If nBitsOfModulus == 1 mod 8, then emBits = nBitsOfModulus - 1 == 0 mod 8 |
913 | | // Thus the size of the input buffer in bytes is emLen = ceil(emBits /8), |
914 | | // one smaller than the size of the modulus. Fix this here by setting the |
915 | | // leftmost byte of the output equal to 0. |
916 | 0 | if (nBitsOfModulus%8 == 1) |
917 | 0 | { |
918 | 0 | pbPSSFormat[0] = 0; |
919 | 0 | pbPSSFormat++; |
920 | 0 | cbPSSFormat--; |
921 | 0 | } |
922 | |
|
923 | 0 | if ((flags!=0) || |
924 | 0 | (cbPSSFormat < (cbHashAlg + cbSalt + 2)) ) |
925 | 0 | { |
926 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
927 | 0 | goto cleanup; |
928 | 0 | } |
929 | | |
930 | 0 | cbDB = cbPSSFormat - (cbHashAlg + 1); |
931 | 0 | cbPadding2 = cbDB - cbSalt - 1; |
932 | 0 | cbMPrime = 8 + cbHash + cbSalt; |
933 | |
|
934 | 0 | SYMCRYPT_ASSERT( cbScratch >= cbHashState + cbMPrime + (cbDB * 2) ); |
935 | |
|
936 | 0 | pHashState = (PVOID) pbScratch; |
937 | 0 | pbMPrime = pbScratch + cbHashState; |
938 | 0 | pbDB = pbMPrime + cbMPrime; |
939 | 0 | pbDBMask = pbDB + cbDB; |
940 | | |
941 | | // set up the M Prime |
942 | 0 | SymCryptWipe(pbMPrime, 8); |
943 | 0 | memcpy(pbMPrime + 8, pbHash, cbHash); |
944 | |
|
945 | 0 | if (NULL == pbSalt) |
946 | 0 | { |
947 | | // generate the random salt |
948 | 0 | scError = SymCryptCallbackRandom( |
949 | 0 | pbMPrime + 8 + cbHash, |
950 | 0 | cbSalt); |
951 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
952 | 0 | { |
953 | 0 | goto cleanup; |
954 | 0 | } |
955 | 0 | } |
956 | 0 | else |
957 | 0 | { |
958 | | // copy the salt passed |
959 | 0 | memcpy(pbMPrime + 8 + cbHash, pbSalt, cbSalt); |
960 | 0 | } |
961 | | |
962 | | // hash the MPrime |
963 | 0 | SymCryptHash( hashAlgorithm, pbMPrime, cbMPrime, pbPSSFormat + cbDB, cbHashAlg ); |
964 | | |
965 | | // copy the same salt into the DB |
966 | 0 | SymCryptWipe(pbDB, cbPadding2); |
967 | 0 | pbDB[cbPadding2] = 0x01; |
968 | 0 | memcpy(pbDB + cbPadding2 + 1, pbMPrime + 8 + cbHash, cbSalt); |
969 | | |
970 | | // MGF(Hash of MPrime) |
971 | 0 | SymCryptRsaPaddingMaskGeneration( |
972 | 0 | hashAlgorithm, |
973 | 0 | pHashState, |
974 | 0 | pbPSSFormat + cbDB, |
975 | 0 | cbHashAlg, |
976 | 0 | pbDBMask, |
977 | 0 | cbDB); |
978 | | |
979 | | // XOR the DB and the mask MGF(seed) |
980 | 0 | for (UINT32 i = 0; i < cbDB; i++) |
981 | 0 | { |
982 | 0 | pbPSSFormat[i] = pbDB[i] ^ pbDBMask[i]; |
983 | 0 | } |
984 | | |
985 | | // calculate the number of bits to be zeroed |
986 | 0 | dwZeroBits = 8*cbPSSFormat + 1 - nBitsOfModulus; |
987 | | |
988 | | // mask off dwZeroBits worth of the encoded message |
989 | 0 | pbPSSFormat[0] &= (BYTE)(0xff >> dwZeroBits); |
990 | | |
991 | | // set the least significant byte of pbPSSFormat to bc |
992 | 0 | pbPSSFormat[cbPSSFormat - 1] = 0xbc; |
993 | |
|
994 | 0 | scError = SYMCRYPT_NO_ERROR; |
995 | |
|
996 | 0 | cleanup: |
997 | |
|
998 | 0 | return scError; |
999 | 0 | } |
1000 | | |
1001 | | SYMCRYPT_ERROR |
1002 | | SYMCRYPT_CALL |
1003 | | SymCryptRsaPssVerifySignaturePadding( |
1004 | | _In_reads_bytes_( cbHash ) PCBYTE pbHash, |
1005 | | SIZE_T cbHash, |
1006 | | _In_ PCSYMCRYPT_HASH hashAlgorithm, |
1007 | | _In_range_(0, cbPSSFormat) SIZE_T cbSalt, |
1008 | | _In_reads_bytes_( cbPSSFormat ) |
1009 | | PCBYTE pbPSSFormat, |
1010 | | SIZE_T cbPSSFormat, |
1011 | | UINT32 nBitsOfModulus, |
1012 | | UINT32 flags, |
1013 | | _Out_writes_bytes_( cbScratch ) |
1014 | | PBYTE pbScratch, |
1015 | | SIZE_T cbScratch ) |
1016 | 0 | { |
1017 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1018 | |
|
1019 | 0 | PVOID pHashState; |
1020 | |
|
1021 | 0 | PBYTE pbDBMask; |
1022 | 0 | PBYTE pbMPrime; |
1023 | 0 | PBYTE pbMPrimeHash; |
1024 | 0 | PCBYTE pbHashOfMPrimeIndex; |
1025 | |
|
1026 | 0 | SIZE_T cbDB; |
1027 | 0 | SIZE_T cbMPrime; |
1028 | 0 | SIZE_T cbPadding2; |
1029 | 0 | SIZE_T cbSaltObserved; |
1030 | |
|
1031 | 0 | SIZE_T dwZeroBits = 0; // Number of bits of the leftmost bit to be zeroed |
1032 | |
|
1033 | 0 | SIZE_T cbHashAlg = SymCryptHashResultSize( hashAlgorithm ); |
1034 | 0 | SIZE_T cbHashState = SymCryptHashStateSize( hashAlgorithm ); |
1035 | |
|
1036 | 0 | UNREFERENCED_PARAMETER( cbScratch ); |
1037 | |
|
1038 | 0 | if (((flags & ~SYMCRYPT_FLAG_RSA_PSS_VERIFY_WITH_MINIMUM_SALT) != 0) || |
1039 | 0 | (cbPSSFormat == 0) || |
1040 | 0 | (pbPSSFormat == NULL)) |
1041 | 0 | { |
1042 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1043 | 0 | goto cleanup; |
1044 | 0 | } |
1045 | | |
1046 | | // Corner case of RFC 3447 for PSS: |
1047 | | // If nBitsOfModulus == 1 mod 8, then emBits = nBitsOfModulus - 1 == 0 mod 8 |
1048 | | // Thus the size of the input buffer in bytes is emLen = ceil(emBits /8), |
1049 | | // one smaller than the size of the modulus. Fix this here by checking that the |
1050 | | // leftmost byte of the input equals 0. |
1051 | 0 | if (nBitsOfModulus%8 == 1) |
1052 | 0 | { |
1053 | 0 | if (pbPSSFormat[0] != 0) |
1054 | 0 | { |
1055 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1056 | 0 | goto cleanup; |
1057 | 0 | } |
1058 | 0 | pbPSSFormat++; |
1059 | 0 | cbPSSFormat--; |
1060 | 0 | } |
1061 | | |
1062 | | // calculate the number of bits to be zeroed |
1063 | 0 | dwZeroBits = 8*cbPSSFormat + 1 - nBitsOfModulus; |
1064 | | |
1065 | | // check the most significant dwZeroBits bits to ensure they're zero and |
1066 | | // check the least significant byte |
1067 | 0 | if( (cbPSSFormat < (cbHashAlg + cbSalt + 2)) || |
1068 | 0 | (pbPSSFormat[0] & (BYTE)(0xff << (8 - dwZeroBits))) != 0 || |
1069 | 0 | pbPSSFormat[cbPSSFormat - 1] != 0xbc |
1070 | 0 | ) |
1071 | 0 | { |
1072 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1073 | 0 | goto cleanup; |
1074 | 0 | } |
1075 | | |
1076 | 0 | cbDB = cbPSSFormat - (cbHashAlg + 1); |
1077 | |
|
1078 | 0 | pHashState = (PVOID) pbScratch; |
1079 | 0 | pbDBMask = pbScratch + cbHashState; |
1080 | | |
1081 | | // index to hash of M Prime |
1082 | 0 | pbHashOfMPrimeIndex = pbPSSFormat + (cbPSSFormat - (cbHashAlg + 1)); |
1083 | | |
1084 | | // MGF(masked DB) |
1085 | 0 | SymCryptRsaPaddingMaskGeneration( |
1086 | 0 | hashAlgorithm, |
1087 | 0 | pHashState, |
1088 | 0 | pbHashOfMPrimeIndex, |
1089 | 0 | cbHashAlg, |
1090 | 0 | pbDBMask, |
1091 | 0 | cbDB); |
1092 | | |
1093 | | // XOR the DB and the DB mask and store the result in pbDBMask (not needed after this) |
1094 | 0 | for (UINT32 i = 0; i < cbDB; i++) |
1095 | 0 | { |
1096 | 0 | pbDBMask[i] = pbPSSFormat[i] ^ pbDBMask[i]; |
1097 | 0 | } |
1098 | | |
1099 | | // mask off the first dwZeroBits |
1100 | 0 | pbDBMask[0] &= (BYTE)(0xff >> dwZeroBits); |
1101 | | |
1102 | | // find the length of the all-zeroes padding2 in pbDBMask |
1103 | | // padding2 must be terminated by a 0x01 byte |
1104 | 0 | for (cbPadding2 = 0; cbPadding2 < (cbDB - cbSalt); cbPadding2++) |
1105 | 0 | { |
1106 | 0 | if (pbDBMask[cbPadding2] == 0x01) |
1107 | 0 | { |
1108 | | // we have reached the end of padding2 |
1109 | 0 | break; |
1110 | 0 | } |
1111 | | |
1112 | 0 | if (pbDBMask[cbPadding2] != 0x00) |
1113 | 0 | { |
1114 | | // non-zero byte in what should be padding2 |
1115 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1116 | 0 | goto cleanup; |
1117 | 0 | } |
1118 | 0 | } |
1119 | | |
1120 | | // Here we have either: |
1121 | | // cbPadding2 == cbDB - cbSalt, which means the padding is too long |
1122 | | // or |
1123 | | // cbPadding2 <= cbDB - cbSalt - 1, and we have broken out of the loop when we found the 0x01 byte |
1124 | 0 | if( cbPadding2 == cbDB - cbSalt ) |
1125 | 0 | { |
1126 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1127 | 0 | goto cleanup; |
1128 | 0 | } |
1129 | | |
1130 | 0 | cbSaltObserved = cbDB - cbPadding2 - 1; |
1131 | | // cbSalt <= cbDB - cbPadding2 - 1 = cbSaltObserved |
1132 | | // so cbSaltObserved is acceptable value for signature verification |
1133 | | // with SYMCRYPT_FLAG_RSA_PSS_VERIFY_WITH_MINIMUM_SALT |
1134 | |
|
1135 | 0 | if( ((flags & SYMCRYPT_FLAG_RSA_PSS_VERIFY_WITH_MINIMUM_SALT) == 0) && |
1136 | 0 | cbSaltObserved != cbSalt ) |
1137 | 0 | { |
1138 | | // When SYMCRYPT_FLAG_RSA_PSS_VERIFY_WITH_MINIMUM_SALT not specified, |
1139 | | // we require salt length observed to exactly match the caller provided salt length |
1140 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1141 | 0 | goto cleanup; |
1142 | 0 | } |
1143 | | |
1144 | 0 | pbMPrime = pbDBMask + cbDB; |
1145 | 0 | cbMPrime = 8 + cbHash + cbSaltObserved; |
1146 | 0 | pbMPrimeHash = pbMPrime + cbMPrime; |
1147 | |
|
1148 | 0 | SYMCRYPT_ASSERT( cbScratch >= cbHashState + cbDB + cbMPrime + cbHashAlg ); |
1149 | | |
1150 | | // create the M Prime |
1151 | 0 | SymCryptWipe(pbMPrime, 8); |
1152 | 0 | memcpy(pbMPrime + 8, pbHash, cbHash); |
1153 | 0 | memcpy(pbMPrime + 8 + cbHash, |
1154 | 0 | pbDBMask + (cbDB - cbSaltObserved), |
1155 | 0 | cbSaltObserved); |
1156 | | |
1157 | | // hash the M Prime |
1158 | 0 | SymCryptHash( hashAlgorithm, pbMPrime, cbMPrime, pbMPrimeHash, cbHashAlg ); |
1159 | |
|
1160 | 0 | if ( !SymCryptEqual(pbPSSFormat + cbDB, pbMPrimeHash, cbHashAlg) ) |
1161 | 0 | { |
1162 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1163 | 0 | goto cleanup; |
1164 | 0 | } |
1165 | | |
1166 | 0 | scError = SYMCRYPT_NO_ERROR; |
1167 | |
|
1168 | 0 | cleanup: |
1169 | 0 | return scError; |
1170 | 0 | } |