2 * rsa.c RSA Public and Private key generation functions,
3 * RSA encrypt and decrypt functions.
5 * Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 * Copyright (C) 1997 - 2000 Pekka Riikonen
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * Created: Sat Mar 1 13:26:45 1997 pekka
21 * RSA public key cryptographic algorithm used in this distribution is:
28 * Public key exponent:
29 * e relatively prime to (p-1) * (q-1)
30 * Private key exponent:
31 * d = e ^ -1 mod ((p-1) * (q-1))
38 * This code is based on SSH's (Secure Shell), PGP's (Pretty Good Privacy)
39 * and RSAREF Toolkit's RSA source codes. They all were a big help for me.
41 * I also suggest reading Bruce Schneier's; Applied Cryptography, Second
42 * Edition, John Wiley & Sons, Inc. 1996. This book deals about RSA and
43 * everything else too about cryptography.
47 #include "silcincludes.h"
51 * SILC PKCS API for RSA
54 /* Generates RSA key pair. */
56 SILC_PKCS_API_INIT(rsa)
58 unsigned int prime_bits = keylen / 2;
61 printf("Generating RSA Public and Private keys, might take a while...\n");
68 printf("Finding p: ");
69 silc_math_gen_prime(&p, prime_bits, TRUE);
71 printf("\nFinding q: ");
72 silc_math_gen_prime(&q, prime_bits, TRUE);
74 if ((silc_mp_cmp(&p, &q)) == 0) {
75 printf("\nFound equal primes, not good, retrying...\n");
79 /* If p is smaller than q, switch them */
80 if ((silc_mp_cmp(&p, &q)) > 0) {
84 silc_mp_set(&hlp, &p);
86 silc_mp_set(&q, &hlp);
91 /* Generate the actual keys */
92 rsa_generate_keys((RsaKey *)context, keylen, &p, &q);
97 printf("\nKeys generated succesfully.\n");
102 SILC_PKCS_API_CLEAR_KEYS(rsa)
104 rsa_clear_keys((RsaKey *)context);
107 /* Returns SILC style encoded RSA public key. */
109 SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
111 RsaKey *key = (RsaKey *)context;
112 unsigned char *e, *n, *ret;
113 unsigned int e_len, n_len;
114 unsigned char tmp[2];
116 e = silc_mp_mp2bin(&key->e, &e_len);
117 n = silc_mp_mp2bin(&key->n, &n_len);
119 *ret_len = e_len + 2 + n_len + 2;
120 ret = silc_calloc(*ret_len, sizeof(unsigned char));
122 /* Put the length of the e. */
128 memcpy(ret + 2, e, e_len);
130 /* Put the length of the n. */
133 memcpy(ret + 2 + e_len, tmp, 2);
136 memcpy(ret + 2 + e_len + 2, n, n_len);
146 /* Returns SILC style encoded RSA private key. Public key is always
147 returned in private key as well. Public keys are often derived
148 directly from private key. */
150 SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
152 RsaKey *key = (RsaKey *)context;
153 unsigned char *e, *n, *d, *ret;
154 unsigned int e_len, n_len, d_len;
155 unsigned char tmp[2];
157 e = silc_mp_mp2bin(&key->e, &e_len);
158 n = silc_mp_mp2bin(&key->n, &n_len);
159 d = silc_mp_mp2bin(&key->d, &d_len);
161 *ret_len = e_len + 2 + n_len + 2 + d_len + 2;
162 ret = silc_calloc(*ret_len, sizeof(unsigned char));
164 /* Put the length of the e. */
170 memcpy(ret + 2, e, e_len);
172 /* Put the length of the n. */
175 memcpy(ret + 2 + e_len, tmp, 2);
178 memcpy(ret + 2 + e_len + 2, n, n_len);
180 /* Put the length of the d. */
183 memcpy(ret + 2 + e_len + 2 + n_len, tmp, 2);
186 memcpy(ret + 2 + e_len + 2 + n_len + 2, d, d_len);
200 SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
202 RsaKey *key = (RsaKey *)context;
203 unsigned char tmp[2];
204 unsigned short e_len, n_len;
206 silc_mp_init(&key->e);
207 silc_mp_init(&key->n);
209 memcpy(tmp, key_data, 2);
210 e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
211 if (e_len > key_len) {
212 silc_mp_clear(&key->e);
213 silc_mp_clear(&key->n);
217 silc_mp_bin2mp(key_data + 2, e_len, &key->e);
219 memcpy(tmp, key_data + 2 + e_len, 2);
220 n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
221 if (e_len + n_len > key_len) {
222 silc_mp_clear(&key->e);
223 silc_mp_clear(&key->n);
227 silc_mp_bin2mp(key_data + 2 + e_len + 2, n_len, &key->n);
232 /* Set private key. This derives the public key from the private
233 key and sets the public key as well. Public key should not be set
234 already and should not be set after setting private key. */
236 SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
238 RsaKey *key = (RsaKey *)context;
239 unsigned char tmp[2];
240 unsigned short e_len, n_len, d_len;
242 silc_mp_init(&key->e);
243 silc_mp_init(&key->n);
244 silc_mp_init(&key->d);
246 memcpy(tmp, key_data, 2);
247 e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
248 if (e_len > key_len) {
249 silc_mp_clear(&key->e);
250 silc_mp_clear(&key->n);
254 silc_mp_bin2mp(key_data + 2, e_len, &key->e);
256 memcpy(tmp, key_data + 2 + e_len, 2);
257 n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
258 if (e_len + n_len > key_len) {
259 silc_mp_clear(&key->e);
260 silc_mp_clear(&key->n);
264 silc_mp_bin2mp(key_data + 2 + e_len + 2, n_len, &key->n);
266 memcpy(tmp, key_data + 2 + e_len + 2 + n_len, 2);
267 d_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
268 if (e_len + n_len + d_len > key_len) {
269 silc_mp_clear(&key->e);
270 silc_mp_clear(&key->n);
274 silc_mp_bin2mp(key_data + 2 + e_len + 2 + n_len + 2, d_len, &key->d);
279 SILC_PKCS_API_CONTEXT_LEN(rsa)
281 return sizeof(RsaKey);
284 SILC_PKCS_API_DATA_CONTEXT_LEN(rsa)
286 return sizeof(RsaDataContext);
289 SILC_PKCS_API_SET_ARG(rsa)
291 RsaDataContext *data_ctx = (RsaDataContext *)data_context;
318 SILC_PKCS_API_ENCRYPT(rsa)
320 RsaKey *key = (RsaKey *)context;
325 silc_mp_init_set_ui(&mp_tmp, 0);
326 silc_mp_init_set_ui(&mp_dst, 0);
328 /* Format the data into MP int */
329 for (i = 0; i < src_len; i++) {
330 silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
331 silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
334 silc_mp_out_str(stderr, 16, &mp_tmp);
337 rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->e, &key->n);
339 fprintf(stderr, "\n");
340 silc_mp_out_str(stderr, 16, &mp_dst);
342 tmplen = (1024 + 7) / 8;
344 /* Format the MP int back into data */
345 for (i = tmplen; i > 0; i--) {
346 dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
347 silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
351 silc_mp_clear(&mp_tmp);
352 silc_mp_clear(&mp_dst);
357 SILC_PKCS_API_DECRYPT(rsa)
359 RsaKey *key = (RsaKey *)context;
364 silc_mp_init_set_ui(&mp_tmp, 0);
365 silc_mp_init_set_ui(&mp_dst, 0);
367 /* Format the data into MP int */
368 for (i = 0; i < src_len; i++) {
369 silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
370 silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
373 silc_mp_out_str(stderr, 16, &mp_tmp);
376 rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->d, &key->n);
378 fprintf(stderr, "\n");
379 silc_mp_out_str(stderr, 16, &mp_dst);
381 tmplen = (1024 + 7) / 8;
383 /* Format the MP int back into data */
384 for (i = tmplen; i > 0; i--) {
385 dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
386 silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
390 silc_mp_clear(&mp_tmp);
391 silc_mp_clear(&mp_dst);
396 SILC_PKCS_API_SIGN(rsa)
398 RsaKey *key = (RsaKey *)context;
403 silc_mp_init_set_ui(&mp_tmp, 0);
404 silc_mp_init_set_ui(&mp_dst, 0);
406 /* Format the data into MP int */
407 for (i = 0; i < src_len; i++) {
408 silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
409 silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
413 rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->d, &key->n);
415 tmplen = (1024 + 7) / 8;
417 /* Format the MP int back into data */
418 for (i = tmplen; i > 0; i--) {
419 dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
420 silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
424 silc_mp_clear(&mp_tmp);
425 silc_mp_clear(&mp_dst);
430 SILC_PKCS_API_VERIFY(rsa)
432 RsaKey *key = (RsaKey *)context;
434 SilcInt mp_tmp, mp_tmp2;
437 silc_mp_init_set_ui(&mp_tmp, 0);
438 silc_mp_init_set_ui(&mp_tmp2, 0);
439 silc_mp_init_set_ui(&mp_dst, 0);
441 /* Format the signature into MP int */
442 for (i = 0; i < signature_len; i++) {
443 silc_mp_mul_2exp(&mp_tmp2, &mp_tmp2, 8);
444 silc_mp_add_ui(&mp_tmp2, &mp_tmp2, signature[i]);
448 rsa_en_de_crypt(&mp_dst, &mp_tmp2, &key->e, &key->n);
450 /* Format the data into MP int */
451 for (i = 0; i < data_len; i++) {
452 silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
453 silc_mp_add_ui(&mp_tmp, &mp_tmp, data[i]);
459 if ((silc_mp_cmp(&mp_tmp, &mp_dst)) != 0)
462 silc_mp_clear(&mp_tmp);
463 silc_mp_clear(&mp_tmp2);
464 silc_mp_clear(&mp_dst);
469 /* Generates RSA public and private keys. Primes p and q that are used
470 to compute the modulus n has to be generated before calling this. They
471 are then sent as argument for the function. */
473 void rsa_generate_keys(RsaKey *key, unsigned int bits,
474 SilcInt *p, SilcInt *q)
480 /* Initialize variables */
481 silc_mp_init(&key->p);
482 silc_mp_init(&key->q);
483 silc_mp_init(&key->n);
484 silc_mp_init(&key->e);
485 silc_mp_init(&key->d);
493 silc_mp_set(&key->p, p);
494 silc_mp_set(&key->q, q);
496 /* Compute modulus, n = p * q */
497 silc_mp_mul(&key->n, &key->p, &key->q);
499 /* phi = (p - 1) * (q - 1) */
500 silc_mp_sub_ui(&pm1, &key->p, 1);
501 silc_mp_sub_ui(&qm1, &key->q, 1);
502 silc_mp_mul(&phi, &pm1, &qm1);
504 /* Set e, the public exponent. We try to use same public exponent
505 for all keys. Also, to make encryption faster we use small
507 silc_mp_set_ui(&key->e, 127);
509 /* See if e is relatively prime to phi. gcd == greates common divisor,
510 if gcd equals 1 they are relatively prime. */
511 silc_mp_gcd(&hlp, &key->e, &phi);
512 if((silc_mp_cmp_ui(&hlp, 1)) > 0) {
513 silc_mp_add_ui(&key->e, &key->e, 2);
517 /* Find d, the private exponent. First we do phi / 2, to get it a
519 silc_mp_div_ui(&dq, &phi, 2);
520 silc_mp_modinv(&key->d, &key->e, &dq);
529 /* Clears whole key structure. */
531 void rsa_clear_keys(RsaKey *key)
534 silc_mp_clear(&key->p);
535 silc_mp_clear(&key->q);
536 silc_mp_clear(&key->n);
537 silc_mp_clear(&key->e);
538 silc_mp_clear(&key->d);
541 /* RSA encrypt/decrypt function. cm = ciphertext or plaintext,
542 mc = plaintext or ciphertext, expo = public or private exponent,
545 Encrypt: c = m ^ e mod n,
546 Decrypt: m = c ^ d mod n
549 void rsa_en_de_crypt(SilcInt *cm, SilcInt *mc,
550 SilcInt *expo, SilcInt *modu)
552 silc_mp_powm(cm, mc, expo, modu);