Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/primes.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// primes.c
3
// Primality tests and prime number generation
4
//
5
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
6
//
7
8
#include "precomp.h"
9
10
UINT32
11
SYMCRYPT_CALL
12
SymCryptIntMillerRabinPrimalityTest(
13
    _In_                            PCSYMCRYPT_INT      piSrc,
14
                                    UINT32              nBitsSrc,
15
                                    UINT32              nIterations,
16
                                    UINT32              flags,
17
    _Out_writes_bytes_( cbScratch ) PBYTE               pbScratch,
18
                                    SIZE_T              cbScratch )
19
0
{
20
0
    BOOLEAN     innerLoop = TRUE;
21
0
    UINT32      borrow = 0;
22
23
0
    UINT32      nDigitsSrc = 0;
24
25
0
    UINT32                  R = 1;
26
0
    PSYMCRYPT_INT           piD = NULL;
27
0
    UINT32                  cbD = 0;
28
0
    PSYMCRYPT_MODULUS       pmModulus = NULL;
29
0
    UINT32                  cbModulus = 0;
30
0
    PSYMCRYPT_MODELEMENT    peX = NULL;
31
0
    UINT32                  cbX = 0;
32
33
0
    PSYMCRYPT_MODELEMENT    peOne = NULL;
34
0
    PSYMCRYPT_MODELEMENT    peMinOne = NULL;
35
36
0
    nDigitsSrc = SymCryptIntDigitsizeOfObject( piSrc );
37
0
    cbD = SymCryptSizeofIntFromDigits( nDigitsSrc );
38
0
    cbModulus = SymCryptSizeofModulusFromDigits( nDigitsSrc );
39
40
0
    SYMCRYPT_ASSERT( nBitsSrc >= SymCryptIntBitsizeOfValue( piSrc ) );
41
42
0
    SYMCRYPT_ASSERT( cbScratch >= cbModulus + SYMCRYPT_SCRATCH_BYTES_FOR_INT_TO_MODULUS(nDigitsSrc) );
43
44
    // Allocate the modulus
45
0
    pmModulus = SymCryptModulusCreate( pbScratch, cbModulus, nDigitsSrc );
46
0
    SYMCRYPT_ASSERT( pmModulus != NULL );
47
0
    pbScratch += cbModulus;
48
0
    cbScratch -= cbModulus;
49
50
    // Set the modulus
51
0
    SymCryptIntToModulus(
52
0
            piSrc,
53
0
            pmModulus,
54
0
            nBitsSrc,       // Average number of expected operations
55
0
            SYMCRYPT_FLAG_MODULUS_PARITY_PUBLIC,
56
0
            pbScratch,
57
0
            cbScratch );
58
59
    // Modelement size
60
0
    cbX = SymCryptSizeofModElementFromModulus( pmModulus );
61
62
0
    SYMCRYPT_ASSERT( cbScratch >=   3*cbX + cbD +
63
0
                                    SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsSrc ) );
64
65
0
    peX = SymCryptModElementCreate( pbScratch, cbX, pmModulus );
66
0
    SYMCRYPT_ASSERT( peX != NULL );
67
0
    pbScratch += cbX;
68
0
    cbScratch -= cbX;
69
70
0
    peOne = SymCryptModElementCreate( pbScratch, cbX, pmModulus );
71
0
    SYMCRYPT_ASSERT( peOne != NULL );
72
0
    pbScratch += cbX;
73
0
    cbScratch -= cbX;
74
75
0
    peMinOne = SymCryptModElementCreate( pbScratch, cbX, pmModulus );
76
0
    SYMCRYPT_ASSERT( peMinOne != NULL );
77
0
    pbScratch += cbX;
78
0
    cbScratch -= cbX;
79
80
    // Allocate D
81
0
    piD = SymCryptIntCreate( pbScratch, cbD, nDigitsSrc );
82
0
    SYMCRYPT_ASSERT( piD != NULL );
83
0
    pbScratch += cbD;
84
0
    cbScratch -= cbD;
85
86
    // Calculate (piSrc - 1)
87
    // Note: We should never get a borrow here because the requirement
88
    // is that Src > 3.
89
0
    SymCryptIntCopy( piSrc, piD );
90
0
    borrow = SymCryptIntSubUint32( piD, 1, piD );
91
0
    SYMCRYPT_ASSERT( borrow==0 );
92
93
0
    SYMCRYPT_ASSERT( SymCryptIntGetBit( piD, 0 ) == 0 );
94
95
    // Check the 3 mod 4 requirement when side-channel safe
96
0
    SYMCRYPT_ASSERT(
97
0
            ((flags & SYMCRYPT_FLAG_DATA_PUBLIC) != 0) ||
98
0
            (SymCryptIntGetBit( piD, 1 )!=0) );
99
0
    UNREFERENCED_PARAMETER( flags );
100
101
    // Calculate R and D such that Src - 1 = D*2^R
