Coverage Report

Created: 2024-11-21 07:03

/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
}