Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/symcrypt/lib/ec_dh.c
15010 views
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
{
20
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
21
22
PBYTE pbScratch = NULL;
23
SIZE_T cbScratch = 0;
24
SIZE_T cbScratchInternal = 0;
25
PBYTE pCurr = NULL;
26
27
PCSYMCRYPT_ECURVE pCurve = NULL;
28
29
PSYMCRYPT_ECPOINT poQ = NULL;
30
PBYTE pbX = NULL;
31
32
UINT32 cbQ = 0;
33
UINT32 cbX = 0;
34
35
// Make sure that the keys may be used in ECDH
36
if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) ||
37
((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) )
38
{
39
scError = SYMCRYPT_INVALID_ARGUMENT;
40
goto cleanup;
41
}
42
43
// Make sure we only specify the correct flags and that
44
// there is a private key
45
if ( (flags != 0) ||
46
(!pkPrivate->hasPrivateKey) )
47
{
48
scError = SYMCRYPT_INVALID_ARGUMENT;
49
goto cleanup;
50
}
51
52
// Check that the curve is the same for both keys
53
if ( SymCryptEcurveIsSame( pkPrivate->pCurve, pkPublic->pCurve ) )
54
{
55
pCurve = pkPrivate->pCurve;
56
}
57
else
58
{
59
scError = SYMCRYPT_INVALID_ARGUMENT;
60
goto cleanup;
61
}
62
63
// Objects and scratch space size calculation
64
cbQ = SymCryptSizeofEcpointFromCurve( pCurve );
65
cbX = SymCryptEcurveSizeofFieldElement( pCurve );
66
67
// Check the output buffer has the correct size
68
if (cbAgreedSecret != cbX)
69
{
70
scError = SYMCRYPT_WRONG_BLOCK_SIZE;
71
goto cleanup;
72
}
73
74
cbScratchInternal = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS(pCurve),
75
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ),
76
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
cbScratch = cbScratchInternal + cbQ + cbX;
85
86
// Scratch space allocation
87
pbScratch = SymCryptCallbackAlloc( cbScratch );
88
if ( pbScratch == NULL )
89
{
90
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
91
goto cleanup;
92
}
93
94
// Creating temporaries
95
pCurr = pbScratch + cbScratchInternal;
96
poQ = SymCryptEcpointCreate( pCurr, cbQ, pCurve );
97
pCurr += cbQ;
98
pbX = pCurr;
99
100
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
if (SymCryptEcpointIsZero(pCurve, pkPublic->poPublicKey, pbScratch, cbScratchInternal))
106
{
107
scError = SYMCRYPT_INVALID_ARGUMENT;
108
goto cleanup;
109
}
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
scError = SymCryptEcpointScalarMul(
116
pCurve,
117
pkPrivate->piPrivateKey,
118
pkPublic->poPublicKey,
119
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
120
poQ,
121
pbScratch,
122
cbScratchInternal );
123
if ( scError != SYMCRYPT_NO_ERROR )
124
{
125
goto cleanup;
126
}
127
128
// Check if the result is the identity point
129
if ( SymCryptEcpointIsZero(
130
pCurve,
131
poQ,
132
pbScratch,
133
cbScratchInternal ) )
134
{
135
scError = SYMCRYPT_INVALID_BLOB;
136
goto cleanup;
137
}
138
139
// Get the x from poQ
140
scError = SymCryptEcpointGetValue( pCurve, poQ, format, SYMCRYPT_ECPOINT_FORMAT_X, pbX, cbX, 0, pbScratch, cbScratchInternal);
141
if ( scError != SYMCRYPT_NO_ERROR )
142
{
143
goto cleanup;
144
}
145
146
// Store it in the destination
147
memcpy( pbAgreedSecret, pbX, cbX);
148
149
cleanup:
150
if ( pbScratch != NULL )
151
{
152
SymCryptWipe( pbScratch, cbScratch );
153
SymCryptCallbackFree( pbScratch );
154
}
155
156
return scError;
157
}
158
159