102
    //      Notice that the loop executes only if
103
    //      the SYMCRYPT_FLAG_DATA_PUBLIC is
104
    //      specified (and Src != 3 mod 4)
105
0
    R = 1;
106
0
    while( SymCryptIntGetBit( piD, R )==0 )
107
0
    {
108
0
        R++;
109
0
    }
110
0
    SymCryptIntDivPow2( piD, R, piD );
111
112
    // Set peOne and peMinOne
113
0
    SymCryptModElementSetValueUint32( 1, pmModulus, peOne, pbScratch, cbScratch );
114
0
    SymCryptModElementSetValueNegUint32( 1, pmModulus, peMinOne, pbScratch, cbScratch );
115
116
0
    for (UINT32 i=0; i<nIterations; i++)
117
0
    {
118
        // Pick a random X in [2, piSrc-2]
119
        // Therefore the flags parameter is 0 (default: not allowed 0, 1, -1 when modulus > 3)
120
0
        SymCryptModSetRandom( pmModulus, peX, 0, pbScratch, cbScratch );
121
122
        // X^D mod piSrc
123
        // Notice that nBitsSrc is public in the call of SymCryptModExp
124
0
        SymCryptModExp( pmModulus, peX, piD, nBitsSrc, 0, peX, pbScratch, cbScratch );
125
126
        // Check for 1 or -1
127
0
        if ( SymCryptModElementIsEqual( pmModulus, peX, peOne ) |
128
0
             SymCryptModElementIsEqual( pmModulus, peX, peMinOne ) )
129
0
        {
130
0
            continue;
131
0
        }
132
133
        // repeat R-1 times
134
        //      Notice that the inner loop executes only if
135
        //      the SYMCRYPT_FLAG_DATA_PUBLIC is
136
        //      specified (and Src != 3 mod 4)
137
0
        innerLoop = TRUE;
138
0
        for (UINT32 j=0; (j<R-1)&&(innerLoop); j++)
139
0
        {
140
            // Square X
141
0
            SymCryptModSquare( pmModulus, peX, peX, pbScratch, cbScratch );
142
143
            // Check if it is 1
144
0
            if (SymCryptModElementIsEqual( pmModulus, peX, peOne ))
145
0
            {
146
0
                return 0x0;
147
0
            }
148
149
            // Check if it is -1
150
0
            if (SymCryptModElementIsEqual( pmModulus, peX, peMinOne ))
151
0
            {
152
0
                innerLoop = FALSE;
153
0
                break;
154
0
            }
155
0
        }
156
157
0
        if (innerLoop)
158
0
        {
159
0
            return 0x0;
160
0
        }
161
0
    }
162
163
0
    return  0xffffffff;     // Prime
164
0
}
165
166
0
#define SYMCRYPT_PRIME_GENERATION_MR_ITERATIONS (64)
167
168
SYMCRYPT_ERROR
169
SYMCRYPT_CALL
170
SymCryptIntGenerateRandomPrime(
171
    _In_                            PCSYMCRYPT_INT      piLow,
172
    _In_                            PCSYMCRYPT_INT      piHigh,
173
    _In_reads_opt_( nPubExp )       PCUINT64            pu64PubExp,
174
                                    UINT32              nPubExp,
175
                                    UINT32              nTries,
176
                                    UINT32              flags,
177
    _Inout_                         PSYMCRYPT_INT       piDst,
178
    _Out_writes_bytes_( cbScratch ) PBYTE               pbScratch,
179
                                    SIZE_T              cbScratch )
180
0
{
181
0
    SYMCRYPT_ERROR  scError = SYMCRYPT_EXTERNAL_FAILURE;
182
0
    PSYMCRYPT_DIVISOR pdPubExp[ SYMCRYPT_RSAKEY_MAX_NUMOF_PUBEXPS ];
183
0
    PSYMCRYPT_INT piTmp;
184
185
0
    UINT32 cnt = 0;
186
0
    UINT32 e;
187
0
    BOOLEAN reject;
188
0
    SIZE_T cbObj;
189
190
0
    UINT32 nBits = SymCryptIntBitsizeOfObject(piDst);
191
0
    UINT32 nBytes = (nBits + 7)/8;
192
193
0
    UINT32 nBitsHigh = SymCryptIntBitsizeOfValue( piHigh );
194
195
0
    PCSYMCRYPT_TRIALDIVISION_CONTEXT pTrialDivisionContext = SymCryptCreateTrialDivisionContext( SymCryptIntDigitsizeOfObject( piHigh ) );
196
197
0
    SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_SCRATCH_BYTES_FOR_INT_PRIME_GEN( SymCryptIntDigitsizeOfObject( piDst ) ) );
198
0
    SYMCRYPT_ASSERT( nPubExp <= SYMCRYPT_RSAKEY_MAX_NUMOF_PUBEXPS );
199
0
    SYMCRYPT_ASSERT( SymCryptDigitsFromBits( 64 ) == 1 );
