Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/dh.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// dh.c   DH functions
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
SymCryptDhSecretAgreement(
13
    _In_                            PCSYMCRYPT_DLKEY        pkPrivate,
14
    _In_                            PCSYMCRYPT_DLKEY        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
    PBYTE   pbScratchInternal = NULL;
25
0
    SIZE_T  cbScratchInternal = 0;
26
27
0
    PCSYMCRYPT_DLGROUP  pDlgroup = NULL;
28
29
0
    PSYMCRYPT_MODELEMENT peRes = NULL;
30
0
    UINT32 cbModelement = 0;
31
32
0
    UINT32 nBitsOfExp = 0;
33
34
    // Make sure that the keys may be used in DH
35
0
    if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DH) == 0) ||
36
0
         ((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DH) == 0) )
37
0
    {
38
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
39
0
        goto cleanup;
40
0
    }
41
42
    // Make sure we only specify the correct flags and that
43
    // there is a private key
44
0
    if ( (flags != 0) || (!pkPrivate->fHasPrivateKey) )
45
0
    {
46
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
47
0
        goto cleanup;
48
0
    }
49
50
    // Check that the group is the same for both keys
51
0
    if ( SymCryptDlgroupIsSame( pkPrivate->pDlgroup, pkPublic->pDlgroup ) )
52
0
    {
53
0
        pDlgroup = pkPrivate->pDlgroup;
54
0
    }
55
0
    else
56
0
    {
57
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
58
0
        goto cleanup;
59
0
    }
60
61
    // Check the output buffer has the correct size
62
0
    if (cbAgreedSecret != SymCryptDlkeySizeofPublicKey( pkPrivate ))
63
0
    {
64
0
        scError = SYMCRYPT_WRONG_BLOCK_SIZE;
65
0
        goto cleanup;
66
0
    }
67
68
    // Objects and scratch space size calculation
69
0
    cbModelement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
70
0
    cbScratch = cbModelement +
71
0
                SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( pDlgroup->nDigitsOfP ),
72
0
                     SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pDlgroup->nDigitsOfP ));
73
74
    // Scratch space allocation
75
0
    pbScratch = SymCryptCallbackAlloc( cbScratch );
76
0
    if ( pbScratch == NULL )
77
0
    {
78
0
        scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
79
0
        goto cleanup;
80
0
    }
81
82
    // Creating temporary
83
0
    pbScratchInternal = pbScratch;
84
0
    cbScratchInternal = cbScratch;
85
0
    peRes = SymCryptModElementCreate( pbScratchInternal, cbModelement, pDlgroup->pmP );
86
0
    pbScratchInternal += cbModelement;
87
0
    cbScratchInternal -= cbModelement;
88
89
0
    SYMCRYPT_ASSERT( peRes != NULL);
90
91
    // Fix the bits of the exponent (the private key might be either mod Q, mod 2^nBitsPriv, or mod P)
92
0
    if (pkPrivate->fPrivateModQ)
93
0
    {
94
0
        nBitsOfExp = pkPrivate->nBitsPriv;
95
0
    }
96
0
    else
97
0
    {
98
0
        nBitsOfExp = pDlgroup->nBitsOfP;
99
0
    }
100
101
    // Calculate the secret
102
0
    SymCryptModExp(
103
0
            pDlgroup->pmP,
104
0
            pkPublic->pePublicKey,
105
0
            pkPrivate->piPrivateKey,
106
0
            nBitsOfExp,
107
0
            0,              // SC safe
108
0
            peRes,
109
0
            pbScratchInternal,
110
0
            cbScratchInternal );
111
112
    // Check if the result is zero
113
0
    if ( SymCryptModElementIsZero( pDlgroup->pmP, peRes ) )
114
0
    {
115
0
        scError = SYMCRYPT_INVALID_BLOB;
116
0
        goto cleanup;
117
0
    }
118
119
    // Output the result
120
0
    scError = SymCryptModElementGetValue(
121
0
            pDlgroup->pmP,
122
0
            peRes,
123
0
            pbAgreedSecret,
124
0
            cbAgreedSecret,
125
0
            format,
126
0
            pbScratchInternal,
127
0
            cbScratchInternal );
128
0
    if ( scError != SYMCRYPT_NO_ERROR )
129
0
    {
130
0
        goto cleanup;
131
0
    }
132
133
0
cleanup:
134
0
    if ( pbScratch != NULL )
135
0
    {
136
0
        SymCryptWipe( pbScratch, cbScratch );
137
0
        SymCryptCallbackFree( pbScratch );
138
0
    }
139
140
0
    return scError;
141
0
}