1 /*
2 * Copyright 2004-2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <string.h>
11
12 #include "apps.h"
13 #include "progs.h"
14 #include <openssl/bn.h>
15
16 /* Consistent with RSA modulus size limit and the size of plausible individual primes */
17 #define BUFSIZE 4098
18
19 typedef enum OPTION_choice {
20 OPT_COMMON,
21 OPT_HEX, OPT_GENERATE, OPT_BITS, OPT_SAFE, OPT_CHECKS,
22 OPT_PROV_ENUM,
23 OPT_IN_FILE
24 } OPTION_CHOICE;
25
check_num(const char * s,const int is_hex)26 static int check_num(const char *s, const int is_hex)
27 {
28 int i;
29 /*
30 * It would make sense to use ossl_isxdigit and ossl_isdigit here,
31 * but ossl_ctype_check is a local symbol in libcrypto.so.
32 */
33 if (is_hex) {
34 for (i = 0; ('0' <= s[i] && s[i] <= '9')
35 || ('A' <= s[i] && s[i] <= 'F')
36 || ('a' <= s[i] && s[i] <= 'f'); i++);
37 } else {
38 for (i = 0; '0' <= s[i] && s[i] <= '9'; i++);
39 }
40 return s[i] == 0;
41 }
42
process_num(const char * s,const int is_hex)43 static void process_num(const char *s, const int is_hex)
44 {
45 int r;
46 BIGNUM *bn = NULL;
47
48 r = check_num(s, is_hex);
49
50 if (r)
51 r = is_hex ? BN_hex2bn(&bn, s) : BN_dec2bn(&bn, s);
52
53 if (!r) {
54 BIO_printf(bio_err, "Failed to process value (%s)\n", s);
55 BN_free(bn);
56 return;
57 }
58
59 BN_print(bio_out, bn);
60 r = BN_check_prime(bn, NULL, NULL);
61 BN_free(bn);
62 if (r < 0) {
63 BIO_printf(bio_err, "Error checking prime\n");
64 return;
65 }
66
67 BIO_printf(bio_out, " (%s) %s prime\n", s, r == 1 ? "is" : "is not");
68 }
69
70 const OPTIONS prime_options[] = {
71 {OPT_HELP_STR, 1, '-', "Usage: %s [options] [number...]\n"},
72
73 OPT_SECTION("General"),
74 {"help", OPT_HELP, '-', "Display this summary"},
75 {"bits", OPT_BITS, 'p', "Size of number in bits"},
76 {"checks", OPT_CHECKS, 'p', "Number of checks"},
77 {"hex", OPT_HEX, '-',
78 "Enables hex format for output from prime generation or input to primality checking"},
79 {"in", OPT_IN_FILE, '-', "Provide file names containing numbers for primality checking"},
80
81 OPT_SECTION("Output"),
82 {"generate", OPT_GENERATE, '-', "Generate a prime"},
83 {"safe", OPT_SAFE, '-',
84 "When used with -generate, generate a safe prime"},
85
86 OPT_PROV_OPTIONS,
87
88 OPT_PARAMETERS(),
89 {"number", 0, 0, "Number(s) to check for primality if not generating"},
90 {NULL}
91 };
92
prime_main(int argc,char ** argv)93 int prime_main(int argc, char **argv)
94 {
95 BIGNUM *bn = NULL;
96 int hex = 0, generate = 0, bits = 0, safe = 0, ret = 1, in_file = 0;
97 char *prog;
98 OPTION_CHOICE o;
99 char file_read_buf[BUFSIZE] = { 0 };
100 BIO *in = NULL;
101
102 prog = opt_init(argc, argv, prime_options);
103 while ((o = opt_next()) != OPT_EOF) {
104 switch (o) {
105 case OPT_EOF:
106 case OPT_ERR:
107 opthelp:
108 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
109 goto end;
110 case OPT_HELP:
111 opt_help(prime_options);
112 ret = 0;
113 goto end;
114 case OPT_HEX:
115 hex = 1;
116 break;
117 case OPT_GENERATE:
118 generate = 1;
119 break;
120 case OPT_BITS:
121 bits = atoi(opt_arg());
122 break;
123 case OPT_SAFE:
124 safe = 1;
125 break;
126 case OPT_CHECKS:
127 /* ignore parameter and argument */
128 opt_arg();
129 break;
130 case OPT_PROV_CASES:
131 if (!opt_provider(o))
132 goto end;
133 break;
134 case OPT_IN_FILE:
135 in_file = 1;
136 break;
137 }
138 }
139
140 /* Optional arguments are numbers to check. */
141 if (generate && !opt_check_rest_arg(NULL))
142 goto opthelp;
143 argc = opt_num_rest();
144 argv = opt_rest();
145 if (!generate && argc == 0) {
146 BIO_printf(bio_err, "Missing number (s) to check\n");
147 goto opthelp;
148 }
149
150 if (generate) {
151 char *s;
152
153 if (!bits) {
154 BIO_printf(bio_err, "Specify the number of bits.\n");
155 goto end;
156 }
157 bn = BN_new();
158 if (bn == NULL) {
159 BIO_printf(bio_err, "Out of memory.\n");
160 goto end;
161 }
162 if (!BN_generate_prime_ex(bn, bits, safe, NULL, NULL, NULL)) {
163 BIO_printf(bio_err, "Failed to generate prime.\n");
164 goto end;
165 }
166 s = hex ? BN_bn2hex(bn) : BN_bn2dec(bn);
167 if (s == NULL) {
168 BIO_printf(bio_err, "Out of memory.\n");
169 goto end;
170 }
171 BIO_printf(bio_out, "%s\n", s);
172 OPENSSL_free(s);
173 } else {
174 for ( ; *argv; argv++) {
175 int bytes_read = 0;
176
177 if (!in_file) {
178 process_num(argv[0], hex);
179 } else {
180 in = bio_open_default_quiet(argv[0], 'r', 0);
181 if (in == NULL) {
182 BIO_printf(bio_err, "Error opening file %s\n", argv[0]);
183 continue;
184 }
185
186 while ((bytes_read = BIO_get_line(in, file_read_buf, BUFSIZE)) > 0) {
187 size_t valid_digits_length;
188
189 /* Number is too long. Discard remainder of the line */
190 if (bytes_read == BUFSIZE - 1 && file_read_buf[BUFSIZE - 2] != '\n') {
191 BIO_printf(bio_err, "Value in %s is over the maximum size (%d digits)\n",
192 argv[0], BUFSIZE - 2);
193 while (BIO_get_line(in, file_read_buf, BUFSIZE) == BUFSIZE - 1);
194 continue;
195 }
196
197 valid_digits_length = strspn(file_read_buf, "1234567890abcdefABCDEF");
198 file_read_buf[valid_digits_length] = '\0';
199
200 process_num(file_read_buf, hex);
201 }
202
203 if (bytes_read < 0)
204 BIO_printf(bio_err, "Read error in %s\n", argv[0]);
205
206 BIO_free(in);
207 }
208 }
209 }
210
211 ret = 0;
212 end:
213 BN_free(bn);
214 return ret;
215 }
216