Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/blockciphermodes.c
15010 views
1
//
2
// BlockCipherModes.c generic implementation of all block cipher modes
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
#include "precomp.h"
8
9
VOID
10
SYMCRYPT_CALL
11
SymCryptEcbEncrypt(
12
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
13
_In_ PCVOID pExpandedKey,
14
_In_reads_( cbData ) PCBYTE pbSrc,
15
_Out_writes_( cbData ) PBYTE pbDst,
16
SIZE_T cbData )
17
{
18
SIZE_T i;
19
SIZE_T cbToDo = cbData & ~(pBlockCipher->blockSize - 1);
20
21
if( pBlockCipher->ecbEncryptFunc != NULL )
22
{
23
//
24
// Use optimized implementation if available
25
//
26
(*pBlockCipher->ecbEncryptFunc)( pExpandedKey, pbSrc, pbDst, cbData );
27
return;
28
}
29
30
//
31
// To avoid buffer overruns we truncate the work to an integral number of blocks.
32
//
33
34
for( i=0; i<cbToDo; i+= pBlockCipher->blockSize )
35
{
36
(*pBlockCipher->encryptFunc)( pExpandedKey, pbSrc + i, pbDst + i );
37
}
38
}
39
40
VOID
41
SYMCRYPT_CALL
42
SymCryptEcbDecrypt(
43
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
44
_In_ PCVOID pExpandedKey,
45
_In_reads_( cbData ) PCBYTE pbSrc,
46
_Out_writes_( cbData ) PBYTE pbDst,
47
SIZE_T cbData )
48
{
49
SIZE_T i;
50
SIZE_T cbToDo = cbData & ~(pBlockCipher->blockSize - 1);
51
52
if( pBlockCipher->ecbDecryptFunc != NULL )
53
{
54
//
55
// Use optimized implementation if available
56
//
57
(*pBlockCipher->ecbDecryptFunc)( pExpandedKey, pbSrc, pbDst, cbData );
58
return;
59
}
60
61
for( i=0; i<cbToDo; i+= pBlockCipher->blockSize )
62
{
63
(*pBlockCipher->decryptFunc)( pExpandedKey, pbSrc + i, pbDst + i );
64
}
65
}
66
67
68
//
69
// SymCryptCbcEncrypt
70
//
71
// Generic CBC encryption routine for block ciphers.
72
// The following restrictions must be obeyed:
73
// - blockSize <= 32 and must be a power of 2
74
// - cbData must be a multiple of the block size
75
//
76
VOID
77
SYMCRYPT_CALL
78
SymCryptCbcEncrypt(
79
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
80
_In_ PCVOID pExpandedKey,
81
_Inout_updates_( pBlockCipher->blockSize )
82
PBYTE pbChainingValue,
83
_In_reads_( cbData ) PCBYTE pbSrc,
84
_Out_writes_( cbData ) PBYTE pbDst,
85
SIZE_T cbData )
86
{
87
SYMCRYPT_ALIGN BYTE buf[SYMCRYPT_MAX_BLOCK_SIZE];
88
SIZE_T blockSize;
89
PCBYTE pbSrcEnd;
90
PCBYTE pSrc = pbSrc;
91
PBYTE pDst = pbDst;
92
93
if( pBlockCipher->cbcEncryptFunc != NULL )
94
{
95
//
96
// Use optimized implementation if available
97
//
98
(*pBlockCipher->cbcEncryptFunc)( pExpandedKey, pbChainingValue, pSrc, pDst, cbData );
99
return;
100
}
101
102
blockSize = pBlockCipher->blockSize;
103
104
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
105
106
107
//
108
// Compute the end of the data, rounding the size down to a multiple of the block size.
109
//
110
pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ];
111
112
//
113
// We keep the chaining state in a local buffer to enforce the read-once write-once rule.
114
//
115
memcpy( buf, pbChainingValue, blockSize );
116
while( pSrc < pbSrcEnd )
117
{
118
SYMCRYPT_ASSERT( pSrc <= pbSrc + cbData - blockSize ); // help PreFast
119
SYMCRYPT_ASSERT( pDst <= pbDst + cbData - blockSize ); // help PreFast
120
SYMCRYPT_ASSERT( blockSize <= cbData ); // help PreFast
121
SymCryptXorBytes( pSrc, buf, buf, blockSize );
122
(*pBlockCipher->encryptFunc)( pExpandedKey, buf, buf );
123
memcpy( pDst, buf, blockSize );
124
pSrc += blockSize;
125
pDst += blockSize;
126
}
127
128
memcpy( pbChainingValue, buf, blockSize );
129
130
SymCryptWipeKnownSize( buf, sizeof( buf ));
131
}
132
133
//
134
// SymCryptCbcDecrypt
135
//
136
// Generic CBC decryption routine for block ciphers.
137
// The following restrictions must be obeyed:
138
// - blockSize <= 32 and must be a power of 2
139
// - cbData must be a multiple of the block size
140
//
141
VOID
142
SYMCRYPT_CALL
143
SymCryptCbcDecrypt(
144
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
145
_In_ PCVOID pExpandedKey,
146
_Inout_updates_( pBlockCipher->blockSize )
147
PBYTE pbChainingValue,
148
_In_reads_( cbData ) PCBYTE pbSrc,
149
_Out_writes_( cbData ) PBYTE pbDst,
150
SIZE_T cbData )
151
{
152
SYMCRYPT_ALIGN BYTE buf[3 * SYMCRYPT_MAX_BLOCK_SIZE];
153
PBYTE chain = &buf[0];
154
PBYTE ciphertext = &buf[SYMCRYPT_MAX_BLOCK_SIZE];
155
PBYTE tmp = &buf[2*SYMCRYPT_MAX_BLOCK_SIZE];
156
157
SIZE_T blockSize;
158
PCBYTE pbSrcEnd;
159
160
if( pBlockCipher->cbcDecryptFunc != NULL )
161
{
162
(*pBlockCipher->cbcDecryptFunc)( pExpandedKey, pbChainingValue, pbSrc, pbDst, cbData );
163
return;
164
}
165
166
blockSize = pBlockCipher->blockSize;
167
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
168
169
//
170
// Compute the end of the data, rounding the size down to a multiple of the block size.
171
//
172
pbSrcEnd = &pbSrc[ cbData & ~(blockSize-1) ];
173
174
#pragma warning(suppress: 22105)
175
memcpy( chain, pbChainingValue, blockSize );
176
177
//
178
// Loop structured to obey the read-once/write-once rule
179
//
180
while( pbSrc < pbSrcEnd )
181
{
182
SYMCRYPT_ASSERT( pbSrc <= pbSrcEnd - blockSize ); // help PreFast
183
memcpy( ciphertext, pbSrc, blockSize );
184
(*pBlockCipher->decryptFunc)( pExpandedKey, ciphertext, tmp );
185
SymCryptXorBytes( tmp, chain, pbDst, blockSize );
186
memcpy( chain, ciphertext, blockSize );
187
pbDst += blockSize;
188
pbSrc += blockSize;
189
}
190
191
memcpy( pbChainingValue, chain, blockSize );
192
193
SymCryptWipeKnownSize( buf, sizeof( buf ));
194
}
195
196
VOID
197
SYMCRYPT_CALL
198
SymCryptCbcMac(
199
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
200
_In_ PCVOID pExpandedKey,
201
_Inout_updates_( pBlockCipher->blockSize )
202
PBYTE pbChainingValue,
203
_In_reads_( cbData ) PCBYTE pbSrc,
204
SIZE_T cbData )
205
{
206
SYMCRYPT_ALIGN BYTE buf[32];
207
SIZE_T blockSize;
208
PCBYTE pbSrcEnd;
209
PCBYTE p;
210
211
if( pBlockCipher->cbcMacFunc != NULL )
212
{
213
//
214
// Use optimized implementation if available
215
//
216
(*pBlockCipher->cbcMacFunc)( pExpandedKey, pbChainingValue, pbSrc, cbData );
217
return;
218
}
219
220
blockSize = pBlockCipher->blockSize;
221
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
222
223
//
224
// Compute the end of the data, rounding the size down to a multiple of the block size.
225
//
226
pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ];
227
228
//
229
// We keep the chaining state in a local buffer to enforce the read-once write-once rule.
230
// It also improves memory locality.
231
//
232
memcpy( buf, pbChainingValue, blockSize );
233
p = pbSrc;
234
while( p < pbSrcEnd )
235
{
236
SYMCRYPT_ASSERT( p <= pbSrc + cbData - blockSize );
237
SymCryptXorBytes( p, buf, buf, blockSize );
238
(*pBlockCipher->encryptFunc)( pExpandedKey, buf, buf );
239
p += blockSize;
240
}
241
242
memcpy( pbChainingValue, buf, blockSize );
243
244
SymCryptWipeKnownSize( buf, sizeof( buf ));
245
}
246
247
VOID
248
SYMCRYPT_CALL
249
SymCryptCtrMsb32(
250
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
251
_In_ PCVOID pExpandedKey,
252
_Inout_updates_( pBlockCipher->blockSize )
253
PBYTE pbChainingValue,
254
_In_reads_( cbData ) PCBYTE pbSrc,
255
_Out_writes_( cbData ) PBYTE pbDst,
256
SIZE_T cbData )
257
{
258
SYMCRYPT_ALIGN BYTE buf[2 * SYMCRYPT_MAX_BLOCK_SIZE];
259
PBYTE count = &buf[0];
260
PBYTE keystream= &buf[SYMCRYPT_MAX_BLOCK_SIZE];
261
SIZE_T blockSize;
262
PCBYTE pbSrcEnd;
263
264
blockSize = pBlockCipher->blockSize;
265
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
266
267
//
268
// Compute the end of the data, rounding the size down to a multiple of the block size.
269
//
270
pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ];
271
272
//
273
// We keep the chaining state in a local buffer to enforce the read-once write-once rule.
274
// It also improves memory locality.
275
//
276
#pragma warning(suppress: 22105)
277
memcpy( count, pbChainingValue, blockSize );
278
while( pbSrc < pbSrcEnd )
279
{
280
SYMCRYPT_ASSERT( pbSrc <= pbSrcEnd - blockSize ); // help PreFast
281
(*pBlockCipher->encryptFunc)( pExpandedKey, count, keystream );
282
SymCryptXorBytes( keystream, pbSrc, pbDst, blockSize );
283
284
//
285
// We only need to increment the last 32 bits of the counter value.
286
//
287
SYMCRYPT_STORE_MSBFIRST32( &count[ blockSize-4 ], 1 + SYMCRYPT_LOAD_MSBFIRST32( &count[ blockSize-4 ] ) );
288
289
pbSrc += blockSize;
290
pbDst += blockSize;
291
}
292
293
memcpy( pbChainingValue, count, blockSize );
294
295
SymCryptWipeKnownSize( buf, sizeof( buf ));
296
}
297
298
VOID
299
SYMCRYPT_CALL
300
SymCryptCtrMsb64(
301
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
302
_In_ PCVOID pExpandedKey,
303
_Inout_updates_( pBlockCipher->blockSize )
304
PBYTE pbChainingValue,
305
_In_reads_( cbData ) PCBYTE pbSrc,
306
_Out_writes_( cbData ) PBYTE pbDst,
307
SIZE_T cbData )
308
{
309
SYMCRYPT_ALIGN BYTE buf[2 * SYMCRYPT_MAX_BLOCK_SIZE];
310
PBYTE count = &buf[0];
311
PBYTE keystream= &buf[SYMCRYPT_MAX_BLOCK_SIZE];
312
SIZE_T blockSize;
313
PCBYTE pbSrcEnd;
314
315
if( pBlockCipher->ctrMsb64Func != NULL )
316
{
317
//
318
// Use optimized implementation if available
319
//
320
(*pBlockCipher->ctrMsb64Func)( pExpandedKey, pbChainingValue, pbSrc, pbDst, cbData );
321
return;
322
}
323
324
blockSize = pBlockCipher->blockSize;
325
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
326
327
//
328
// Compute the end of the data, rounding the size down to a multiple of the block size.
329
//
330
pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ];
331
332
//
333
// We keep the chaining state in a local buffer to enforce the read-once write-once rule.
334
// It also improves memory locality.
335
//
336
#pragma warning(suppress: 22105)
337
memcpy( count, pbChainingValue, blockSize );
338
while( pbSrc < pbSrcEnd )
339
{
340
SYMCRYPT_ASSERT( pbSrc <= pbSrcEnd - blockSize ); // help PreFast
341
(*pBlockCipher->encryptFunc)( pExpandedKey, count, keystream );
342
SymCryptXorBytes( keystream, pbSrc, pbDst, blockSize );
343
344
//
345
// We only need to increment the last 64 bits of the counter value.
346
//
347
SYMCRYPT_STORE_MSBFIRST64( &count[ blockSize-8 ], 1 + SYMCRYPT_LOAD_MSBFIRST64( &count[ blockSize-8 ] ) );
348
349
pbSrc += blockSize;
350
pbDst += blockSize;
351
}
352
353
memcpy( pbChainingValue, count, blockSize );
354
355
SymCryptWipeKnownSize( buf, sizeof( buf ));
356
}
357
358
VOID
359
SYMCRYPT_CALL
360
SymCryptCfbEncrypt(
361
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
362
SIZE_T cbShift,
363
_In_ PCVOID pExpandedKey,
364
_Inout_updates_( pBlockCipher->blockSize )
365
PBYTE pbChainingValue,
366
_In_reads_( cbData ) PCBYTE pbSrc,
367
_Out_writes_( cbData ) PBYTE pbDst,
368
SIZE_T cbData )
369
//
370
// Encrypt a buffer using the CFB cipher mode.
371
//
372
// This implements the CFB mode using a 1-byte feedback shift.
373
// This requires a block cipher encryption call for each byte, which is very slow.
374
// Use of this cipher mode is not recommended.
375
//
376
// - pBlockCipher is a pointer to the block cipher description table.
377
// Suitable description tables for all ciphers in this library have been pre-defined.
378
// - pExpandedKey points to the expanded key to use. This generic function uses PVOID so there
379
// is no type safety to ensure that the expanded key and the encryption function match.
380
// - pbChainingValue points to the chaining value. On entry and exit it
381
// contains the last blockSize ciphertext bytes.
382
// - pbSrc is the input data buffer that will be encrypted/decrypted.
383
// - cbData. Number of bytes to encrypt/decrypt. This must be a multiple of the block size.
384
// - pbDst is the output buffer that receives the encrypted/decrypted data. The input and output
385
// buffers may be the same or non-overlapping, but may not partially overlap.
386
//
387
{
388
SYMCRYPT_ALIGN BYTE buf[2*SYMCRYPT_MAX_BLOCK_SIZE];
389
PBYTE chain = &buf[0];
390
PBYTE tmp = &buf[SYMCRYPT_MAX_BLOCK_SIZE];
391
SIZE_T blockSize;
392
393
blockSize = pBlockCipher->blockSize;
394
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
395
396
// Force cbShift to either be 1 or blockSize
397
if(cbShift != 1)
398
{
399
cbShift = blockSize;
400
}
401
402
memcpy( chain, pbChainingValue, blockSize );
403
while( cbData >= cbShift )
404
{
405
(*pBlockCipher->encryptFunc)( pExpandedKey, chain, tmp );
406
SymCryptXorBytes( pbSrc, tmp, tmp, cbShift ); // tmp[0..cbShift-1] ^= pbSrc[0..cbShift-1]
407
memcpy( pbDst, tmp, cbShift );
408
409
memmove( chain, chain + cbShift, blockSize - cbShift );
410
memcpy( chain + blockSize - cbShift, tmp, cbShift );
411
412
pbDst += cbShift;
413
pbSrc += cbShift;
414
cbData -= cbShift;
415
}
416
417
memcpy( pbChainingValue, chain, blockSize );
418
}
419
420
421
VOID
422
SYMCRYPT_CALL
423
SymCryptCfbDecrypt(
424
_In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher,
425
SIZE_T cbShift,
426
_In_ PCVOID pExpandedKey,
427
_Inout_updates_( pBlockCipher->blockSize )
428
PBYTE pbChainingValue,
429
_In_reads_( cbData ) PCBYTE pbSrc,
430
_Out_writes_( cbData ) PBYTE pbDst,
431
SIZE_T cbData )
432
{
433
SYMCRYPT_ALIGN BYTE buf[2*SYMCRYPT_MAX_BLOCK_SIZE];
434
PBYTE chain = &buf[0];
435
PBYTE tmp = &buf[SYMCRYPT_MAX_BLOCK_SIZE];
436
SIZE_T blockSize;
437
438
blockSize = pBlockCipher->blockSize;
439
SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE );
440
441
// Force cbShift to either be 1 or blockSize
442
if(cbShift != 1)
443
{
444
cbShift = blockSize;
445
}
446
447
memcpy( chain, pbChainingValue, blockSize );
448
while( cbData >= cbShift )
449
{
450
(*pBlockCipher->encryptFunc)( pExpandedKey, chain, tmp );
451
452
//
453
// First we update the chain block
454
//
455
456
memmove( chain, chain + cbShift, blockSize - cbShift );
457
memcpy( chain + blockSize - cbShift, pbSrc, cbShift );
458
459
//
460
// To obey the read-once rule, we take the ciphertext from the updated chain block.
461
//
462
SymCryptXorBytes( chain + blockSize - cbShift, tmp, pbDst, cbShift );
463
464
pbDst += cbShift;
465
pbSrc += cbShift;
466
cbData -= cbShift;
467
}
468
469
memcpy( pbChainingValue, chain, blockSize );
470
}
471
472