200
201
0
    UNREFERENCED_PARAMETER( flags );
202
203
    // Allocate divisor objects for each public exponent & initialize them
204
0
    cbObj = SymCryptSizeofDivisorFromDigits( 1 );
205
0
    for( e = 0; e < nPubExp; e++ )
206
0
    {
207
0
        SYMCRYPT_ASSERT( cbScratch >= cbObj );
208
0
        if( pu64PubExp[e] == 0 )
209
0
        {
210
0
            scError = SYMCRYPT_INVALID_ARGUMENT;
211
0
            goto exit;
212
0
        }
213
214
0
        pdPubExp[e] = SymCryptDivisorCreate( pbScratch, cbObj, 1 );
215
0
        pbScratch += cbObj;
216
0
        cbScratch -= cbObj;
217
218
0
        SymCryptIntSetValueUint64( pu64PubExp[e], SymCryptIntFromDivisor( pdPubExp[e] ) );
219
0
        SymCryptIntToDivisor( SymCryptIntFromDivisor( pdPubExp[e] ), pdPubExp[e], 1000, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratch );
220
0
    }
221
222
0
    cbObj = SymCryptSizeofIntFromDigits( 1 );
223
0
    SYMCRYPT_ASSERT( cbScratch >= cbObj + nBytes );
224
0
    piTmp = SymCryptIntCreate( pbScratch, cbObj, 1 );
225
0
    pbScratch += cbObj;
226
0
    cbScratch -= cbObj;
227
228
0
    do
229
0
    {
230
0
        cnt++;
231
232
0
        scError = SymCryptCallbackRandom( pbScratch, nBytes );
233
0
        if (scError != SYMCRYPT_NO_ERROR)
234
0
        {
235
0
            goto exit;
236
0
        }
237
238
0
        scError = SymCryptIntSetValue( pbScratch, nBytes, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piDst );
239
0
        if (scError != SYMCRYPT_NO_ERROR)
240
0
        {
241
0
            goto exit;
242
0
        }
243
244
        // Set the integer to 3 mod 4
245
0
        SymCryptIntSetBits( piDst, 3, 0, 2 );
246
247
        // Zero out the top bits above the upper limit
248
0
        SymCryptIntModPow2( piDst, nBitsHigh, piDst );
249
250
        // Check if it is in the correct range
251
0
        if ( (SymCryptIntIsLessThan( piDst, piLow )) ||
252
0
             (!SymCryptIntIsLessThan( piDst, piHigh )) )
253
0
        {
254
0
            continue;
255
0
        }
256
257
        // Fast compositeness check
258
0
        if( SymCryptIntFindSmallDivisor( pTrialDivisionContext, piDst, NULL, 0 ) != 0 )
259
0
        {
260
            // We found a small divisor; it is not a prime
261
0
            continue;
262
0
        }
263
264
        // Check for compatibility with public exponents (if provided)
265
0
        reject = FALSE;
266
0
        for( e = 0; e < nPubExp; e++ )
267
0
        {
268
0
            SymCryptIntDivMod( piDst, pdPubExp[e], NULL, piTmp, pbScratch, cbScratch );
269
270
            // Check that e has a modular inverse mod P-1
271
            // If e and P-1 are coprime, or GCD( P-1, e ) == 1, then e^-1 exists
272
            // We have (P mod e) in piTmp.
273
            // If piTmp == 0 then P is divisible by e, and will fail primality test - we don't care about the result of the GCD
274
            // Otherwise, GCD( (P mod e)-1, e ) == GCD( P-1 mod e, e ) == GCD( P-1, e )
275
            //
276
            // Note that if P-1 is a multiple of e then (P mod e)-1 == 0, and GCD( 0, e ) == e
277
0
            if( SymCryptUint64Gcd( pu64PubExp[e], SymCryptIntGetValueLsbits64( piTmp ) - 1, SYMCRYPT_FLAG_GCD_INPUTS_NOT_BOTH_EVEN ) != 1 )
278
0
            {
279
                // We can't continue the big loop from here :-(
280
0
                reject = TRUE;
281
0
                break;
282
0
            }
283
0
        }
284
0
        if( reject )
285
0
        {
286
0
            continue;
287
0
        }
288
289
        // Primality check
290
0
        if (SymCryptIntMillerRabinPrimalityTest( piDst, nBitsHigh, SYMCRYPT_PRIME_GENERATION_MR_ITERATIONS, 0, pbScratch, cbScratch ))
291
0
        {
292
0
            scError = SYMCRYPT_NO_ERROR;
293
0
            break;
294
0
        }
295
0
    }
296
0
    while (cnt<nTries);
297
298
0
    if (cnt>=nTries)
299
0
    {
300
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
301
0
    }
302
303
0
exit:
304
0
    SymCryptFreeTrialDivisionContext( pTrialDivisionContext );
305
0
    return scError;
306
0
}