1 /* $NetBSD: qsafe.c,v 1.1 2006/01/24 18:59:23 elad Exp $ */
4 * Copyright 1994 Phil Karn <karn@qualcomm.com>
5 * Copyright 1996-1998, 2003 William Allen206 Simpson <wsimpson@greendragon.com>
6 * Copyright 2000 Niels Provos <provos@citi.umich.edu>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * Test probable "safe" primes,
33 * suitable for use as Diffie-Hellman moduli;
34 * that is, where q = (p-1)/2 is also prime.
36 * This is the second of two steps.
37 * This step is processor intensive.
39 * 1996 May William Allen Simpson
40 * extracted from earlier code by Phil Karn, April 1994.
41 * read large prime candidates list (q),
42 * and check prime probability of (p).
43 * 1998 May William Allen Simpson
45 * optionally limit to a single generator.
46 * 2000 Dec Niels Provos
47 * convert from GMP to openssl BN.
48 * 2003 Jun William Allen Simpson
49 * change outfile definition slightly to match openssh mistake.
50 * move common file i/o to own file for better documentation.
51 * redo debugprint again.
58 #include <openssl/bn.h>
61 /* define DEBUGPRINT 1 */
62 #define TRIAL_MINIMUM (4)
64 static void usage(void);
67 * perform a Miller-Rabin primality test
68 * on the list of candidates
69 * (checking both q and p)
70 * from standard input.
71 * The result is a list of so-call "safe" primes
75 main(int argc
, char *argv
[])
81 uint32_t count_in
= 0;
82 uint32_t count_out
= 0;
83 uint32_t count_possible
= 0;
84 uint32_t generator_known
;
85 uint32_t generator_wanted
= 0;
100 if ((trials
= strtoul(argv
[1], NULL
, 10)) < TRIAL_MINIMUM
) {
101 trials
= TRIAL_MINIMUM
;
105 generator_wanted
= strtoul(argv
[2], NULL
, 16);
114 (void)fprintf(stderr
,
115 "%.24s Final %d Miller-Rabin trials (%x generator)\n",
116 ctime(&time_start
), trials
, generator_wanted
);
118 lp
= (char *) malloc((unsigned long) QLINESIZE
+ 1);
120 while (fgets(lp
, QLINESIZE
, stdin
) != NULL
) {
121 size_t ll
= strlen(lp
);
125 if (ll
< 14 || *lp
== '!' || *lp
== '#') {
127 (void)fprintf(stderr
, "%10lu: comment or short"
128 " line\n", count_in
);
134 cp
= &lp
[14]; /* (skip) */
137 in_type
= strtoul(cp
, &cp
, 10);
140 in_tests
= strtoul(cp
, &cp
, 10);
141 if (in_tests
& QTEST_COMPOSITE
) {
143 (void)fprintf(stderr
, "%10lu: known composite\n",
150 in_tries
= (uint32_t) strtoul(cp
, &cp
, 10);
152 /* size (most significant bit) */
153 in_size
= (uint32_t) strtoul(cp
, &cp
, 10);
155 /* generator (hex) */
156 generator_known
= (uint32_t) strtoul(cp
, &cp
, 16);
158 /* Skip white space */
159 cp
+= strspn(cp
, " ");
163 case QTYPE_SOPHIE_GERMAINE
:
165 (void)fprintf(stderr
, "%10lu: (%lu) "
166 "Sophie-Germaine\n", count_in
,
182 (void)fprintf(stderr
, "%10lu: (%lu)\n",
194 * due to earlier inconsistencies in interpretation, check the
197 if ((uint32_t)BN_num_bits(p
) != (in_size
+ 1)) {
199 (void)fprintf(stderr
, "%10lu: bit size %ul "
200 "mismatch\n", count_in
, in_size
);
205 if (in_size
< QSIZE_MINIMUM
) {
207 (void)fprintf(stderr
, "%10lu: bit size %ul "
208 "too short\n", count_in
, in_size
);
213 if (in_tests
& QTEST_MILLER_RABIN
)
219 * guess unknown generator
221 if (generator_known
== 0) {
222 if (BN_mod_word(p
, 24UL) == 11)
224 else if (BN_mod_word(p
, 12UL) == 5)
227 BN_ULONG r
= BN_mod_word(p
, 10UL);
229 if (r
== 3 || r
== 7) {
236 * skip tests when desired generator doesn't match
238 if (generator_wanted
> 0 &&
239 generator_wanted
!= generator_known
) {
241 (void)fprintf(stderr
,
242 "%10lu: generator %ld != %ld\n",
243 count_in
, generator_known
, generator_wanted
);
251 * The (1/4)^N performance bound on Miller-Rabin is extremely
252 * pessimistic, so don't spend a lot of time really verifying
253 * that q is prime until after we know that p is also prime. A
254 * single pass will weed out the vast majority of composite
257 if (BN_is_prime(q
, 1, NULL
, ctx
, NULL
) <= 0) {
259 (void)fprintf(stderr
, "%10lu: q failed first "
260 "possible prime test\n", count_in
);
266 * q is possibly prime, so go ahead and really make sure that
267 * p is prime. If it is, then we can go back and do the same
268 * for q. If p is composite, chances are that will show up on
269 * the first Rabin-Miller iteration so it doesn't hurt to
270 * specify a high iteration count.
272 if (!BN_is_prime(p
, trials
, NULL
, ctx
, NULL
)) {
274 (void)fprintf(stderr
, "%10lu: p is not prime\n",
281 (void)fprintf(stderr
, "%10lu: p is almost certainly "
282 "prime\n", count_in
);
285 /* recheck q more rigorously */
286 if (!BN_is_prime(q
, trials
- 1, NULL
, ctx
, NULL
)) {
288 (void)fprintf(stderr
, "%10lu: q is not prime\n",
294 fprintf(stderr
, "%10lu: q is almost certainly prime\n",
297 if (0 > qfileout(stdout
,
299 (in_tests
| QTEST_MILLER_RABIN
),
318 fflush(stdout
); /* fclose(stdout); */
320 (void)fprintf(stderr
,
321 "%.24s Found %u safe primes of %u candidates in %lu seconds\n",
322 ctime(&time_stop
), count_out
, count_possible
,
323 (long) (time_stop
- time_start
));
331 (void)fprintf(stderr
, "Usage: %s <trials> [generator]\n",