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