/src/SymCrypt/lib/ec_dh.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // ec_dh.c ECDH function |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | // |
7 | | |
8 | | #include "precomp.h" |
9 | | |
10 | | SYMCRYPT_ERROR |
11 | | SYMCRYPT_CALL |
12 | | SymCryptEcDhSecretAgreement( |
13 | | _In_ PCSYMCRYPT_ECKEY pkPrivate, |
14 | | _In_ PCSYMCRYPT_ECKEY pkPublic, |
15 | | SYMCRYPT_NUMBER_FORMAT format, |
16 | | UINT32 flags, |
17 | | _Out_writes_( cbAgreedSecret ) PBYTE pbAgreedSecret, |
18 | | SIZE_T cbAgreedSecret ) |
19 | 0 | { |
20 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
21 | |
|
22 | 0 | PBYTE pbScratch = NULL; |
23 | 0 | SIZE_T cbScratch = 0; |
24 | 0 | SIZE_T cbScratchInternal = 0; |
25 | 0 | PBYTE pCurr = NULL; |
26 | |
|
27 | 0 | PCSYMCRYPT_ECURVE pCurve = NULL; |
28 | |
|
29 | 0 | PSYMCRYPT_ECPOINT poQ = NULL; |
30 | 0 | PBYTE pbX = NULL; |
31 | |
|
32 | 0 | UINT32 cbQ = 0; |
33 | 0 | UINT32 cbX = 0; |
34 | | |
35 | | // Make sure that the keys may be used in ECDH |
36 | 0 | if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) || |
37 | 0 | ((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) ) |
38 | 0 | { |
39 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
40 | 0 | goto cleanup; |
41 | 0 | } |
42 | | |
43 | | // Make sure we only specify the correct flags and that |
44 | | // there is a private key |
45 | 0 | if ( (flags != 0) || |
46 | 0 | (!pkPrivate->hasPrivateKey) ) |
47 | 0 | { |
48 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
49 | 0 | goto cleanup; |
50 | 0 | } |
51 | | |
52 | | // Check that the curve is the same for both keys |
53 | 0 | if ( SymCryptEcurveIsSame( pkPrivate->pCurve, pkPublic->pCurve ) ) |
54 | 0 | { |
55 | 0 | pCurve = pkPrivate->pCurve; |
56 | 0 | } |
57 | 0 | else |
58 | 0 | { |
59 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
60 | 0 | goto cleanup; |
61 | 0 | } |
62 | | |
63 | | // Objects and scratch space size calculation |
64 | 0 | cbQ = SymCryptSizeofEcpointFromCurve( pCurve ); |
65 | 0 | cbX = SymCryptEcurveSizeofFieldElement( pCurve ); |
66 | | |
67 | | // Check the output buffer has the correct size |
68 | 0 | if (cbAgreedSecret != cbX) |
69 | 0 | { |
70 | 0 | scError = SYMCRYPT_WRONG_BLOCK_SIZE; |
71 | 0 | goto cleanup; |
72 | 0 | } |
73 | | |
74 | 0 | cbScratchInternal = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS(pCurve), |
75 | 0 | SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ), |
76 | 0 | SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) )); |
77 | | |
78 | | // |
79 | | // From symcrypt_internal.h we have: |
80 | | // - sizeof results are upper bounded by 2^19 |
81 | | // - SYMCRYPT_SCRATCH_BYTES results are upper bounded by 2^27 (including RSA and ECURVE) |
82 | | // Thus the following calculation does not overflow cbScratch. |
83 | | // |
84 | 0 | cbScratch = cbScratchInternal + cbQ + cbX; |
85 | | |
86 | | // Scratch space allocation |
87 | 0 | pbScratch = SymCryptCallbackAlloc( cbScratch ); |
88 | 0 | if ( pbScratch == NULL ) |
89 | 0 | { |
90 | 0 | scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE; |
91 | 0 | goto cleanup; |
92 | 0 | } |
93 | | |
94 | | // Creating temporaries |
95 | 0 | pCurr = pbScratch + cbScratchInternal; |
96 | 0 | poQ = SymCryptEcpointCreate( pCurr, cbQ, pCurve ); |
97 | 0 | pCurr += cbQ; |
98 | 0 | pbX = pCurr; |
99 | |
|
100 | 0 | SYMCRYPT_ASSERT( poQ != NULL); |
101 | | |
102 | | // Make sure that the public key is not the zero point |
103 | | // No need to check that the point is on the curve; that check is done when the |
104 | | // public key is created. |
105 | 0 | if (SymCryptEcpointIsZero(pCurve, pkPublic->poPublicKey, pbScratch, cbScratchInternal)) |
106 | 0 | { |
107 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
108 | 0 | goto cleanup; |
109 | 0 | } |
110 | | |
111 | | // Calculate the secret |
112 | | // Always do low order clearing by multiplying by the cofactor. |
113 | | // Note: the internal format of piPrivateKey is "DivH", so we |
114 | | // get the correct result. |
115 | 0 | scError = SymCryptEcpointScalarMul( |
116 | 0 | pCurve, |
117 | 0 | pkPrivate->piPrivateKey, |
118 | 0 | pkPublic->poPublicKey, |
119 | 0 | SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL, |
120 | 0 | poQ, |
121 | 0 | pbScratch, |
122 | 0 | cbScratchInternal ); |
123 | 0 | if ( scError != SYMCRYPT_NO_ERROR ) |
124 | 0 | { |
125 | 0 | goto cleanup; |
126 | 0 | } |
127 | | |
128 | | // Check if the result is the identity point |
129 | 0 | if ( SymCryptEcpointIsZero( |
130 | 0 | pCurve, |
131 | 0 | poQ, |
132 | 0 | pbScratch, |
133 | 0 | cbScratchInternal ) ) |
134 | 0 | { |
135 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
136 | 0 | goto cleanup; |
137 | 0 | } |
138 | | |
139 | | // Get the x from poQ |
140 | 0 | scError = SymCryptEcpointGetValue( pCurve, poQ, format, SYMCRYPT_ECPOINT_FORMAT_X, pbX, cbX, 0, pbScratch, cbScratchInternal); |
141 | 0 | if ( scError != SYMCRYPT_NO_ERROR ) |
142 | 0 | { |
143 | 0 | goto cleanup; |
144 | 0 | } |
145 | | |
146 | | // Store it in the destination |
147 | 0 | memcpy( pbAgreedSecret, pbX, cbX); |
148 | |
|
149 | 0 | cleanup: |
150 | 0 | if ( pbScratch != NULL ) |
151 | 0 | { |
152 | 0 | SymCryptWipe( pbScratch, cbScratch ); |
153 | 0 | SymCryptCallbackFree( pbScratch ); |
154 | 0 | } |
155 | |
|
156 | 0 | return scError; |
157 | 0 | } |