Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/eckey.c
15010 views
1
//
2
// eckey.c Functions for the ECKEY object
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
PSYMCRYPT_ECKEY
11
SYMCRYPT_CALL
12
SymCryptEckeyAllocate( _In_ PCSYMCRYPT_ECURVE pCurve )
13
{
14
PVOID p;
15
SIZE_T cb;
16
PSYMCRYPT_ECKEY res = NULL;
17
18
cb = SymCryptSizeofEckeyFromCurve( pCurve );
19
20
p = SymCryptCallbackAlloc( cb );
21
22
if ( p==NULL )
23
{
24
goto cleanup;
25
}
26
27
res = SymCryptEckeyCreate( p, cb, pCurve );
28
29
cleanup:
30
return res;
31
}
32
33
VOID
34
SYMCRYPT_CALL
35
SymCryptEckeyFree( _Out_ PSYMCRYPT_ECKEY pkObj )
36
{
37
SYMCRYPT_CHECK_MAGIC( pkObj );
38
SymCryptEckeyWipe( pkObj );
39
SymCryptCallbackFree( pkObj );
40
}
41
42
UINT32
43
SYMCRYPT_CALL
44
SymCryptSizeofEckeyFromCurve( _In_ PCSYMCRYPT_ECURVE pCurve )
45
{
46
//
47
// From symcrypt_internal.h we have:
48
// - sizeof results are upper bounded by 2^19
49
// - SYMCRYPT_SCRATCH_BYTES results are upper bounded by 2^27 (including RSA and ECURVE)
50
// - SymCryptSizeofEcpointFromCurve outputs the size of up to 4 modelements + some overhead
51
// Thus the following calculation does not overflow the result.
52
//
53
return sizeof(SYMCRYPT_ECKEY) + SymCryptSizeofEcpointFromCurve( pCurve ) + SymCryptSizeofIntFromDigits(SymCryptEcurveDigitsofScalarMultiplier(pCurve));
54
}
55
56
PSYMCRYPT_ECKEY
57
SYMCRYPT_CALL
58
SymCryptEckeyCreate(
59
_Out_writes_bytes_( cbBuffer ) PBYTE pbBuffer,
60
SIZE_T cbBuffer,
61
PCSYMCRYPT_ECURVE pCurve )
62
{
63
PSYMCRYPT_ECKEY pkObj = NULL;
64
UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
65
66
SIZE_T cbPublicKey = SymCryptSizeofEcpointFromCurve( pCurve );
67
SIZE_T cbPrivateKey = SymCryptSizeofIntFromDigits( privateKeyDigits );
68
69
UNREFERENCED_PARAMETER( cbBuffer ); // only referenced in ASSERTs...
70
71
SYMCRYPT_ASSERT( pCurve != NULL );
72
SYMCRYPT_ASSERT( cbBuffer >= SymCryptSizeofEckeyFromCurve( pCurve ) );
73
74
SYMCRYPT_ASSERT( cbBuffer >= sizeof(SYMCRYPT_ECKEY) +
75
cbPublicKey +
76
cbPrivateKey );
77
78
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
79
80
pkObj = (PSYMCRYPT_ECKEY) pbBuffer;
81
82
pkObj->fAlgorithmInfo = 0;
83
pkObj->hasPrivateKey = FALSE;
84
pkObj->pCurve = pCurve;
85
86
pkObj->poPublicKey = SymCryptEcpointCreate(
87
pbBuffer + sizeof(SYMCRYPT_ECKEY),
88
cbPublicKey,
89
pCurve );
90
SYMCRYPT_ASSERT( pkObj->poPublicKey != NULL );
91
92
pkObj->piPrivateKey = SymCryptIntCreate(
93
pbBuffer + sizeof(SYMCRYPT_ECKEY) + cbPublicKey,
94
cbPrivateKey,
95
privateKeyDigits );
96
SYMCRYPT_ASSERT( pkObj->piPrivateKey );
97
98
// Setting the magic
99
SYMCRYPT_SET_MAGIC( pkObj );
100
101
return pkObj;
102
}
103
104
VOID
105
SYMCRYPT_CALL
106
SymCryptEckeyWipePrivateState(
107
_Inout_ PSYMCRYPT_ECKEY pkEckey )
108
{
109
SymCryptIntSetValueUint32( 0, pkEckey->piPrivateKey );
110
pkEckey->hasPrivateKey = FALSE;
111
}
112
113
VOID
114
SYMCRYPT_CALL
115
SymCryptEckeyWipe( _Out_ PSYMCRYPT_ECKEY pkDst )
116
{
117
// Wipe the whole structure in one go.
118
SymCryptWipe( pkDst, SymCryptSizeofEckeyFromCurve( pkDst->pCurve ) );
119
}
120
121
VOID
122
SymCryptEckeyCopy(
123
_In_ PCSYMCRYPT_ECKEY pkSrc,
124
_Out_ PSYMCRYPT_ECKEY pkDst )
125
{
126
//
127
// in-place copy is somewhat common...
128
//
129
if( pkSrc != pkDst )
130
{
131
// Copy the fAlgorithmInfo flags
132
pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo;
133
134
// Copy the hasPrivateKey flag
135
pkDst->hasPrivateKey = pkSrc->hasPrivateKey;
136
137
// Copy the public key
138
SymCryptEcpointCopy( pkSrc->pCurve, pkSrc->poPublicKey, pkDst->poPublicKey );
139
140
// Copy the private key
141
SymCryptIntCopy( pkSrc->piPrivateKey, pkDst->piPrivateKey );
142
}
143
}
144
145
UINT32
146
SYMCRYPT_CALL
147
SymCryptEckeySizeofPublicKey(
148
_In_ PCSYMCRYPT_ECKEY pkEckey,
149
_In_ SYMCRYPT_ECPOINT_FORMAT ecPointFormat )
150
{
151
//
152
// From symcrypt_internal.h we have:
153
// - sizeof results are upper bounded by 2^19
154
// - SYMCRYPT_SCRATCH_BYTES results are upper bounded by 2^27 (including RSA and ECURVE)
155
// - SymCryptEcpointFormatNumberofElements returns up to 4 elements.
156
//
157
// Thus the following calculation does not overflow cbScratch.
158
//
159
return SymCryptEcpointFormatNumberofElements[ecPointFormat] * SymCryptEcurveSizeofFieldElement( pkEckey->pCurve );
160
}
161
162
UINT32
163
SYMCRYPT_CALL
164
SymCryptEckeySizeofPrivateKey( _In_ PCSYMCRYPT_ECKEY pkEckey )
165
{
166
return SymCryptEcurveSizeofScalarMultiplier( pkEckey->pCurve );
167
}
168
169
BOOLEAN
170
SYMCRYPT_CALL
171
SymCryptEckeyHasPrivateKey( _In_ PCSYMCRYPT_ECKEY pkEckey )
172
{
173
return pkEckey->hasPrivateKey;
174
}
175
176
#define SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION (0x1)
177
178
SYMCRYPT_ERROR
179
SYMCRYPT_CALL
180
SymCryptEckeyPerformPublicKeyValidation(
181
_In_ PCSYMCRYPT_ECKEY pEckey,
182
_In_ UINT32 flags,
183
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
184
SIZE_T cbScratch )
185
{
186
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
187
188
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
189
190
PSYMCRYPT_ECPOINT poNPub = NULL;
191
UINT32 cbNPub = SymCryptSizeofEcpointFromCurve( pCurve );
192
193
// This is an excessive amount of space to require, but all callers can currently provide it, and it's easy to phrase
194
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve ) );
195
196
SYMCRYPT_ASSERT( cbScratch >= cbNPub );
197
198
// Check if Public key is O
199
if ( SymCryptEcpointIsZero( pCurve, pEckey->poPublicKey, pbScratch, cbScratch ) )
200
{
201
return SYMCRYPT_INVALID_ARGUMENT;
202
}
203
204
// Public key is represented by Modelements of the underlying finite field for the curve
205
// If we have reached this point we have either:
206
// Constructed the Public key to have coordinates in the field (Generate case), or
207
// Verified the Public key has coordinates in the field (SetValue case)
208
209
// Check that Public key is on the curve
210
// Skip check for Montgomery curves as we do not have an EcpointOnCurve function for them
211
if ( !SYMCRYPT_CURVE_IS_MONTGOMERY_TYPE(pCurve) &&
212
!SymCryptEcpointOnCurve( pCurve, pEckey->poPublicKey, pbScratch, cbScratch ) )
213
{
214
return SYMCRYPT_INVALID_ARGUMENT;
215
}
216
217
// Perform validation that Public key is in a subgroup of order GOrd.
218
if ( (flags & SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION) != 0 )
219
{
220
if ( SymCryptIntIsEqualUint32( pCurve->H, 1 ) )
221
{
222
// If cofactor is 1 then to validate that Public key has order GOrd
223
// it is sufficient to validate Public key is on the curve
224
// We just performed this check - so we are done.
225
}
226
else
227
{
228
// Ensure GOrd*(Public key) == O
229
poNPub = SymCryptEcpointCreate( pbScratch, cbNPub, pCurve );
230
pbScratch += cbNPub;
231
cbScratch -= cbNPub;
232
233
SYMCRYPT_ASSERT( poNPub != NULL );
234
235
// Do the multiplication
236
scError = SymCryptEcpointScalarMul(
237
pCurve,
238
SymCryptIntFromModulus( pCurve->GOrd ),
239
pEckey->poPublicKey,
240
0, // Do not multiply by cofactor!
241
poNPub,
242
pbScratch,
243
cbScratch );
244
if ( scError != SYMCRYPT_NO_ERROR )
245
{
246
return scError;
247
}
248
249
if ( !SymCryptEcpointIsZero( pCurve, poNPub, pbScratch, cbScratch ) )
250
{
251
return SYMCRYPT_INVALID_ARGUMENT;
252
}
253
}
254
}
255
256
return SYMCRYPT_NO_ERROR;
257
}
258
259
SYMCRYPT_ERROR
260
SYMCRYPT_CALL
261
SymCryptEckeySetValue(
262
_In_reads_bytes_( cbPrivateKey )
263
PCBYTE pbPrivateKey,
264
SIZE_T cbPrivateKey,
265
_In_reads_bytes_( cbPublicKey )
266
PCBYTE pbPublicKey,
267
SIZE_T cbPublicKey,
268
SYMCRYPT_NUMBER_FORMAT numFormat,
269
SYMCRYPT_ECPOINT_FORMAT ecPointFormat,
270
UINT32 flags,
271
_Inout_ PSYMCRYPT_ECKEY pEckey )
272
{
273
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
274
PBYTE pbScratch = NULL;
275
UINT32 cbScratch = 0;
276
PBYTE pbScratchInternal = NULL;
277
UINT32 cbScratchInternal = 0;
278
279
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
280
281
PSYMCRYPT_ECPOINT poTmp = NULL;
282
UINT32 cbTmp = 0;
283
284
PSYMCRYPT_INT piTmpInteger = NULL;
285
UINT32 cbTmpInteger = 0;
286
PSYMCRYPT_MODELEMENT peTmpModElement = NULL;
287
UINT32 cbTmpModElement = pCurve->cbModElement;
288
289
UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
290
291
UINT32 fValidatePublicKeyOrder = SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION;
292
293
// Ensure caller has specified what algorithm(s) the key will be used with
294
UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH;
295
// Make sure only allowed flags are specified
296
UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | algorithmFlags;
297
298
if ( ( ( flags & ~allowedFlags ) != 0 ) ||
299
( ( flags & algorithmFlags ) == 0 ) )
300
{
301
scError = SYMCRYPT_INVALID_ARGUMENT;
302
goto cleanup;
303
}
304
305
// Check that minimal validation flag only specified with no fips
306
if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
307
( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) != 0 ) )
308
{
309
scError = SYMCRYPT_INVALID_ARGUMENT;
310
goto cleanup;
311
}
312
313
if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) != 0 )
314
{
315
fValidatePublicKeyOrder = 0;
316
}
317
318
if ( ( ( cbPrivateKey == 0 ) && ( cbPublicKey == 0 ) ) ||
319
( ( cbPrivateKey != 0 ) && ( cbPrivateKey != SymCryptEcurveSizeofScalarMultiplier( pEckey->pCurve ) ) ) ||
320
( ( cbPublicKey != 0 ) && ( cbPublicKey != SymCryptEckeySizeofPublicKey( pEckey, ecPointFormat ) ) ) )
321
{
322
scError = SYMCRYPT_INVALID_ARGUMENT;
323
goto cleanup;
324
}
325
326
// Allocate scratch space
327
cbScratch = SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve );
328
pbScratch = SymCryptCallbackAlloc( cbScratch );
329
if ( pbScratch == NULL )
330
{
331
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
332
goto cleanup;
333
}
334
335
if ( pbPrivateKey != NULL )
336
{
337
//
338
// Private key calculations
339
//
340
341
pbScratchInternal = pbScratch;
342
cbScratchInternal = cbScratch;
343
344
// Allocate the integer
345
cbTmpInteger = SymCryptSizeofIntFromDigits( privateKeyDigits );
346
piTmpInteger = SymCryptIntCreate( pbScratchInternal, cbTmpInteger, privateKeyDigits );
347
SYMCRYPT_ASSERT( piTmpInteger != NULL );
348
349
pbScratchInternal += cbTmpInteger;
350
cbScratchInternal -= cbTmpInteger;
351
352
// Allocate the modelement
353
peTmpModElement = SymCryptModElementCreate( pbScratchInternal, cbTmpModElement, pCurve->GOrd );
354
SYMCRYPT_ASSERT( peTmpModElement != NULL );
355
356
pbScratchInternal += cbTmpModElement;
357
cbScratchInternal -= cbTmpModElement;
358
359
// Get the "raw" private key
360
scError = SymCryptIntSetValue( pbPrivateKey, cbPrivateKey, numFormat, piTmpInteger );
361
if (scError != SYMCRYPT_NO_ERROR)
362
{
363
goto cleanup;
364
}
365
366
// Validation steps
367
if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
368
{
369
// Perform range validation on imported Private key if it is in canonical format
370
if ( pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL )
371
{
372
// Check if Private key is greater than or equal to GOrd
373
if ( !SymCryptIntIsLessThan( piTmpInteger, SymCryptIntFromModulus( pCurve->GOrd ) ) )
374
{
375
scError = SYMCRYPT_INVALID_ARGUMENT;
376
goto cleanup;
377
}
378
}
379
380
// "TimesH" formats
381
// IntGetBits requirements:
382
// We know that coFactorPower is up to SYMCRYPT_ECURVE_MAX_COFACTOR_POWER. Thus
383
// less than 32 and less than the digits size in bits.
384
if ( (pCurve->coFactorPower>0) &&
385
(pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH) &&
386
(SymCryptIntGetBits( piTmpInteger, 0, pCurve->coFactorPower) != 0) )
387
{
388
scError = SYMCRYPT_INVALID_ARGUMENT;
389
goto cleanup;
390
}
391
392
393
// High bit restrictions
394
// IntGetBits requirements:
395
// Satisfied by asserting that
396
// HighBitRestrictionPosition + HighBitRestrictionNumOfBits <= GOrdBitsize + coFactorPower
397
// during EcurveAllocate.
398
if ( (pCurve->HighBitRestrictionNumOfBits>0) &&
399
(SymCryptIntGetBits(
400
piTmpInteger,
401
pCurve->HighBitRestrictionPosition,
402
pCurve->HighBitRestrictionNumOfBits) != pCurve->HighBitRestrictionValue) )
403
{
404
scError = SYMCRYPT_INVALID_ARGUMENT;
405
goto cleanup;
406
}
407
}
408
409
// Convert the private key to "DivH" format
410
if (pCurve->coFactorPower>0)
411
{
412
// "TimesH" format: Divide the input private key with the cofactor
413
// by shifting right the appropriate number of bits
414
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH)
415
{
416
SymCryptIntDivPow2( piTmpInteger, pCurve->coFactorPower, piTmpInteger );
417
}
418
419
// "Canonical" format: Divide by h modulo GOrd
420
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
421
{
422
SymCryptIntToModElement( piTmpInteger, pCurve->GOrd, peTmpModElement, pbScratchInternal, cbScratchInternal );
423
SymCryptModDivPow2( pCurve->GOrd, peTmpModElement, pCurve->coFactorPower, peTmpModElement, pbScratchInternal, cbScratchInternal );
424
SymCryptModElementToInt( pCurve->GOrd, peTmpModElement, piTmpInteger, pbScratchInternal, cbScratchInternal );
425
}
426
}
427
428
// Divide the input private key since it could be larger than subgroup order
429
SymCryptIntDivMod(
430
piTmpInteger,
431
SymCryptDivisorFromModulus(pCurve->GOrd),
432
NULL,
433
piTmpInteger,
434
pbScratchInternal,
435
cbScratchInternal );
436
437
// Check if Private key is 0 after dividing it by the subgroup order
438
// Other part of range validation - perform unconditionally as it is cheap
439
// and it never makes sense for private key to be 0 intentionally
440
if (SymCryptIntIsEqualUint32( piTmpInteger, 0 ))
441
{
442
scError = SYMCRYPT_INVALID_ARGUMENT;
443
goto cleanup;
444
}
445
446
// Copy into the ECKEY
447
SymCryptIntCopy( piTmpInteger, pEckey->piPrivateKey );
448
449
pEckey->hasPrivateKey = TRUE;
450
}
451
452
if ( pbPublicKey != NULL )
453
{
454
scError = SymCryptEcpointSetValue(
455
pCurve,
456
pbPublicKey,
457
cbPublicKey,
458
numFormat,
459
ecPointFormat,
460
pEckey->poPublicKey,
461
SYMCRYPT_FLAG_DATA_PUBLIC,
462
pbScratch,
463
cbScratch );
464
if ( scError != SYMCRYPT_NO_ERROR )
465
{
466
goto cleanup;
467
}
468
469
// Perform Public key validation on imported Public key.
470
if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
471
{
472
scError = SymCryptEckeyPerformPublicKeyValidation(
473
pEckey,
474
fValidatePublicKeyOrder,
475
pbScratch,
476
cbScratch );
477
if ( scError != SYMCRYPT_NO_ERROR )
478
{
479
goto cleanup;
480
}
481
}
482
}
483
484
// Calculating the public key if no key was provided
485
// or if needed for keypair regeneration validation
486
if ( (pbPublicKey==NULL) ||
487
( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
488
(pbPrivateKey!=NULL) && (pbPublicKey!=NULL) ) )
489
{
490
// Calculate the public key from the private key
491
pbScratchInternal = pbScratch;
492
cbScratchInternal = cbScratch;
493
494
// By default calculate the Public key directly where it will be persisted
495
poTmp = pEckey->poPublicKey;
496
497
if ( pbPublicKey != NULL )
498
{
499
// If doing regeneration validation calculate the Public key in scratch
500
cbTmp = SymCryptSizeofEcpointFromCurve( pCurve );
501
poTmp = SymCryptEcpointCreate( pbScratchInternal, cbTmp, pCurve );
502
pbScratchInternal += cbTmp;
503
cbScratchInternal -= cbTmp;
504
}
505
506
SYMCRYPT_ASSERT( poTmp != NULL );
507
508
// Always multiply by the cofactor since the internal format is "DIVH"
509
scError = SymCryptEcpointScalarMul(
510
pCurve,
511
pEckey->piPrivateKey,
512
NULL,
513
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
514
poTmp,
515
pbScratchInternal,
516
cbScratchInternal );
517
if ( scError != SYMCRYPT_NO_ERROR )
518
{
519
goto cleanup;
520
}
521
522
if ( pbPublicKey != NULL )
523
{
524
if ( !SymCryptEcpointIsEqual( pCurve, poTmp, pEckey->poPublicKey, 0, pbScratchInternal, cbScratchInternal ) )
525
{
526
scError = SYMCRYPT_INVALID_ARGUMENT;
527
goto cleanup;
528
}
529
}
530
else if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
531
{
532
// Perform Public key validation on generated Public key.
533
scError = SymCryptEckeyPerformPublicKeyValidation(
534
pEckey,
535
fValidatePublicKeyOrder,
536
pbScratch,
537
cbScratch );
538
if ( scError != SYMCRYPT_NO_ERROR )
539
{
540
goto cleanup;
541
}
542
}
543
}
544
545
pEckey->fAlgorithmInfo = flags; // We want to track all of the flags in the Eckey
546
547
if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 )
548
{
549
if ( ( flags & SYMCRYPT_FLAG_ECKEY_ECDSA ) != 0 )
550
{
551
// Ensure ECDSA algorithm selftest is run before first use of ECDSA algorithm
552
SYMCRYPT_RUN_SELFTEST_ONCE(
553
SymCryptEcDsaSelftest,
554
SYMCRYPT_SELFTEST_ALGORITHM_ECDSA );
555
556
// PCT does not need to be run on import - mark it as done
557
pEckey->fAlgorithmInfo |= SYMCRYPT_PCT_ECDSA;
558
}
559
560
if ( ( flags & SYMCRYPT_FLAG_ECKEY_ECDH ) != 0 )
561
{
562
SYMCRYPT_RUN_SELFTEST_ONCE(
563
SymCryptEcDhSecretAgreementSelftest,
564
SYMCRYPT_SELFTEST_ALGORITHM_ECDH );
565
}
566
}
567
568
cleanup:
569
570
if ( pbScratch != NULL )
571
{
572
SymCryptWipe( pbScratch, cbScratch );
573
SymCryptCallbackFree( pbScratch );
574
}
575
576
return scError;
577
}
578
579
SYMCRYPT_ERROR
580
SYMCRYPT_CALL
581
SymCryptEckeyGetValue(
582
_In_ PCSYMCRYPT_ECKEY pEckey,
583
_Out_writes_bytes_( cbPrivateKey )
584
PBYTE pbPrivateKey,
585
SIZE_T cbPrivateKey,
586
_Out_writes_bytes_( cbPublicKey )
587
PBYTE pbPublicKey,
588
SIZE_T cbPublicKey,
589
SYMCRYPT_NUMBER_FORMAT numFormat,
590
SYMCRYPT_ECPOINT_FORMAT ecPointFormat,
591
UINT32 flags )
592
{
593
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
594
PBYTE pbScratch = NULL;
595
UINT32 cbScratch = 0;
596
PBYTE pbScratchInternal = NULL;
597
UINT32 cbScratchInternal = 0;
598
599
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
600
601
PSYMCRYPT_INT piTmpInteger = NULL;
602
UINT32 cbTmpInteger = 0;
603
PSYMCRYPT_MODELEMENT peTmpModElement = NULL;
604
UINT32 cbTmpModElement = pCurve->cbModElement;
605
606
UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
607
608
SYMCRYPT_ASSERT( (cbPrivateKey==0) || (cbPrivateKey == SymCryptEcurveSizeofScalarMultiplier( pEckey->pCurve )) );
609
SYMCRYPT_ASSERT( (cbPublicKey==0) || (cbPublicKey == SymCryptEckeySizeofPublicKey( pEckey, ecPointFormat)) );
610
611
// Make sure we only specify the correct flags
612
if (flags != 0)
613
{
614
scError = SYMCRYPT_INVALID_ARGUMENT;
615
goto cleanup;
616
}
617
618
// Allocate scratch space
619
cbScratch = SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve );
620
pbScratch = SymCryptCallbackAlloc( cbScratch );
621
if ( pbScratch == NULL )
622
{
623
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
624
goto cleanup;
625
}
626
627
pbScratchInternal = pbScratch;
628
cbScratchInternal = cbScratch;
629
630
// Allocate the integer
631
cbTmpInteger = SymCryptSizeofIntFromDigits( privateKeyDigits );
632
piTmpInteger = SymCryptIntCreate( pbScratchInternal, cbTmpInteger, privateKeyDigits );
633
SYMCRYPT_ASSERT( piTmpInteger != NULL );
634
635
pbScratchInternal += cbTmpInteger;
636
cbScratchInternal -= cbTmpInteger;
637
638
// Allocate the modelement
639
peTmpModElement = SymCryptModElementCreate( pbScratchInternal, cbTmpModElement, pCurve->GOrd );
640
SYMCRYPT_ASSERT( peTmpModElement != NULL );
641
642
pbScratchInternal += cbTmpModElement;
643
cbScratchInternal -= cbTmpModElement;
644
645
if ((cbPrivateKey == 0) && (cbPublicKey == 0))
646
{
647
scError = SYMCRYPT_INVALID_ARGUMENT;
648
goto cleanup;
649
}
650
651
if (cbPrivateKey != 0)
652
{
653
if (!pEckey->hasPrivateKey)
654
{
655
scError = SYMCRYPT_INVALID_BLOB;
656
goto cleanup;
657
}
658
659
// If this keypair may be used in ECDSA, and does not have the no FIPS flag, run the PCT if
660
// it has not already been run
661
if ( ((pEckey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) != 0) &&
662
((pEckey->fAlgorithmInfo & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0) )
663
{
664
SYMCRYPT_RUN_KEY_GEN_PCT(
665
SymCryptEcDsaPct,
666
pEckey,
667
SYMCRYPT_PCT_ECDSA );
668
}
669
670
// Copy the key into the temporary integer
671
SymCryptIntCopy( pEckey->piPrivateKey, piTmpInteger );
672
673
// Convert the "DivH" format into the external format
674
if (pCurve->coFactorPower>0)
675
{
676
// For the "Canonical" format: Multiply the integer by h
677
// and then take the result modulo GOrd
678
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
679
{
680
SymCryptIntMulPow2( piTmpInteger, pCurve->coFactorPower, piTmpInteger );
681
SymCryptIntDivMod(
682
piTmpInteger,
683
SymCryptDivisorFromModulus(pCurve->GOrd),
684
NULL,
685
piTmpInteger,
686
pbScratchInternal,
687
cbScratchInternal );
688
}
689
690
// For the "TimesH" format: Multiply the integer by h again by shifting
691
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH)
692
{
693
SymCryptIntMulPow2( piTmpInteger, pCurve->coFactorPower, piTmpInteger );
694
}
695
}
696
697
scError = SymCryptIntGetValue( piTmpInteger, pbPrivateKey, cbPrivateKey, numFormat );
698
if (scError != SYMCRYPT_NO_ERROR)
699
{
700
goto cleanup;
701
}
702
}
703
704
if (cbPublicKey != 0)
705
{
706
scError = SymCryptEcpointGetValue(
707
pCurve,
708
pEckey->poPublicKey,
709
numFormat,
710
ecPointFormat,
711
pbPublicKey,
712
cbPublicKey,
713
SYMCRYPT_FLAG_DATA_PUBLIC,
714
pbScratch,
715
cbScratch );
716
}
717
718
cleanup:
719
720
if ( pbScratch != NULL )
721
{
722
SymCryptWipe( pbScratch, cbScratch );
723
SymCryptCallbackFree( pbScratch );
724
}
725
726
return scError;
727
}
728
729
#define SYMCRYPT_ECPOINT_SET_RANDOM_MAX_TRIES (1000)
730
731
SYMCRYPT_ERROR
732
SYMCRYPT_CALL
733
SymCryptEckeySetRandom(
734
_In_ UINT32 flags,
735
_Inout_ PSYMCRYPT_ECKEY pEckey )
736
{
737
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
738
PBYTE pbScratch = NULL;
739
UINT32 cbScratch = 0;
740
PBYTE pbScratchInternal = NULL;
741
UINT32 cbScratchInternal = 0;
742
743
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
744
745
PSYMCRYPT_ECPOINT poTmp = NULL;
746
UINT32 cbTmp = 0;
747
748
INT32 cntr = SYMCRYPT_ECPOINT_SET_RANDOM_MAX_TRIES;
749
750
PSYMCRYPT_MODELEMENT peScalar = NULL;
751
PSYMCRYPT_INT piScalar = NULL;
752
UINT32 cbScalar = 0;
753
754
UINT32 highBitRestrictionPosition = pCurve->HighBitRestrictionPosition;
755
756
// Ensure caller has specified what algorithm(s) the key will be used with
757
UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH;
758
// Make sure only allowed flags are specified
759
UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags;
760
761
if ( ( ( flags & ~allowedFlags ) != 0 ) ||
762
( ( flags & algorithmFlags ) == 0 ) )
763
{
764
scError = SYMCRYPT_INVALID_ARGUMENT;
765
goto cleanup;
766
}
767
768
//
769
// From symcrypt_internal.h we have:
770
// - sizeof results are upper bounded by 2^19
771
// - SYMCRYPT_SCRATCH_BYTES results are upper bounded by 2^27 (including RSA and ECURVE)
772
// Thus the following calculation does not overflow cbScratch.
773
//
774
cbScratch = SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve );
775
pbScratch = SymCryptCallbackAlloc( cbScratch );
776
if ( pbScratch == NULL )
777
{
778
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
779
goto cleanup;
780
}
781
782
// Allocating temporaries
783
pbScratchInternal = pbScratch;
784
cbScratchInternal = cbScratch;
785
786
peScalar = SymCryptModElementCreate( pbScratchInternal, pCurve->cbModElement, pCurve->GOrd );
787
SYMCRYPT_ASSERT( peScalar != NULL );
788
789
pbScratchInternal += pCurve->cbModElement;
790
cbScratchInternal -= pCurve->cbModElement;
791
792
cbScalar = SymCryptSizeofIntFromDigits( SymCryptEcurveDigitsofScalarMultiplier(pCurve) );
793
piScalar = SymCryptIntCreate( pbScratchInternal, cbScalar, SymCryptEcurveDigitsofScalarMultiplier(pCurve) );
794
795
pbScratchInternal += cbScalar;
796
cbScratchInternal -= cbScalar;
797
798
// Shift the high bit position if the format is "TIMESH"
799
// Note: Do not actually multiply the integer as we will check if it is
800
// less than the group order
801
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH)
802
{
803
highBitRestrictionPosition -= pCurve->coFactorPower;
804
}
805
806
// Main loop
807
do
808
{
809
// We perform Private key range validation by construction
810
// Setting a random mod element in the [1, SubgroupOrder-1] set
811
// This will be the "DivH" format of the private key. This means
812
// that PublicKey = h * PrivateKey * G
813
SymCryptModSetRandom(
814
pCurve->GOrd,
815
peScalar,
816
(SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE|SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE),
817
pbScratchInternal,
818
cbScratchInternal );
819
820
// Converting to "canonical" format
821
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
822
{
823
for (UINT32 i=0; i<pCurve->coFactorPower; i++)
824
{
825
SymCryptModAdd( pCurve->GOrd, peScalar, peScalar, peScalar, pbScratchInternal, cbScratchInternal );
826
}
827
}
828
829
// Set the temporary scalar to verify the format
830
SymCryptModElementToInt( pCurve->GOrd, peScalar, piScalar, pbScratchInternal, cbScratchInternal );
831
832
if (pCurve->HighBitRestrictionNumOfBits > 0)
833
{
834
// Set the desired bits
835
SymCryptIntSetBits(
836
piScalar,
837
pCurve->HighBitRestrictionValue,
838
highBitRestrictionPosition,
839
pCurve->HighBitRestrictionNumOfBits );
840
841
// Make sure we didn't exceed the group order
842
if ( SymCryptIntIsLessThan(
843
piScalar,
844
SymCryptIntFromModulus( pCurve->GOrd )) )
845
{
846
break;
847
}
848
}
849
else
850
{
851
// No high bit restriction was specified
852
break;
853
}
854
855
cntr--;
856
}
857
while (cntr>0);
858
859
if (cntr <= 0)
860
{
861
scError = SYMCRYPT_INVALID_ARGUMENT;
862
goto cleanup;
863
}
864
865
// Here piScalar has a private key that satisfies the restriction(s)
866
// Move it to the modelement
867
SymCryptIntToModElement( piScalar, pCurve->GOrd, peScalar, pbScratchInternal, cbScratchInternal );
868
869
// Convert the private key back to "DIVH" format
870
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
871
{
872
SymCryptModDivPow2( pCurve->GOrd, peScalar, pCurve->coFactorPower, peScalar, pbScratchInternal, cbScratchInternal );
873
}
874
875
// Set the private key
876
SymCryptModElementToInt( pCurve->GOrd, peScalar, pEckey->piPrivateKey, pbScratchInternal, cbScratchInternal );
877
878
// Do the multiplication (pass over the entire scratch space as it is not needed anymore)
879
scError = SymCryptEcpointScalarMul(
880
pCurve,
881
pEckey->piPrivateKey,
882
NULL,
883
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
884
pEckey->poPublicKey,
885
pbScratch,
886
cbScratch );
887
if ( scError != SYMCRYPT_NO_ERROR )
888
{
889
goto cleanup;
890
}
891
892
// Perform range and public key order validation on generated Public key.
893
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
894
{
895
// Perform Public key validation.
896
// Always perform range validation and validation that Public key is in subgroup of order GOrd
897
scError = SymCryptEckeyPerformPublicKeyValidation(
898
pEckey,
899
SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION,
900
pbScratch,
901
cbScratch );
902
if ( scError != SYMCRYPT_NO_ERROR )
903
{
904
goto cleanup;
905
}
906
}
907
908
pEckey->hasPrivateKey = TRUE;
909
910
pEckey->fAlgorithmInfo = flags; // We want to track all of the flags in the Eckey
911
912
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
913
{
914
if( ( flags & SYMCRYPT_FLAG_ECKEY_ECDSA ) != 0 )
915
{
916
// Ensure ECDSA algorithm selftest is run before first use of ECDSA algorithm
917
SYMCRYPT_RUN_SELFTEST_ONCE(
918
SymCryptEcDsaSelftest,
919
SYMCRYPT_SELFTEST_ALGORITHM_ECDSA );
920
}
921
922
if( ( flags & SYMCRYPT_FLAG_ECKEY_ECDH ) != 0 )
923
{
924
// Ensure we have run the algorithm selftest at least once.
925
SYMCRYPT_RUN_SELFTEST_ONCE(
926
SymCryptEcDhSecretAgreementSelftest,
927
SYMCRYPT_SELFTEST_ALGORITHM_ECDH );
928
929
// Run PCT eagerly so it only needs to be defined here
930
// The important case for performance is ECDH key generation
931
932
// ECDH PCT per SP80056a-rev3 5.6.2.1.4 b)
933
// Recompute the public key from the private key
934
// Option a) appears to be explicitly overruled by 140-3 IG
935
pbScratchInternal = pbScratch;
936
cbScratchInternal = cbScratch;
937
938
cbTmp = SymCryptSizeofEcpointFromCurve( pCurve );
939
poTmp = SymCryptEcpointCreate( pbScratchInternal, cbTmp, pCurve );
940
pbScratchInternal += cbTmp;
941
cbScratchInternal -= cbTmp;
942
943
SYMCRYPT_ASSERT( poTmp != NULL );
944
945
// Always multiply by the cofactor since the internal format is "DIVH"
946
scError = SymCryptEcpointScalarMul(
947
pCurve,
948
pEckey->piPrivateKey,
949
NULL,
950
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
951
poTmp,
952
pbScratchInternal,
953
cbScratchInternal );
954
if ( scError != SYMCRYPT_NO_ERROR )
955
{
956
goto cleanup;
957
}
958
959
SYMCRYPT_FIPS_ASSERT( SymCryptEcpointIsEqual( pCurve, poTmp, pEckey->poPublicKey, 0, pbScratchInternal, cbScratchInternal ) );
960
}
961
}
962
963
cleanup:
964
965
if ( pbScratch != NULL )
966
{
967
SymCryptWipe( pbScratch, cbScratch );
968
SymCryptCallbackFree( pbScratch );
969
}
970
971
return scError;
972
}
973
974
SYMCRYPT_ERROR
975
SYMCRYPT_CALL
976
SymCryptEckeyExtendKeyUsage(
977
_Inout_ PSYMCRYPT_ECKEY pEckey,
978
UINT32 flags )
979
{
980
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
981
982
// Ensure caller has specified what algorithm(s) the key will be used with
983
UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH;
984
985
if ( ( ( flags & ~algorithmFlags ) != 0 ) ||
986
( ( flags & algorithmFlags ) == 0) )
987
{
988
scError = SYMCRYPT_INVALID_ARGUMENT;
989
goto cleanup;
990
}
991
992
pEckey->fAlgorithmInfo |= flags;
993
994
cleanup:
995
return scError;
996
}
997
998