xref: /llvm-project/polly/lib/External/isl/imath/examples/rsakey.c (revision 658eb9e14264d48888ade0e3daf0b648f76c3f0e)
1*658eb9e1SMichael Kruse /*
2*658eb9e1SMichael Kruse   Name:     rsakey.c
3*658eb9e1SMichael Kruse   Purpose:  Generate keys for the RSA cryptosystem.
4*658eb9e1SMichael Kruse   Author:   M. J. Fromberger
5*658eb9e1SMichael Kruse 
6*658eb9e1SMichael Kruse   Usage:  rsakey [-e <expt>] <modbits> [<outfile>]
7*658eb9e1SMichael Kruse 
8*658eb9e1SMichael Kruse   Generates an RSA key pair with a modulus having <modbits> significant bits,
9*658eb9e1SMichael Kruse   and writes it to the specified output file, or to the standard output.  The
10*658eb9e1SMichael Kruse   -e option allows the user to specify an encryption exponent; otherwise, an
11*658eb9e1SMichael Kruse   encryption exponent is chosen at random.
12*658eb9e1SMichael Kruse 
13*658eb9e1SMichael Kruse   Primes p and q are obtained by reading random bits from /dev/random, setting
14*658eb9e1SMichael Kruse   the low-order bit, and testing for primality.  If the first candidate is not
15*658eb9e1SMichael Kruse   prime, successive odd candidates are tried until a probable prime is found.
16*658eb9e1SMichael Kruse 
17*658eb9e1SMichael Kruse   Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved.
18*658eb9e1SMichael Kruse 
19*658eb9e1SMichael Kruse   Permission is hereby granted, free of charge, to any person obtaining a copy
20*658eb9e1SMichael Kruse   of this software and associated documentation files (the "Software"), to deal
21*658eb9e1SMichael Kruse   in the Software without restriction, including without limitation the rights
22*658eb9e1SMichael Kruse   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23*658eb9e1SMichael Kruse   copies of the Software, and to permit persons to whom the Software is
24*658eb9e1SMichael Kruse   furnished to do so, subject to the following conditions:
25*658eb9e1SMichael Kruse 
26*658eb9e1SMichael Kruse   The above copyright notice and this permission notice shall be included in
27*658eb9e1SMichael Kruse   all copies or substantial portions of the Software.
28*658eb9e1SMichael Kruse 
29*658eb9e1SMichael Kruse   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30*658eb9e1SMichael Kruse   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31*658eb9e1SMichael Kruse   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
32*658eb9e1SMichael Kruse   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33*658eb9e1SMichael Kruse   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34*658eb9e1SMichael Kruse   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35*658eb9e1SMichael Kruse   SOFTWARE.
36*658eb9e1SMichael Kruse  */
37*658eb9e1SMichael Kruse 
38*658eb9e1SMichael Kruse #include <errno.h>
39*658eb9e1SMichael Kruse #include <limits.h>
40*658eb9e1SMichael Kruse #include <stdio.h>
41*658eb9e1SMichael Kruse #include <stdlib.h>
42*658eb9e1SMichael Kruse #include <string.h>
43*658eb9e1SMichael Kruse 
44*658eb9e1SMichael Kruse #include <getopt.h>
45*658eb9e1SMichael Kruse #include <unistd.h>
46*658eb9e1SMichael Kruse 
47*658eb9e1SMichael Kruse #include "imath.h"
48*658eb9e1SMichael Kruse #include "iprime.h"
49*658eb9e1SMichael Kruse 
50*658eb9e1SMichael Kruse typedef struct {
51*658eb9e1SMichael Kruse   mpz_t p;
52*658eb9e1SMichael Kruse   mpz_t q;
53*658eb9e1SMichael Kruse   mpz_t n;
54*658eb9e1SMichael Kruse   mpz_t e;
55*658eb9e1SMichael Kruse   mpz_t d;
56*658eb9e1SMichael Kruse } rsa_key;
57*658eb9e1SMichael Kruse 
58*658eb9e1SMichael Kruse /* Load the specified buffer with random bytes */
59*658eb9e1SMichael Kruse int randomize(unsigned char *buf, size_t len);
60*658eb9e1SMichael Kruse 
61*658eb9e1SMichael Kruse /* Overwrite the specified value with n_bits random bits */
62*658eb9e1SMichael Kruse mp_result mp_int_randomize(mp_int a, mp_size n_bits);
63*658eb9e1SMichael Kruse 
64*658eb9e1SMichael Kruse /* Find a prime starting from the given odd seed */
65*658eb9e1SMichael Kruse mp_result find_prime(mp_int seed, FILE *fb);
66*658eb9e1SMichael Kruse 
67*658eb9e1SMichael Kruse /* Initialize/destroy an rsa_key structure */
68*658eb9e1SMichael Kruse mp_result rsa_key_init(rsa_key *kp);
69*658eb9e1SMichael Kruse void rsa_key_clear(rsa_key *kp);
70*658eb9e1SMichael Kruse void rsa_key_write(rsa_key *kp, FILE *ofp);
71*658eb9e1SMichael Kruse 
main(int argc,char * argv[])72*658eb9e1SMichael Kruse int main(int argc, char *argv[]) {
73*658eb9e1SMichael Kruse   int opt, modbits;
74*658eb9e1SMichael Kruse   FILE *ofp = stdout;
75*658eb9e1SMichael Kruse   char *expt = NULL;
76*658eb9e1SMichael Kruse   rsa_key the_key;
77*658eb9e1SMichael Kruse   mp_result res;
78*658eb9e1SMichael Kruse 
79*658eb9e1SMichael Kruse   /* Process command-line arguments */
80*658eb9e1SMichael Kruse   while ((opt = getopt(argc, argv, "e:")) != EOF) {
81*658eb9e1SMichael Kruse     switch (opt) {
82*658eb9e1SMichael Kruse       case 'e':
83*658eb9e1SMichael Kruse         expt = optarg;
84*658eb9e1SMichael Kruse         break;
85*658eb9e1SMichael Kruse       default:
86*658eb9e1SMichael Kruse         fprintf(stderr, "Usage: rsakey [-e <expt>] <modbits> [<outfile>]\n");
87*658eb9e1SMichael Kruse         return 1;
88*658eb9e1SMichael Kruse     }
89*658eb9e1SMichael Kruse   }
90*658eb9e1SMichael Kruse 
91*658eb9e1SMichael Kruse   if (optind >= argc) {
92*658eb9e1SMichael Kruse     fprintf(stderr, "Error:  You must specify the number of modulus bits.\n");
93*658eb9e1SMichael Kruse     fprintf(stderr, "Usage: rsakey [-e <expt>] <modbits> [<outfile>]\n");
94*658eb9e1SMichael Kruse     return 1;
95*658eb9e1SMichael Kruse   }
96*658eb9e1SMichael Kruse   modbits = (int)strtol(argv[optind++], NULL, 0);
97*658eb9e1SMichael Kruse   if (modbits < CHAR_BIT) {
98*658eb9e1SMichael Kruse     fprintf(stderr, "Error:  Invalid value for number of modulus bits.\n");
99*658eb9e1SMichael Kruse     return 1;
100*658eb9e1SMichael Kruse   }
101*658eb9e1SMichael Kruse   if (modbits % 2 == 1) ++modbits;
102*658eb9e1SMichael Kruse 
103*658eb9e1SMichael Kruse   /* Check if output file is specified */
104*658eb9e1SMichael Kruse   if (optind < argc) {
105*658eb9e1SMichael Kruse     if ((ofp = fopen(argv[optind], "wt")) == NULL) {
106*658eb9e1SMichael Kruse       fprintf(stderr,
107*658eb9e1SMichael Kruse               "Error:  Unable to open output file for writing.\n"
108*658eb9e1SMichael Kruse               " - Filename: %s\n"
109*658eb9e1SMichael Kruse               " - Error:    %s\n",
110*658eb9e1SMichael Kruse               argv[optind], strerror(errno));
111*658eb9e1SMichael Kruse       return 1;
112*658eb9e1SMichael Kruse     }
113*658eb9e1SMichael Kruse   }
114*658eb9e1SMichael Kruse 
115*658eb9e1SMichael Kruse   if ((res = rsa_key_init(&the_key)) != MP_OK) {
116*658eb9e1SMichael Kruse     fprintf(stderr,
117*658eb9e1SMichael Kruse             "Error initializing RSA key structure:\n"
118*658eb9e1SMichael Kruse             " - %s (%d)\n",
119*658eb9e1SMichael Kruse             mp_error_string(res), res);
120*658eb9e1SMichael Kruse     return 1;
121*658eb9e1SMichael Kruse   }
122*658eb9e1SMichael Kruse 
123*658eb9e1SMichael Kruse   /* If specified, try to load the key exponent */
124*658eb9e1SMichael Kruse   if (expt != NULL) {
125*658eb9e1SMichael Kruse     if ((res = mp_int_read_string(&(the_key.e), 10, expt)) != MP_OK) {
126*658eb9e1SMichael Kruse       fprintf(stderr,
127*658eb9e1SMichael Kruse               "Error:  Invalid value for encryption exponent.\n"
128*658eb9e1SMichael Kruse               " - %s (%d)\n",
129*658eb9e1SMichael Kruse               mp_error_string(res), res);
130*658eb9e1SMichael Kruse       goto EXIT;
131*658eb9e1SMichael Kruse     }
132*658eb9e1SMichael Kruse   }
133*658eb9e1SMichael Kruse 
134*658eb9e1SMichael Kruse   if ((res = mp_int_randomize(&(the_key.p), (modbits / 2))) != MP_OK) {
135*658eb9e1SMichael Kruse     fprintf(stderr,
136*658eb9e1SMichael Kruse             "Error:  Unable to randomize first prime.\n"
137*658eb9e1SMichael Kruse             " - %s (%d)\n",
138*658eb9e1SMichael Kruse             mp_error_string(res), res);
139*658eb9e1SMichael Kruse     goto EXIT;
140*658eb9e1SMichael Kruse   }
141*658eb9e1SMichael Kruse   fprintf(stderr, "p: ");
142*658eb9e1SMichael Kruse   find_prime(&(the_key.p), stderr);
143*658eb9e1SMichael Kruse 
144*658eb9e1SMichael Kruse   if ((res = mp_int_randomize(&(the_key.q), (modbits / 2))) != MP_OK) {
145*658eb9e1SMichael Kruse     fprintf(stderr,
146*658eb9e1SMichael Kruse             "Error:  Unable to randomize second prime.\n"
147*658eb9e1SMichael Kruse             " - %s (%d)\n",
148*658eb9e1SMichael Kruse             mp_error_string(res), res);
149*658eb9e1SMichael Kruse     goto EXIT;
150*658eb9e1SMichael Kruse   }
151*658eb9e1SMichael Kruse   fprintf(stderr, "\nq: ");
152*658eb9e1SMichael Kruse   find_prime(&(the_key.q), stderr);
153*658eb9e1SMichael Kruse   fputc('\n', stderr);
154*658eb9e1SMichael Kruse 
155*658eb9e1SMichael Kruse   /* Temporarily, the key's "n" field will be (p - 1) * (q - 1) for
156*658eb9e1SMichael Kruse      purposes of computing the decryption exponent.
157*658eb9e1SMichael Kruse    */
158*658eb9e1SMichael Kruse   mp_int_mul(&(the_key.p), &(the_key.q), &(the_key.n));
159*658eb9e1SMichael Kruse   mp_int_sub(&(the_key.n), &(the_key.p), &(the_key.n));
160*658eb9e1SMichael Kruse   mp_int_sub(&(the_key.n), &(the_key.q), &(the_key.n));
161*658eb9e1SMichael Kruse   mp_int_add_value(&(the_key.n), 1, &(the_key.n));
162*658eb9e1SMichael Kruse 
163*658eb9e1SMichael Kruse   if (expt == NULL &&
164*658eb9e1SMichael Kruse       (res = mp_int_randomize(&(the_key.e), (modbits / 2))) != MP_OK) {
165*658eb9e1SMichael Kruse     fprintf(stderr,
166*658eb9e1SMichael Kruse             "Error:  Unable to randomize encryption exponent.\n"
167*658eb9e1SMichael Kruse             " - %s (%d)\n",
168*658eb9e1SMichael Kruse             mp_error_string(res), res);
169*658eb9e1SMichael Kruse     goto EXIT;
170*658eb9e1SMichael Kruse   }
171*658eb9e1SMichael Kruse   while ((res = mp_int_invmod(&(the_key.e), &(the_key.n), &(the_key.d))) !=
172*658eb9e1SMichael Kruse          MP_OK) {
173*658eb9e1SMichael Kruse     if (expt != NULL) {
174*658eb9e1SMichael Kruse       fprintf(stderr,
175*658eb9e1SMichael Kruse               "Error:  Unable to compute decryption exponent.\n"
176*658eb9e1SMichael Kruse               " - %s (%d)\n",
177*658eb9e1SMichael Kruse               mp_error_string(res), res);
178*658eb9e1SMichael Kruse       goto EXIT;
179*658eb9e1SMichael Kruse     }
180*658eb9e1SMichael Kruse     if ((res = mp_int_randomize(&(the_key.e), (modbits / 2))) != MP_OK) {
181*658eb9e1SMichael Kruse       fprintf(stderr,
182*658eb9e1SMichael Kruse               "Error:  Unable to re-randomize encryption exponent.\n"
183*658eb9e1SMichael Kruse               " - %s (%d)\n",
184*658eb9e1SMichael Kruse               mp_error_string(res), res);
185*658eb9e1SMichael Kruse       goto EXIT;
186*658eb9e1SMichael Kruse     }
187*658eb9e1SMichael Kruse   }
188*658eb9e1SMichael Kruse 
189*658eb9e1SMichael Kruse   /* Recompute the real modulus, now that exponents are done. */
190*658eb9e1SMichael Kruse   mp_int_mul(&(the_key.p), &(the_key.q), &(the_key.n));
191*658eb9e1SMichael Kruse 
192*658eb9e1SMichael Kruse   /* Write completed key to the specified output file */
193*658eb9e1SMichael Kruse   rsa_key_write(&the_key, ofp);
194*658eb9e1SMichael Kruse 
195*658eb9e1SMichael Kruse EXIT:
196*658eb9e1SMichael Kruse   fclose(ofp);
197*658eb9e1SMichael Kruse   rsa_key_clear(&the_key);
198*658eb9e1SMichael Kruse   return 0;
199*658eb9e1SMichael Kruse }
200*658eb9e1SMichael Kruse 
randomize(unsigned char * buf,size_t len)201*658eb9e1SMichael Kruse int randomize(unsigned char *buf, size_t len) {
202*658eb9e1SMichael Kruse   FILE *rnd = fopen("/dev/random", "rb");
203*658eb9e1SMichael Kruse   size_t nr;
204*658eb9e1SMichael Kruse 
205*658eb9e1SMichael Kruse   if (rnd == NULL) return -1;
206*658eb9e1SMichael Kruse 
207*658eb9e1SMichael Kruse   nr = fread(buf, sizeof(*buf), len, rnd);
208*658eb9e1SMichael Kruse   fclose(rnd);
209*658eb9e1SMichael Kruse 
210*658eb9e1SMichael Kruse   return (int)nr;
211*658eb9e1SMichael Kruse }
212*658eb9e1SMichael Kruse 
mp_int_randomize(mp_int a,mp_size n_bits)213*658eb9e1SMichael Kruse mp_result mp_int_randomize(mp_int a, mp_size n_bits) {
214*658eb9e1SMichael Kruse   mp_size n_bytes = (n_bits + CHAR_BIT - 1) / CHAR_BIT;
215*658eb9e1SMichael Kruse   unsigned char *buf;
216*658eb9e1SMichael Kruse   mp_result res = MP_OK;
217*658eb9e1SMichael Kruse 
218*658eb9e1SMichael Kruse   if ((buf = malloc(n_bytes)) == NULL) return MP_MEMORY;
219*658eb9e1SMichael Kruse 
220*658eb9e1SMichael Kruse   if ((mp_size)randomize(buf, n_bytes) != n_bytes) {
221*658eb9e1SMichael Kruse     res = MP_TRUNC;
222*658eb9e1SMichael Kruse     goto CLEANUP;
223*658eb9e1SMichael Kruse   }
224*658eb9e1SMichael Kruse 
225*658eb9e1SMichael Kruse   /* Clear bits beyond the number requested */
226*658eb9e1SMichael Kruse   if (n_bits % CHAR_BIT != 0) {
227*658eb9e1SMichael Kruse     unsigned char b_mask = (1 << (n_bits % CHAR_BIT)) - 1;
228*658eb9e1SMichael Kruse     unsigned char t_mask = (1 << (n_bits % CHAR_BIT)) >> 1;
229*658eb9e1SMichael Kruse 
230*658eb9e1SMichael Kruse     buf[0] &= b_mask;
231*658eb9e1SMichael Kruse     buf[0] |= t_mask;
232*658eb9e1SMichael Kruse   }
233*658eb9e1SMichael Kruse 
234*658eb9e1SMichael Kruse   /* Set low-order bit to insure value is odd */
235*658eb9e1SMichael Kruse   buf[n_bytes - 1] |= 1;
236*658eb9e1SMichael Kruse 
237*658eb9e1SMichael Kruse   res = mp_int_read_unsigned(a, buf, n_bytes);
238*658eb9e1SMichael Kruse 
239*658eb9e1SMichael Kruse CLEANUP:
240*658eb9e1SMichael Kruse   memset(buf, 0, n_bytes);
241*658eb9e1SMichael Kruse   free(buf);
242*658eb9e1SMichael Kruse 
243*658eb9e1SMichael Kruse   return res;
244*658eb9e1SMichael Kruse }
245*658eb9e1SMichael Kruse 
find_prime(mp_int seed,FILE * fb)246*658eb9e1SMichael Kruse mp_result find_prime(mp_int seed, FILE *fb) {
247*658eb9e1SMichael Kruse   mp_result res;
248*658eb9e1SMichael Kruse   int count = 0;
249*658eb9e1SMichael Kruse 
250*658eb9e1SMichael Kruse   if (mp_int_is_even(seed))
251*658eb9e1SMichael Kruse     if ((res = mp_int_add_value(seed, 1, seed)) != MP_OK) return res;
252*658eb9e1SMichael Kruse 
253*658eb9e1SMichael Kruse   while ((res = mp_int_is_prime(seed)) == MP_FALSE) {
254*658eb9e1SMichael Kruse     ++count;
255*658eb9e1SMichael Kruse 
256*658eb9e1SMichael Kruse     if (fb != NULL && (count % 50) == 0) fputc('.', fb);
257*658eb9e1SMichael Kruse 
258*658eb9e1SMichael Kruse     if ((res = mp_int_add_value(seed, 2, seed)) != MP_OK) return res;
259*658eb9e1SMichael Kruse   }
260*658eb9e1SMichael Kruse 
261*658eb9e1SMichael Kruse   if (res == MP_TRUE && fb != NULL) fputc('+', fb);
262*658eb9e1SMichael Kruse 
263*658eb9e1SMichael Kruse   return res;
264*658eb9e1SMichael Kruse }
265*658eb9e1SMichael Kruse 
rsa_key_init(rsa_key * kp)266*658eb9e1SMichael Kruse mp_result rsa_key_init(rsa_key *kp) {
267*658eb9e1SMichael Kruse   mp_int_init(&(kp->p));
268*658eb9e1SMichael Kruse   mp_int_init(&(kp->q));
269*658eb9e1SMichael Kruse   mp_int_init(&(kp->n));
270*658eb9e1SMichael Kruse   mp_int_init(&(kp->e));
271*658eb9e1SMichael Kruse   mp_int_init(&(kp->d));
272*658eb9e1SMichael Kruse 
273*658eb9e1SMichael Kruse   return MP_OK;
274*658eb9e1SMichael Kruse }
275*658eb9e1SMichael Kruse 
rsa_key_clear(rsa_key * kp)276*658eb9e1SMichael Kruse void rsa_key_clear(rsa_key *kp) {
277*658eb9e1SMichael Kruse   mp_int_clear(&(kp->p));
278*658eb9e1SMichael Kruse   mp_int_clear(&(kp->q));
279*658eb9e1SMichael Kruse   mp_int_clear(&(kp->n));
280*658eb9e1SMichael Kruse   mp_int_clear(&(kp->e));
281*658eb9e1SMichael Kruse   mp_int_clear(&(kp->d));
282*658eb9e1SMichael Kruse }
283*658eb9e1SMichael Kruse 
rsa_key_write(rsa_key * kp,FILE * ofp)284*658eb9e1SMichael Kruse void rsa_key_write(rsa_key *kp, FILE *ofp) {
285*658eb9e1SMichael Kruse   int len;
286*658eb9e1SMichael Kruse   char *obuf;
287*658eb9e1SMichael Kruse 
288*658eb9e1SMichael Kruse   len = mp_int_string_len(&(kp->n), 10);
289*658eb9e1SMichael Kruse   obuf = malloc(len);
290*658eb9e1SMichael Kruse   mp_int_to_string(&(kp->p), 10, obuf, len);
291*658eb9e1SMichael Kruse   fprintf(ofp, "p = %s\n", obuf);
292*658eb9e1SMichael Kruse   mp_int_to_string(&(kp->q), 10, obuf, len);
293*658eb9e1SMichael Kruse   fprintf(ofp, "q = %s\n", obuf);
294*658eb9e1SMichael Kruse   mp_int_to_string(&(kp->e), 10, obuf, len);
295*658eb9e1SMichael Kruse   fprintf(ofp, "e = %s\n", obuf);
296*658eb9e1SMichael Kruse   mp_int_to_string(&(kp->d), 10, obuf, len);
297*658eb9e1SMichael Kruse   fprintf(ofp, "d = %s\n", obuf);
298*658eb9e1SMichael Kruse   mp_int_to_string(&(kp->n), 10, obuf, len);
299*658eb9e1SMichael Kruse   fprintf(ofp, "n = %s\n", obuf);
300*658eb9e1SMichael Kruse 
301*658eb9e1SMichael Kruse   free(obuf);
302*658eb9e1SMichael Kruse }
303*658eb9e1SMichael Kruse 
304*658eb9e1SMichael Kruse /* Here there be dragons */
305