Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/aeskw.c
15010 views
1
//
2
// aeskw.c Implementation of the AES-KW(P) block cipher modes
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
//
8
// The KW and KWP modes have inherently terrible performance characteristics from how they are
9
// defined. Notably, they require a serial chain of AES block operations 12x longer than an
10
// equivalent AES-CBC encryption (which is already not a favored mode just because of the serial
11
// nature).
12
// Additionally the intermediate state of AES-KW and AES-KWP must be of a size proportional to
13
// the plaintext / ciphertext, rather than fitting into some constant-sized state.
14
//
15
// The current strategy for intermediate state handling is to allocate an internal buffer for
16
// the state. We expect that the caller does not care too much about performance if they are using
17
// these modes, so the overhead of an allocation per operation should not be a problem.
18
//
19
// While it is possible to expose an API surface which uses the destination buffer as a scratch
20
// buffer to store intermediate state, this would break the read-once/write-once rule, making the
21
// API surface brittle to misuse if the caller is encrypting to memory that may be in a different
22
// security domain (i.e. kernel caller encrypting a secret directly into memory which is mapped to
23
// user mode).
24
// If we need to expose a non-allocating version, we can introduce a lower-level API where the
25
// caller provides an appropriately sized scratch buffer, but we will cross that bridge if it is
26
// required.
27
//
28
29
#include "precomp.h"
30
31
const UINT64 SymCryptAesKwDefaultICV = 0xA6A6A6A6A6A6A6A6;
32
const UINT32 SymCryptAesKwpDefaultICV = 0xA65959A6;
33
#define SYMCRYPT_AES_SEMIBLOCK_SIZE (SYMCRYPT_AES_BLOCK_SIZE / 2)
34
35
const SIZE_T SymCryptAesKWMinPlaintextLen = 16u; // 2*SYMCRYPT_AES_SEMIBLOCK_SIZE
36
const SIZE_T SymCryptAesKWMaxPlaintextLen = (1u<<31)-8;
37
const SIZE_T SymCryptAesKWMinCiphertextLen = 24u; // 3*SYMCRYPT_AES_SEMIBLOCK_SIZE
38
const SIZE_T SymCryptAesKWMaxCiphertextLen = (1u<<31);
39
40
const SIZE_T SymCryptAesKWPMinPlaintextLen = 1u;
41
const SIZE_T SymCryptAesKWPMaxPlaintextLen = (1u<<31)-8;
42
const SIZE_T SymCryptAesKWPMinCiphertextLen = 16u;
43
const SIZE_T SymCryptAesKWPMaxCiphertextLen = (1u<<31);
44
45
//
46
// This function corresponds to algorithm W(S) from section 6.1 of SP 800-38F
47
//
48
// We perform this algorithm destructively in place, reading and writing to the same location
49
// multiple times
50
//
51
static
52
VOID
53
SYMCRYPT_CALL
54
SymCryptAesKwxInternalWrap(
55
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
56
_Inout_updates_bytes_(cbBuf) PBYTE pbBuf,
57
UINT32 cbBuf )
58
{
59
SYMCRYPT_ALIGN BYTE activeBlock[SYMCRYPT_AES_BLOCK_SIZE];
60
const UINT32 nSemiBlocks = cbBuf / SYMCRYPT_AES_SEMIBLOCK_SIZE; // n per SP 800-38F
61
UINT64 encryptionIdx = 1; // t per SP 800-38F
62
UINT64 lowHalfTemp = 0;
63
64
SYMCRYPT_ASSERT((cbBuf & (SYMCRYPT_AES_SEMIBLOCK_SIZE-1)) == 0);
65
SYMCRYPT_ASSERT(cbBuf >= SymCryptAesKWMinCiphertextLen);
66
SYMCRYPT_ASSERT(cbBuf <= SymCryptAesKWMaxCiphertextLen);
67
68
// Special case for first encryption
69
// Initialize the low half of active block with the first semi-block of input
70
memcpy( activeBlock, pbBuf, SYMCRYPT_AES_SEMIBLOCK_SIZE);
71
72
for( UINT32 outerLoopCnt = 0; outerLoopCnt < 6; outerLoopCnt++ )
73
{
74
for( UINT32 innerLoopCnt = 1; innerLoopCnt < nSemiBlocks; innerLoopCnt++ )
75
{
76
SIZE_T bufOffset = innerLoopCnt*SYMCRYPT_AES_SEMIBLOCK_SIZE;
77
78
// Initialize the high half of active block to semi-block from buf
79
memcpy( activeBlock+SYMCRYPT_AES_SEMIBLOCK_SIZE, pbBuf+bufOffset, SYMCRYPT_AES_SEMIBLOCK_SIZE);
80
81
// Encrypt activeBlock in place
82
SymCryptAesEncrypt( pExpandedKey, activeBlock, activeBlock );
83
84
// Store the high half of result back to semi-block from buf
85
memcpy( pbBuf+bufOffset, activeBlock+SYMCRYPT_AES_SEMIBLOCK_SIZE, SYMCRYPT_AES_SEMIBLOCK_SIZE );
86
87
// Use the low half of the result and the next encryptionIdx to
88
// initialize the low half of the next encryption
89
lowHalfTemp = SYMCRYPT_LOAD_LSBFIRST64( activeBlock );
90
lowHalfTemp ^= SYMCRYPT_BSWAP64( encryptionIdx );
91
SYMCRYPT_STORE_LSBFIRST64( activeBlock, lowHalfTemp );
92
93
// Update encryptionIdx
94
encryptionIdx++;
95
}
96
}
97
98
SYMCRYPT_ASSERT( (encryptionIdx-1) == (nSemiBlocks-1)*6 );
99
100
// Special case for last encryption
101
// Store the final low half of encryption as the first semi-block of output
102
SYMCRYPT_STORE_LSBFIRST64( pbBuf, lowHalfTemp );
103
104
SymCryptWipeKnownSize( activeBlock, sizeof(activeBlock) );
105
}
106
107
//
108
// This function corresponds to algorithm W^-1(S) from section 6.1 of SP 800-38F
109
//
110
// We perform this algorithm destructively in place, reading and writing to the same location
111
// multiple times
112
//
113
static
114
VOID
115
SYMCRYPT_CALL
116
SymCryptAesKwxInternalUnwrap(
117
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
118
_Inout_updates_bytes_(cbBuf) PBYTE pbBuf,
119
UINT32 cbBuf )
120
{
121
SYMCRYPT_ALIGN BYTE activeBlock[SYMCRYPT_AES_BLOCK_SIZE];
122
const UINT32 nSemiBlocks = cbBuf / SYMCRYPT_AES_SEMIBLOCK_SIZE; // n per SP 800-38F
123
UINT64 decryptionIdx = 6*(nSemiBlocks-1); // t per SP 800-38F
124
UINT64 lowHalfTemp = 0;
125
126
SYMCRYPT_ASSERT((cbBuf & (SYMCRYPT_AES_SEMIBLOCK_SIZE-1)) == 0);
127
SYMCRYPT_ASSERT(cbBuf >= SymCryptAesKWMinCiphertextLen);
128
SYMCRYPT_ASSERT(cbBuf <= SymCryptAesKWMaxCiphertextLen);
129
130
// Special case for first decryption
131
// Initialize the low half temporary with the first semi-block of input
132
lowHalfTemp = SYMCRYPT_LOAD_LSBFIRST64( pbBuf );
133
134
for( UINT32 outerLoopCnt = 0; outerLoopCnt < 6; outerLoopCnt++ )
135
{
136
for( UINT32 innerLoopCnt = nSemiBlocks-1; innerLoopCnt > 0; innerLoopCnt-- )
137
{
138
SIZE_T bufOffset = innerLoopCnt*SYMCRYPT_AES_SEMIBLOCK_SIZE;
139
140
// Update low half with decryptionIdx and store to low half of active block
141
lowHalfTemp ^= SYMCRYPT_BSWAP64( decryptionIdx );
142
SYMCRYPT_STORE_LSBFIRST64( activeBlock, lowHalfTemp );
143
144
// Initialize the high half of active block to semi-block from buf
145
memcpy( activeBlock+SYMCRYPT_AES_SEMIBLOCK_SIZE, pbBuf+bufOffset, SYMCRYPT_AES_SEMIBLOCK_SIZE);
146
147
// Decrypt activeBlock in place
148
SymCryptAesDecrypt( pExpandedKey, activeBlock, activeBlock );
149
150
// Store the high half of result back to semi-block from buf
151
memcpy( pbBuf+bufOffset, activeBlock+SYMCRYPT_AES_SEMIBLOCK_SIZE, SYMCRYPT_AES_SEMIBLOCK_SIZE );
152
153
// Update decryptionIdx
154
decryptionIdx--;
155
156
// Use the low half of the result to set the low half temporary
157
lowHalfTemp = SYMCRYPT_LOAD_LSBFIRST64( activeBlock );
158
}
159
}
160
161
SYMCRYPT_ASSERT( decryptionIdx == 0 );
162
163
// Special case for last decryption
164
// Store the final low half of decryption as the first semi-block of output
165
SYMCRYPT_STORE_LSBFIRST64( pbBuf, lowHalfTemp );
166
167
SymCryptWipeKnownSize( activeBlock, sizeof(activeBlock) );
168
}
169
170
SYMCRYPT_ERROR
171
SYMCRYPT_CALL
172
SymCryptAesKwEncrypt(
173
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
174
_In_reads_(cbSrc) PCBYTE pbSrc,
175
SIZE_T cbSrc,
176
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
177
SIZE_T cbDst,
178
_Out_ SIZE_T* pcbResult )
179
{
180
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
181
PBYTE pbScratch = NULL;
182
UINT32 cbScratch = 0;
183
184
if( (cbSrc < SymCryptAesKWMinPlaintextLen) ||
185
(cbSrc > SymCryptAesKWMaxPlaintextLen) ||
186
((cbSrc & (SYMCRYPT_AES_SEMIBLOCK_SIZE-1)) != 0) )
187
{
188
scError = SYMCRYPT_INVALID_ARGUMENT;
189
goto cleanup;
190
}
191
192
cbScratch = ((UINT32) cbSrc)+SYMCRYPT_AES_SEMIBLOCK_SIZE;
193
if( cbDst < cbScratch )
194
{
195
scError = SYMCRYPT_BUFFER_TOO_SMALL;
196
goto cleanup;
197
}
198
199
pbScratch = SymCryptCallbackAlloc( cbScratch );
200
if( pbScratch == NULL )
201
{
202
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
203
goto cleanup;
204
}
205
206
// set up input buffer as ICV1 || P
207
SYMCRYPT_STORE_LSBFIRST64( pbScratch, SymCryptAesKwDefaultICV );
208
memcpy( pbScratch+8, pbSrc, cbSrc );
209
210
// encrypt input buffer in place
211
SymCryptAesKwxInternalWrap( pExpandedKey, pbScratch, cbScratch );
212
213
// copy encrypted buffer to output
214
memcpy( pbDst, pbScratch, cbScratch );
215
*pcbResult = cbScratch;
216
217
cleanup:
218
if( pbScratch != NULL )
219
{
220
SymCryptWipe( pbScratch, cbScratch );
221
SymCryptCallbackFree( pbScratch );
222
}
223
return scError;
224
}
225
226
SYMCRYPT_ERROR
227
SYMCRYPT_CALL
228
SymCryptAesKwDecrypt(
229
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
230
_In_reads_(cbSrc) PCBYTE pbSrc,
231
SIZE_T cbSrc,
232
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
233
SIZE_T cbDst,
234
_Out_ SIZE_T* pcbResult )
235
{
236
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
237
PBYTE pbScratch = NULL;
238
UINT32 cbScratch = 0;
239
240
if( (cbSrc < SymCryptAesKWMinCiphertextLen) ||
241
(cbSrc > SymCryptAesKWMaxCiphertextLen) ||
242
((cbSrc & (SYMCRYPT_AES_SEMIBLOCK_SIZE-1)) != 0) )
243
{
244
scError = SYMCRYPT_INVALID_ARGUMENT;
245
goto cleanup;
246
}
247
248
cbScratch = (UINT32) cbSrc;
249
if( cbDst < cbScratch-SYMCRYPT_AES_SEMIBLOCK_SIZE )
250
{
251
scError = SYMCRYPT_BUFFER_TOO_SMALL;
252
goto cleanup;
253
}
254
255
pbScratch = SymCryptCallbackAlloc( cbScratch );
256
if( pbScratch == NULL )
257
{
258
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
259
goto cleanup;
260
}
261
262
// set up input buffer as C
263
memcpy( pbScratch, pbSrc, cbSrc );
264
265
// decrypt input buffer in place
266
SymCryptAesKwxInternalUnwrap( pExpandedKey, pbScratch, cbScratch );
267
268
// check first semi-block has the expected value
269
if( SYMCRYPT_LOAD_LSBFIRST64( pbScratch ) != SymCryptAesKwDefaultICV )
270
{
271
scError = SYMCRYPT_AUTHENTICATION_FAILURE;
272
goto cleanup;
273
}
274
275
// copy decrypted buffer to output
276
memcpy( pbDst, pbScratch+SYMCRYPT_AES_SEMIBLOCK_SIZE, cbScratch-SYMCRYPT_AES_SEMIBLOCK_SIZE );
277
*pcbResult = cbScratch-SYMCRYPT_AES_SEMIBLOCK_SIZE;
278
279
cleanup:
280
if( pbScratch != NULL )
281
{
282
SymCryptWipe( pbScratch, cbScratch );
283
SymCryptCallbackFree( pbScratch );
284
}
285
return scError;
286
287
}
288
289
SYMCRYPT_ERROR
290
SYMCRYPT_CALL
291
SymCryptAesKwpEncrypt(
292
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
293
_In_reads_(cbSrc) PCBYTE pbSrc,
294
SIZE_T cbSrc,
295
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
296
SIZE_T cbDst,
297
_Out_ SIZE_T* pcbResult )
298
{
299
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
300
PBYTE pbScratch = NULL;
301
UINT32 cbScratch = 0;
302
UINT32 cbPad = 0;
303
304
if( (cbSrc < SymCryptAesKWPMinPlaintextLen) ||
305
(cbSrc > SymCryptAesKWPMaxPlaintextLen) )
306
{
307
scError = SYMCRYPT_INVALID_ARGUMENT;
308
goto cleanup;
309
}
310
311
cbPad = SYMCRYPT_AES_SEMIBLOCK_SIZE - ((UINT32) cbSrc & (SYMCRYPT_AES_SEMIBLOCK_SIZE-1));
312
if( cbPad == SYMCRYPT_AES_SEMIBLOCK_SIZE )
313
{
314
cbPad = 0;
315
}
316
317
cbScratch = (UINT32) cbSrc + SYMCRYPT_AES_SEMIBLOCK_SIZE + cbPad;
318
if( cbDst < cbScratch )
319
{
320
scError = SYMCRYPT_BUFFER_TOO_SMALL;
321
goto cleanup;
322
}
323
324
SYMCRYPT_ASSERT( cbScratch >= 16 );
325
326
pbScratch = SymCryptCallbackAlloc( cbScratch );
327
if( pbScratch == NULL )
328
{
329
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
330
goto cleanup;
331
}
332
333
// set up input buffer as ICV2 || len(P) || P || PAD
334
SYMCRYPT_STORE_LSBFIRST32( pbScratch, SymCryptAesKwpDefaultICV );
335
SYMCRYPT_STORE_MSBFIRST32( pbScratch+4, (UINT32) cbSrc );
336
// pad by unconditionally setting the last 8 bytes to 0
337
// then overwrite some or all of the padding bytes with plaintext
338
SYMCRYPT_STORE_LSBFIRST64( pbScratch+cbScratch-SYMCRYPT_AES_SEMIBLOCK_SIZE, 0u );
339
memcpy( pbScratch+8, pbSrc, cbSrc );
340
341
// encrypt input buffer in place
342
if( cbScratch == SYMCRYPT_AES_BLOCK_SIZE )
343
{
344
// special case for AES-KWP with small plaintext
345
SymCryptAesEncrypt( pExpandedKey, pbScratch, pbScratch );
346
} else {
347
SymCryptAesKwxInternalWrap( pExpandedKey, pbScratch, cbScratch );
348
}
349
350
// copy encrypted buffer to output
351
memcpy( pbDst, pbScratch, cbScratch );
352
*pcbResult = cbScratch;
353
354
cleanup:
355
if( pbScratch != NULL )
356
{
357
SymCryptWipe( pbScratch, cbScratch );
358
SymCryptCallbackFree( pbScratch );
359
}
360
return scError;
361
}
362
363
SYMCRYPT_ERROR
364
SYMCRYPT_CALL
365
SymCryptAesKwpDecrypt(
366
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
367
_In_reads_(cbSrc) PCBYTE pbSrc,
368
SIZE_T cbSrc,
369
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
370
SIZE_T cbDst,
371
_Out_ SIZE_T* pcbResult )
372
{
373
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
374
PBYTE pbScratch = NULL;
375
UINT32 cbScratch = 0;
376
UINT32 cbPlaintext = 0;
377
UINT32 cbPad = 0;
378
UINT32 mVerificationError = 0; // Mask indicating whether the decrypted buffer is malformed
379
UINT32 mIsPlaintext = 0; // Mask for plaintext bytes in the final semi-block
380
381
if( (cbSrc < SymCryptAesKWPMinCiphertextLen) ||
382
(cbSrc > SymCryptAesKWPMaxCiphertextLen) ||
383
((cbSrc & (SYMCRYPT_AES_SEMIBLOCK_SIZE-1)) != 0) )
384
{
385
scError = SYMCRYPT_INVALID_ARGUMENT;
386
goto cleanup;
387
}
388
389
cbScratch = (UINT32) cbSrc;
390
if( cbDst < cbScratch-SYMCRYPT_AES_SEMIBLOCK_SIZE-7 )
391
{
392
scError = SYMCRYPT_BUFFER_TOO_SMALL;
393
goto cleanup;
394
}
395
396
pbScratch = SymCryptCallbackAlloc( cbScratch );
397
if( pbScratch == NULL )
398
{
399
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
400
goto cleanup;
401
}
402
403
// set up input buffer as C
404
memcpy( pbScratch, pbSrc, cbSrc );
405
406
// decrypt input buffer in place
407
if( cbScratch == SYMCRYPT_AES_BLOCK_SIZE )
408
{
409
// special case for AES-KWP with small ciphertext
410
SymCryptAesDecrypt( pExpandedKey, pbScratch, pbScratch );
411
} else {
412
SymCryptAesKwxInternalUnwrap( pExpandedKey, pbScratch, cbScratch );
413
}
414
415
// Check if the decrypted buffer is of an expected form
416
// check bytes [0..3] are expected ICV
417
mVerificationError |= SYMCRYPT_LOAD_LSBFIRST32( pbScratch ) ^ SymCryptAesKwpDefaultICV;
418
419
// check bytes [4..7] are a valid plaintext length (i.e. computed cbPad in range [0,7])
420
cbPlaintext = SYMCRYPT_LOAD_MSBFIRST32( pbScratch+4 );
421
cbPad = (UINT32) cbSrc - cbPlaintext - SYMCRYPT_AES_SEMIBLOCK_SIZE;
422
mVerificationError |= (cbPad & 0xfffffff8);
423
424
// check that padding is all 0s
425
for( UINT32 i = 1; i<SYMCRYPT_AES_SEMIBLOCK_SIZE; i++ )
426
{
427
mIsPlaintext = SymCryptMask32LtU31(i, SYMCRYPT_AES_SEMIBLOCK_SIZE-(cbPad&7));
428
mVerificationError |= ((UINT32) pbScratch[ cbScratch-SYMCRYPT_AES_SEMIBLOCK_SIZE+i ]) & ~mIsPlaintext;
429
}
430
431
// Now if there was any verification error, we fail
432
if( mVerificationError != 0 )
433
{
434
scError = SYMCRYPT_AUTHENTICATION_FAILURE;
435
goto cleanup;
436
}
437
438
// We are variable time w.r.t. the plaintext length on success
439
if( cbDst < cbPlaintext )
440
{
441
scError = SYMCRYPT_BUFFER_TOO_SMALL;
442
goto cleanup;
443
}
444
445
// copy decrypted buffer to output
446
memcpy( pbDst, pbScratch+SYMCRYPT_AES_SEMIBLOCK_SIZE, cbPlaintext );
447
*pcbResult = cbPlaintext;
448
449
cleanup:
450
if( pbScratch != NULL )
451
{
452
SymCryptWipe( pbScratch, cbScratch );
453
SymCryptCallbackFree( pbScratch );
454
}
455
return scError;
456
457
}
458
459