| /* rsa.c - RSA implementation |
| * Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn) |
| * Copyright (C) 2000, 2001, 2002, 2003, 2008 Free Software Foundation, Inc. |
| * |
| * This file is part of Libgcrypt. |
| * |
| * Libgcrypt is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Lesser General Public License as |
| * published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * Libgcrypt is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| /* This code uses an algorithm protected by U.S. Patent #4,405,829 |
| which expired on September 20, 2000. The patent holder placed that |
| patent into the public domain on Sep 6th, 2000. |
| */ |
| |
| #include <config.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include "g10lib.h" |
| #include "mpi.h" |
| #include "cipher.h" |
| |
| |
| typedef struct |
| { |
| gcry_mpi_t n; /* modulus */ |
| gcry_mpi_t e; /* exponent */ |
| } RSA_public_key; |
| |
| |
| typedef struct |
| { |
| gcry_mpi_t n; /* public modulus */ |
| gcry_mpi_t e; /* public exponent */ |
| gcry_mpi_t d; /* exponent */ |
| gcry_mpi_t p; /* prime p. */ |
| gcry_mpi_t q; /* prime q. */ |
| gcry_mpi_t u; /* inverse of p mod q. */ |
| } RSA_secret_key; |
| |
| |
| /* A sample 1024 bit RSA key used for the selftests. */ |
| static const char sample_secret_key[] = |
| "(private-key" |
| " (rsa" |
| " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" |
| " 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" |
| " ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" |
| " 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)" |
| " (e #010001#)" |
| " (d #046129f2489d71579be0a75fe029bd6cdb574ebf57ea8a5b0fda942cab943b11" |
| " 7d7bb95e5d28875e0f9fc5fcc06a72f6d502464dabded78ef6b716177b83d5bd" |
| " c543dc5d3fed932e59f5897e92e6f58a0f33424106a3b6fa2cbf877510e4ac21" |
| " c3ee47851e97d12996222ac3566d4ccb0b83d164074abf7de655fc2446da1781#)" |
| " (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" |
| " fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)" |
| " (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9" |
| " 35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)" |
| " (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" |
| " ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)))"; |
| /* A sample 1024 bit RSA key used for the selftests (public only). */ |
| static const char sample_public_key[] = |
| "(public-key" |
| " (rsa" |
| " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" |
| " 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" |
| " ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" |
| " 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)" |
| " (e #010001#)))"; |
| |
| |
| |
| |
| static int test_keys (RSA_secret_key *sk, unsigned nbits); |
| static int check_secret_key (RSA_secret_key *sk); |
| static void public (gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *skey); |
| static void secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey); |
| |
| |
| /* Check that a freshly generated key actually works. Returns 0 on success. */ |
| static int |
| test_keys (RSA_secret_key *sk, unsigned int nbits) |
| { |
| int result = -1; /* Default to failure. */ |
| RSA_public_key pk; |
| gcry_mpi_t plaintext = gcry_mpi_new (nbits); |
| gcry_mpi_t ciphertext = gcry_mpi_new (nbits); |
| gcry_mpi_t decr_plaintext = gcry_mpi_new (nbits); |
| gcry_mpi_t signature = gcry_mpi_new (nbits); |
| |
| /* Put the relevant parameters into a public key structure. */ |
| pk.n = sk->n; |
| pk.e = sk->e; |
| |
| /* Create a random plaintext. */ |
| gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); |
| |
| /* Encrypt using the public key. */ |
| public (ciphertext, plaintext, &pk); |
| |
| /* Check that the cipher text does not match the plaintext. */ |
| if (!gcry_mpi_cmp (ciphertext, plaintext)) |
| goto leave; /* Ciphertext is identical to the plaintext. */ |
| |
| /* Decrypt using the secret key. */ |
| secret (decr_plaintext, ciphertext, sk); |
| |
| /* Check that the decrypted plaintext matches the original plaintext. */ |
| if (gcry_mpi_cmp (decr_plaintext, plaintext)) |
| goto leave; /* Plaintext does not match. */ |
| |
| /* Create another random plaintext as data for signature checking. */ |
| gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); |
| |
| /* Use the RSA secret function to create a signature of the plaintext. */ |
| secret (signature, plaintext, sk); |
| |
| /* Use the RSA public function to verify this signature. */ |
| public (decr_plaintext, signature, &pk); |
| if (gcry_mpi_cmp (decr_plaintext, plaintext)) |
| goto leave; /* Signature does not match. */ |
| |
| /* Modify the signature and check that the signing fails. */ |
| gcry_mpi_add_ui (signature, signature, 1); |
| public (decr_plaintext, signature, &pk); |
| if (!gcry_mpi_cmp (decr_plaintext, plaintext)) |
| goto leave; /* Signature matches but should not. */ |
| |
| result = 0; /* All tests succeeded. */ |
| |
| leave: |
| gcry_mpi_release (signature); |
| gcry_mpi_release (decr_plaintext); |
| gcry_mpi_release (ciphertext); |
| gcry_mpi_release (plaintext); |
| return result; |
| } |
| |
| |
| /* Callback used by the prime generation to test whether the exponent |
| is suitable. Returns 0 if the test has been passed. */ |
| static int |
| check_exponent (void *arg, gcry_mpi_t a) |
| { |
| gcry_mpi_t e = arg; |
| gcry_mpi_t tmp; |
| int result; |
| |
| mpi_sub_ui (a, a, 1); |
| tmp = _gcry_mpi_alloc_like (a); |
| result = !gcry_mpi_gcd(tmp, e, a); /* GCD is not 1. */ |
| gcry_mpi_release (tmp); |
| mpi_add_ui (a, a, 1); |
| return result; |
| } |
| |
| /**************** |
| * Generate a key pair with a key of size NBITS. |
| * USE_E = 0 let Libcgrypt decide what exponent to use. |
| * = 1 request the use of a "secure" exponent; this is required by some |
| * specification to be 65537. |
| * > 2 Use this public exponent. If the given exponent |
| * is not odd one is internally added to it. |
| * TRANSIENT_KEY: If true, generate the primes using the standard RNG. |
| * Returns: 2 structures filled with all needed values |
| */ |
| static gpg_err_code_t |
| generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, |
| int transient_key) |
| { |
| gcry_mpi_t p, q; /* the two primes */ |
| gcry_mpi_t d; /* the private key */ |
| gcry_mpi_t u; |
| gcry_mpi_t t1, t2; |
| gcry_mpi_t n; /* the public key */ |
| gcry_mpi_t e; /* the exponent */ |
| gcry_mpi_t phi; /* helper: (p-1)(q-1) */ |
| gcry_mpi_t g; |
| gcry_mpi_t f; |
| gcry_random_level_t random_level; |
| |
| if (fips_mode ()) |
| { |
| if (nbits < 1024) |
| return GPG_ERR_INV_VALUE; |
| if (transient_key) |
| return GPG_ERR_INV_VALUE; |
| } |
| |
| /* The random quality depends on the transient_key flag. */ |
| random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; |
| |
| /* Make sure that nbits is even so that we generate p, q of equal size. */ |
| if ( (nbits&1) ) |
| nbits++; |
| |
| if (use_e == 1) /* Alias for a secure value */ |
| use_e = 65537; /* as demanded by Sphinx. */ |
| |
| /* Public exponent: |
| In general we use 41 as this is quite fast and more secure than the |
| commonly used 17. Benchmarking the RSA verify function |
| with a 1024 bit key yields (2001-11-08): |
| e=17 0.54 ms |
| e=41 0.75 ms |
| e=257 0.95 ms |
| e=65537 1.80 ms |
| */ |
| e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); |
| if (!use_e) |
| mpi_set_ui (e, 41); /* This is a reasonable secure and fast value */ |
| else |
| { |
| use_e |= 1; /* make sure this is odd */ |
| mpi_set_ui (e, use_e); |
| } |
| |
| n = gcry_mpi_new (nbits); |
| |
| p = q = NULL; |
| do |
| { |
| /* select two (very secret) primes */ |
| if (p) |
| gcry_mpi_release (p); |
| if (q) |
| gcry_mpi_release (q); |
| if (use_e) |
| { /* Do an extra test to ensure that the given exponent is |
| suitable. */ |
| p = _gcry_generate_secret_prime (nbits/2, random_level, |
| check_exponent, e); |
| q = _gcry_generate_secret_prime (nbits/2, random_level, |
| check_exponent, e); |
| } |
| else |
| { /* We check the exponent later. */ |
| p = _gcry_generate_secret_prime (nbits/2, random_level, NULL, NULL); |
| q = _gcry_generate_secret_prime (nbits/2, random_level, NULL, NULL); |
| } |
| if (mpi_cmp (p, q) > 0 ) /* p shall be smaller than q (for calc of u)*/ |
| mpi_swap(p,q); |
| /* calculate the modulus */ |
| mpi_mul( n, p, q ); |
| } |
| while ( mpi_get_nbits(n) != nbits ); |
| |
| /* calculate Euler totient: phi = (p-1)(q-1) */ |
| t1 = mpi_alloc_secure( mpi_get_nlimbs(p) ); |
| t2 = mpi_alloc_secure( mpi_get_nlimbs(p) ); |
| phi = gcry_mpi_snew ( nbits ); |
| g = gcry_mpi_snew ( nbits ); |
| f = gcry_mpi_snew ( nbits ); |
| mpi_sub_ui( t1, p, 1 ); |
| mpi_sub_ui( t2, q, 1 ); |
| mpi_mul( phi, t1, t2 ); |
| gcry_mpi_gcd(g, t1, t2); |
| mpi_fdiv_q(f, phi, g); |
| |
| while (!gcry_mpi_gcd(t1, e, phi)) /* (while gcd is not 1) */ |
| { |
| if (use_e) |
| BUG (); /* The prime generator already made sure that we |
| never can get to here. */ |
| mpi_add_ui (e, e, 2); |
| } |
| |
| /* calculate the secret key d = e^1 mod phi */ |
| d = gcry_mpi_snew ( nbits ); |
| mpi_invm(d, e, f ); |
| /* calculate the inverse of p and q (used for chinese remainder theorem)*/ |
| u = gcry_mpi_snew ( nbits ); |
| mpi_invm(u, p, q ); |
| |
| if( DBG_CIPHER ) |
| { |
| log_mpidump(" p= ", p ); |
| log_mpidump(" q= ", q ); |
| log_mpidump("phi= ", phi ); |
| log_mpidump(" g= ", g ); |
| log_mpidump(" f= ", f ); |
| log_mpidump(" n= ", n ); |
| log_mpidump(" e= ", e ); |
| log_mpidump(" d= ", d ); |
| log_mpidump(" u= ", u ); |
| } |
| |
| gcry_mpi_release (t1); |
| gcry_mpi_release (t2); |
| gcry_mpi_release (phi); |
| gcry_mpi_release (f); |
| gcry_mpi_release (g); |
| |
| sk->n = n; |
| sk->e = e; |
| sk->p = p; |
| sk->q = q; |
| sk->d = d; |
| sk->u = u; |
| |
| /* Now we can test our keys. */ |
| if (test_keys (sk, nbits - 64)) |
| { |
| gcry_mpi_release (sk->n); sk->n = NULL; |
| gcry_mpi_release (sk->e); sk->e = NULL; |
| gcry_mpi_release (sk->p); sk->p = NULL; |
| gcry_mpi_release (sk->q); sk->q = NULL; |
| gcry_mpi_release (sk->d); sk->d = NULL; |
| gcry_mpi_release (sk->u); sk->u = NULL; |
| fips_signal_error ("self-test after key generation failed"); |
| return GPG_ERR_SELFTEST_FAILED; |
| } |
| |
| return 0; |
| } |
| |
| |
| /* Helper for generate_x931. */ |
| static gcry_mpi_t |
| gen_x931_parm_xp (unsigned int nbits) |
| { |
| gcry_mpi_t xp; |
| |
| xp = gcry_mpi_snew (nbits); |
| gcry_mpi_randomize (xp, nbits, GCRY_VERY_STRONG_RANDOM); |
| |
| /* The requirement for Xp is: |
| |
| sqrt{2}*2^{nbits-1} <= xp <= 2^{nbits} - 1 |
| |
| We set the two high order bits to 1 to satisfy the lower bound. |
| By using mpi_set_highbit we make sure that the upper bound is |
| satisfied as well. */ |
| mpi_set_highbit (xp, nbits-1); |
| mpi_set_bit (xp, nbits-2); |
| gcry_assert ( mpi_get_nbits (xp) == nbits ); |
| |
| return xp; |
| } |
| |
| |
| /* Helper for generate_x931. */ |
| static gcry_mpi_t |
| gen_x931_parm_xi (void) |
| { |
| gcry_mpi_t xi; |
| |
| xi = gcry_mpi_snew (101); |
| gcry_mpi_randomize (xi, 101, GCRY_VERY_STRONG_RANDOM); |
| mpi_set_highbit (xi, 100); |
| gcry_assert ( mpi_get_nbits (xi) == 101 ); |
| |
| return xi; |
| } |
| |
| |
| |
| /* Variant of the standard key generation code using the algorithm |
| from X9.31. Using this algorithm has the advantage that the |
| generation can be made deterministic which is required for CAVS |
| testing. */ |
| static gpg_err_code_t |
| generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, |
| gcry_sexp_t deriveparms, int *swapped) |
| { |
| gcry_mpi_t p, q; /* The two primes. */ |
| gcry_mpi_t e; /* The public exponent. */ |
| gcry_mpi_t n; /* The public key. */ |
| gcry_mpi_t d; /* The private key */ |
| gcry_mpi_t u; /* The inverse of p and q. */ |
| gcry_mpi_t pm1; /* p - 1 */ |
| gcry_mpi_t qm1; /* q - 1 */ |
| gcry_mpi_t phi; /* Euler totient. */ |
| gcry_mpi_t f, g; /* Helper. */ |
| |
| *swapped = 0; |
| |
| if (e_value == 1) /* Alias for a secure value. */ |
| e_value = 65537; |
| |
| /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */ |
| if (nbits < 1024 || (nbits % 256)) |
| return GPG_ERR_INV_VALUE; |
| |
| /* Point 2: 2 <= bitlength(e) < 2^{k-2} |
| Note that we do not need to check the upper bound because we use |
| an unsigned long for E and thus there is no way for E to reach |
| that limit. */ |
| if (e_value < 3) |
| return GPG_ERR_INV_VALUE; |
| |
| /* Our implementaion requires E to be odd. */ |
| if (!(e_value & 1)) |
| return GPG_ERR_INV_VALUE; |
| |
| /* Point 3: e > 0 or e 0 if it is to be randomly generated. |
| We support only a fixed E and thus there is no need for an extra test. */ |
| |
| |
| /* Compute or extract the derive parameters. */ |
| { |
| gcry_mpi_t xp1 = NULL; |
| gcry_mpi_t xp2 = NULL; |
| gcry_mpi_t xp = NULL; |
| gcry_mpi_t xq1 = NULL; |
| gcry_mpi_t xq2 = NULL; |
| gcry_mpi_t xq = NULL; |
| gcry_mpi_t tmpval; |
| |
| if (!deriveparms) |
| { |
| /* Not given: Generate them. */ |
| xp = gen_x931_parm_xp (nbits/2); |
| /* Make sure that |xp - xq| > 2^{nbits - 100} holds. */ |
| tmpval = gcry_mpi_snew (nbits/2); |
| do |
| { |
| gcry_mpi_release (xq); |
| xq = gen_x931_parm_xp (nbits/2); |
| mpi_sub (tmpval, xp, xq); |
| } |
| while (mpi_get_nbits (tmpval) <= (nbits/2 - 100)); |
| gcry_mpi_release (tmpval); |
| |
| xp1 = gen_x931_parm_xi (); |
| xp2 = gen_x931_parm_xi (); |
| xq1 = gen_x931_parm_xi (); |
| xq2 = gen_x931_parm_xi (); |
| |
| } |
| else |
| { |
| /* Parameters to derive the key are given. */ |
| struct { const char *name; gcry_mpi_t *value; } tbl[] = { |
| { "Xp1", &xp1 }, |
| { "Xp2", &xp2 }, |
| { "Xp", &xp }, |
| { "Xq1", &xq1 }, |
| { "Xq2", &xq2 }, |
| { "Xq", &xq }, |
| { NULL, NULL } |
| }; |
| int idx; |
| gcry_sexp_t oneparm; |
| |
| for (idx=0; tbl[idx].name; idx++) |
| { |
| oneparm = gcry_sexp_find_token (deriveparms, tbl[idx].name, 0); |
| if (oneparm) |
| { |
| *tbl[idx].value = gcry_sexp_nth_mpi (oneparm, 1, |
| GCRYMPI_FMT_USG); |
| gcry_sexp_release (oneparm); |
| } |
| } |
| for (idx=0; tbl[idx].name; idx++) |
| if (!*tbl[idx].value) |
| break; |
| if (tbl[idx].name) |
| { |
| /* At least one parameter is missing. */ |
| for (idx=0; tbl[idx].name; idx++) |
| gcry_mpi_release (*tbl[idx].value); |
| return GPG_ERR_MISSING_VALUE; |
| } |
| } |
| |
| e = mpi_alloc_set_ui (e_value); |
| |
| /* Find two prime numbers. */ |
| p = _gcry_derive_x931_prime (xp, xp1, xp2, e, NULL, NULL); |
| q = _gcry_derive_x931_prime (xq, xq1, xq2, e, NULL, NULL); |
| gcry_mpi_release (xp); xp = NULL; |
| gcry_mpi_release (xp1); xp1 = NULL; |
| gcry_mpi_release (xp2); xp2 = NULL; |
| gcry_mpi_release (xq); xq = NULL; |
| gcry_mpi_release (xq1); xq1 = NULL; |
| gcry_mpi_release (xq2); xq2 = NULL; |
| if (!p || !q) |
| { |
| gcry_mpi_release (p); |
| gcry_mpi_release (q); |
| gcry_mpi_release (e); |
| return GPG_ERR_NO_PRIME; |
| } |
| } |
| |
| |
| /* Compute the public modulus. We make sure that p is smaller than |
| q to allow the use of the CRT. */ |
| if (mpi_cmp (p, q) > 0 ) |
| { |
| mpi_swap (p, q); |
| *swapped = 1; |
| } |
| n = gcry_mpi_new (nbits); |
| mpi_mul (n, p, q); |
| |
| /* Compute the Euler totient: phi = (p-1)(q-1) */ |
| pm1 = gcry_mpi_snew (nbits/2); |
| qm1 = gcry_mpi_snew (nbits/2); |
| phi = gcry_mpi_snew (nbits); |
| mpi_sub_ui (pm1, p, 1); |
| mpi_sub_ui (qm1, q, 1); |
| mpi_mul (phi, pm1, qm1); |
| |
| g = gcry_mpi_snew (nbits); |
| gcry_assert (gcry_mpi_gcd (g, e, phi)); |
| |
| /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */ |
| gcry_mpi_gcd (g, pm1, qm1); |
| f = pm1; pm1 = NULL; |
| gcry_mpi_release (qm1); qm1 = NULL; |
| mpi_fdiv_q (f, phi, g); |
| gcry_mpi_release (phi); phi = NULL; |
| d = g; g = NULL; |
| /* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */ |
| mpi_invm (d, e, f); |
| |
| /* Compute the inverse of p and q. */ |
| u = f; f = NULL; |
| mpi_invm (u, p, q ); |
| |
| if( DBG_CIPHER ) |
| { |
| if (*swapped) |
| log_debug ("p and q are swapped\n"); |
| log_mpidump(" p", p ); |
| log_mpidump(" q", q ); |
| log_mpidump(" n", n ); |
| log_mpidump(" e", e ); |
| log_mpidump(" d", d ); |
| log_mpidump(" u", u ); |
| } |
| |
| |
| sk->n = n; |
| sk->e = e; |
| sk->p = p; |
| sk->q = q; |
| sk->d = d; |
| sk->u = u; |
| |
| /* Now we can test our keys. */ |
| if (test_keys (sk, nbits - 64)) |
| { |
| gcry_mpi_release (sk->n); sk->n = NULL; |
| gcry_mpi_release (sk->e); sk->e = NULL; |
| gcry_mpi_release (sk->p); sk->p = NULL; |
| gcry_mpi_release (sk->q); sk->q = NULL; |
| gcry_mpi_release (sk->d); sk->d = NULL; |
| gcry_mpi_release (sk->u); sk->u = NULL; |
| fips_signal_error ("self-test after key generation failed"); |
| return GPG_ERR_SELFTEST_FAILED; |
| } |
| |
| return 0; |
| } |
| |
| |
| /**************** |
| * Test wether the secret key is valid. |
| * Returns: true if this is a valid key. |
| */ |
| static int |
| check_secret_key( RSA_secret_key *sk ) |
| { |
| int rc; |
| gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 ); |
| |
| mpi_mul(temp, sk->p, sk->q ); |
| rc = mpi_cmp( temp, sk->n ); |
| mpi_free(temp); |
| return !rc; |
| } |
| |
| |
| |
| /**************** |
| * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT. |
| * |
| * c = m^e mod n |
| * |
| * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY. |
| */ |
| static void |
| public(gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *pkey ) |
| { |
| if( output == input ) /* powm doesn't like output and input the same */ |
| { |
| gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs(input)*2 ); |
| mpi_powm( x, input, pkey->e, pkey->n ); |
| mpi_set(output, x); |
| mpi_free(x); |
| } |
| else |
| mpi_powm( output, input, pkey->e, pkey->n ); |
| } |
| |
| #if 0 |
| static void |
| stronger_key_check ( RSA_secret_key *skey ) |
| { |
| gcry_mpi_t t = mpi_alloc_secure ( 0 ); |
| gcry_mpi_t t1 = mpi_alloc_secure ( 0 ); |
| gcry_mpi_t t2 = mpi_alloc_secure ( 0 ); |
| gcry_mpi_t phi = mpi_alloc_secure ( 0 ); |
| |
| /* check that n == p * q */ |
| mpi_mul( t, skey->p, skey->q); |
| if (mpi_cmp( t, skey->n) ) |
| log_info ( "RSA Oops: n != p * q\n" ); |
| |
| /* check that p is less than q */ |
| if( mpi_cmp( skey->p, skey->q ) > 0 ) |
| { |
| log_info ("RSA Oops: p >= q - fixed\n"); |
| _gcry_mpi_swap ( skey->p, skey->q); |
| } |
| |
| /* check that e divides neither p-1 nor q-1 */ |
| mpi_sub_ui(t, skey->p, 1 ); |
| mpi_fdiv_r(t, t, skey->e ); |
| if ( !mpi_cmp_ui( t, 0) ) |
| log_info ( "RSA Oops: e divides p-1\n" ); |
| mpi_sub_ui(t, skey->q, 1 ); |
| mpi_fdiv_r(t, t, skey->e ); |
| if ( !mpi_cmp_ui( t, 0) ) |
| log_info ( "RSA Oops: e divides q-1\n" ); |
| |
| /* check that d is correct */ |
| mpi_sub_ui( t1, skey->p, 1 ); |
| mpi_sub_ui( t2, skey->q, 1 ); |
| mpi_mul( phi, t1, t2 ); |
| gcry_mpi_gcd(t, t1, t2); |
| mpi_fdiv_q(t, phi, t); |
| mpi_invm(t, skey->e, t ); |
| if ( mpi_cmp(t, skey->d ) ) |
| { |
| log_info ( "RSA Oops: d is wrong - fixed\n"); |
| mpi_set (skey->d, t); |
| _gcry_log_mpidump (" fixed d", skey->d); |
| } |
| |
| /* check for correctness of u */ |
| mpi_invm(t, skey->p, skey->q ); |
| if ( mpi_cmp(t, skey->u ) ) |
| { |
| log_info ( "RSA Oops: u is wrong - fixed\n"); |
| mpi_set (skey->u, t); |
| _gcry_log_mpidump (" fixed u", skey->u); |
| } |
| |
| log_info ( "RSA secret key check finished\n"); |
| |
| mpi_free (t); |
| mpi_free (t1); |
| mpi_free (t2); |
| mpi_free (phi); |
| } |
| #endif |
| |
| |
| |
| /**************** |
| * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT. |
| * |
| * m = c^d mod n |
| * |
| * Or faster: |
| * |
| * m1 = c ^ (d mod (p-1)) mod p |
| * m2 = c ^ (d mod (q-1)) mod q |
| * h = u * (m2 - m1) mod q |
| * m = m1 + h * p |
| * |
| * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY. |
| */ |
| static void |
| secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) |
| { |
| if (!skey->p || !skey->q || !skey->u) |
| { |
| mpi_powm (output, input, skey->d, skey->n); |
| } |
| else |
| { |
| gcry_mpi_t m1 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); |
| gcry_mpi_t m2 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); |
| gcry_mpi_t h = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); |
| |
| /* m1 = c ^ (d mod (p-1)) mod p */ |
| mpi_sub_ui( h, skey->p, 1 ); |
| mpi_fdiv_r( h, skey->d, h ); |
| mpi_powm( m1, input, h, skey->p ); |
| /* m2 = c ^ (d mod (q-1)) mod q */ |
| mpi_sub_ui( h, skey->q, 1 ); |
| mpi_fdiv_r( h, skey->d, h ); |
| mpi_powm( m2, input, h, skey->q ); |
| /* h = u * ( m2 - m1 ) mod q */ |
| mpi_sub( h, m2, m1 ); |
| if ( mpi_is_neg( h ) ) |
| mpi_add ( h, h, skey->q ); |
| mpi_mulm( h, skey->u, h, skey->q ); |
| /* m = m2 + h * p */ |
| mpi_mul ( h, h, skey->p ); |
| mpi_add ( output, m1, h ); |
| |
| mpi_free ( h ); |
| mpi_free ( m1 ); |
| mpi_free ( m2 ); |
| } |
| } |
| |
| |
| |
| /* Perform RSA blinding. */ |
| static gcry_mpi_t |
| rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n) |
| { |
| /* A helper. */ |
| gcry_mpi_t a; |
| |
| /* Result. */ |
| gcry_mpi_t y; |
| |
| a = gcry_mpi_snew (gcry_mpi_get_nbits (n)); |
| y = gcry_mpi_snew (gcry_mpi_get_nbits (n)); |
| |
| /* Now we calculate: y = (x * r^e) mod n, where r is the random |
| number, e is the public exponent, x is the non-blinded data and n |
| is the RSA modulus. */ |
| gcry_mpi_powm (a, r, e, n); |
| gcry_mpi_mulm (y, a, x, n); |
| |
| gcry_mpi_release (a); |
| |
| return y; |
| } |
| |
| /* Undo RSA blinding. */ |
| static gcry_mpi_t |
| rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n) |
| { |
| gcry_mpi_t y; |
| |
| y = gcry_mpi_snew (gcry_mpi_get_nbits (n)); |
| |
| /* Here we calculate: y = (x * r^-1) mod n, where x is the blinded |
| decrypted data, ri is the modular multiplicative inverse of r and |
| n is the RSA modulus. */ |
| |
| gcry_mpi_mulm (y, ri, x, n); |
| |
| return y; |
| } |
| |
| /********************************************* |
| ************** interface ****************** |
| *********************************************/ |
| |
| static gcry_err_code_t |
| rsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue, |
| const gcry_sexp_t genparms, |
| gcry_mpi_t *skey, gcry_mpi_t **retfactors, |
| gcry_sexp_t *r_extrainfo) |
| { |
| RSA_secret_key sk; |
| gpg_err_code_t ec; |
| gcry_sexp_t deriveparms; |
| int transient_key = 0; |
| int use_x931 = 0; |
| gcry_sexp_t l1; |
| |
| (void)algo; |
| |
| *retfactors = NULL; /* We don't return them. */ |
| |
| deriveparms = (genparms? |
| gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL); |
| if (!deriveparms) |
| { |
| /* Parse the optional "use-x931" flag. */ |
| l1 = gcry_sexp_find_token (genparms, "use-x931", 0); |
| if (l1) |
| { |
| use_x931 = 1; |
| gcry_sexp_release (l1); |
| } |
| } |
| |
| if (deriveparms || use_x931 || fips_mode ()) |
| { |
| int swapped; |
| ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); |
| gcry_sexp_release (deriveparms); |
| if (!ec && r_extrainfo && swapped) |
| { |
| ec = gcry_sexp_new (r_extrainfo, |
| "(misc-key-info(p-q-swapped))", 0, 1); |
| if (ec) |
| { |
| gcry_mpi_release (sk.n); sk.n = NULL; |
| gcry_mpi_release (sk.e); sk.e = NULL; |
| gcry_mpi_release (sk.p); sk.p = NULL; |
| gcry_mpi_release (sk.q); sk.q = NULL; |
| gcry_mpi_release (sk.d); sk.d = NULL; |
| gcry_mpi_release (sk.u); sk.u = NULL; |
| } |
| } |
| } |
| else |
| { |
| /* Parse the optional "transient-key" flag. */ |
| l1 = gcry_sexp_find_token (genparms, "transient-key", 0); |
| if (l1) |
| { |
| transient_key = 1; |
| gcry_sexp_release (l1); |
| } |
| /* Generate. */ |
| ec = generate_std (&sk, nbits, evalue, transient_key); |
| } |
| |
| if (!ec) |
| { |
| skey[0] = sk.n; |
| skey[1] = sk.e; |
| skey[2] = sk.d; |
| skey[3] = sk.p; |
| skey[4] = sk.q; |
| skey[5] = sk.u; |
| } |
| |
| return ec; |
| } |
| |
| |
| static gcry_err_code_t |
| rsa_generate (int algo, unsigned int nbits, unsigned long evalue, |
| gcry_mpi_t *skey, gcry_mpi_t **retfactors) |
| { |
| return rsa_generate_ext (algo, nbits, evalue, NULL, skey, retfactors, NULL); |
| } |
| |
| |
| static gcry_err_code_t |
| rsa_check_secret_key (int algo, gcry_mpi_t *skey) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| RSA_secret_key sk; |
| |
| (void)algo; |
| |
| sk.n = skey[0]; |
| sk.e = skey[1]; |
| sk.d = skey[2]; |
| sk.p = skey[3]; |
| sk.q = skey[4]; |
| sk.u = skey[5]; |
| |
| if (!sk.p || !sk.q || !sk.u) |
| err = GPG_ERR_NO_OBJ; /* To check the key we need the optional |
| parameters. */ |
| else if (!check_secret_key (&sk)) |
| err = GPG_ERR_PUBKEY_ALGO; |
| |
| return err; |
| } |
| |
| |
| static gcry_err_code_t |
| rsa_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, |
| gcry_mpi_t *pkey, int flags) |
| { |
| RSA_public_key pk; |
| |
| (void)algo; |
| (void)flags; |
| |
| pk.n = pkey[0]; |
| pk.e = pkey[1]; |
| resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.n)); |
| public (resarr[0], data, &pk); |
| |
| return GPG_ERR_NO_ERROR; |
| } |
| |
| |
| static gcry_err_code_t |
| rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, |
| gcry_mpi_t *skey, int flags) |
| { |
| RSA_secret_key sk; |
| gcry_mpi_t r = MPI_NULL; /* Random number needed for blinding. */ |
| gcry_mpi_t ri = MPI_NULL; /* Modular multiplicative inverse of |
| r. */ |
| gcry_mpi_t x = MPI_NULL; /* Data to decrypt. */ |
| gcry_mpi_t y; /* Result. */ |
| |
| (void)algo; |
| |
| /* Extract private key. */ |
| sk.n = skey[0]; |
| sk.e = skey[1]; |
| sk.d = skey[2]; |
| sk.p = skey[3]; /* Optional. */ |
| sk.q = skey[4]; /* Optional. */ |
| sk.u = skey[5]; /* Optional. */ |
| |
| y = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); |
| |
| /* We use blinding by default to mitigate timing attacks which can |
| be practically mounted over the network as shown by Brumley and |
| Boney in 2003. */ |
| if (! (flags & PUBKEY_FLAG_NO_BLINDING)) |
| { |
| /* Initialize blinding. */ |
| |
| /* First, we need a random number r between 0 and n - 1, which |
| is relatively prime to n (i.e. it is neither p nor q). The |
| random number needs to be only unpredictable, thus we employ |
| the gcry_create_nonce function by using GCRY_WEAK_RANDOM with |
| gcry_mpi_randomize. */ |
| r = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); |
| ri = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); |
| |
| gcry_mpi_randomize (r, gcry_mpi_get_nbits (sk.n), GCRY_WEAK_RANDOM); |
| gcry_mpi_mod (r, r, sk.n); |
| |
| /* Calculate inverse of r. It practically impossible that the |
| follwing test fails, thus we do not add code to release |
| allocated resources. */ |
| if (!gcry_mpi_invm (ri, r, sk.n)) |
| return GPG_ERR_INTERNAL; |
| } |
| |
| if (! (flags & PUBKEY_FLAG_NO_BLINDING)) |
| x = rsa_blind (data[0], r, sk.e, sk.n); |
| else |
| x = data[0]; |
| |
| /* Do the encryption. */ |
| secret (y, x, &sk); |
| |
| if (! (flags & PUBKEY_FLAG_NO_BLINDING)) |
| { |
| /* Undo blinding. */ |
| gcry_mpi_t a = gcry_mpi_copy (y); |
| |
| gcry_mpi_release (y); |
| y = rsa_unblind (a, ri, sk.n); |
| |
| gcry_mpi_release (a); |
| } |
| |
| if (! (flags & PUBKEY_FLAG_NO_BLINDING)) |
| { |
| /* Deallocate resources needed for blinding. */ |
| gcry_mpi_release (x); |
| gcry_mpi_release (r); |
| gcry_mpi_release (ri); |
| } |
| |
| /* Copy out result. */ |
| *result = y; |
| |
| return GPG_ERR_NO_ERROR; |
| } |
| |
| |
| static gcry_err_code_t |
| rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) |
| { |
| RSA_secret_key sk; |
| |
| (void)algo; |
| |
| sk.n = skey[0]; |
| sk.e = skey[1]; |
| sk.d = skey[2]; |
| sk.p = skey[3]; |
| sk.q = skey[4]; |
| sk.u = skey[5]; |
| resarr[0] = mpi_alloc( mpi_get_nlimbs (sk.n)); |
| secret (resarr[0], data, &sk); |
| |
| return GPG_ERR_NO_ERROR; |
| } |
| |
| |
| static gcry_err_code_t |
| rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, |
| int (*cmp) (void *opaque, gcry_mpi_t tmp), |
| void *opaquev) |
| { |
| RSA_public_key pk; |
| gcry_mpi_t result; |
| gcry_err_code_t rc; |
| |
| (void)algo; |
| (void)cmp; |
| (void)opaquev; |
| |
| pk.n = pkey[0]; |
| pk.e = pkey[1]; |
| result = gcry_mpi_new ( 160 ); |
| public( result, data[0], &pk ); |
| #ifdef IS_DEVELOPMENT_VERSION |
| if (DBG_CIPHER) |
| { |
| log_mpidump ("rsa verify result:", result ); |
| log_mpidump (" hash:", hash ); |
| } |
| #endif /*IS_DEVELOPMENT_VERSION*/ |
| /*rc = (*cmp)( opaquev, result );*/ |
| rc = mpi_cmp (result, hash) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR; |
| gcry_mpi_release (result); |
| |
| return rc; |
| } |
| |
| |
| static unsigned int |
| rsa_get_nbits (int algo, gcry_mpi_t *pkey) |
| { |
| (void)algo; |
| |
| return mpi_get_nbits (pkey[0]); |
| } |
| |
| |
| /* Compute a keygrip. MD is the hash context which we are going to |
| update. KEYPARAM is an S-expression with the key parameters, this |
| is usually a public key but may also be a secret key. An example |
| of such an S-expression is: |
| |
| (rsa |
| (n #00B...#) |
| (e #010001#)) |
| |
| PKCS-15 says that for RSA only the modulus should be hashed - |
| however, it is not clear wether this is meant to use the raw bytes |
| (assuming this is an unsigned integer) or whether the DER required |
| 0 should be prefixed. We hash the raw bytes. */ |
| static gpg_err_code_t |
| compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) |
| { |
| gcry_sexp_t l1; |
| const char *data; |
| size_t datalen; |
| |
| l1 = gcry_sexp_find_token (keyparam, "n", 1); |
| if (!l1) |
| return GPG_ERR_NO_OBJ; |
| |
| data = gcry_sexp_nth_data (l1, 1, &datalen); |
| if (!data) |
| { |
| gcry_sexp_release (l1); |
| return GPG_ERR_NO_OBJ; |
| } |
| |
| gcry_md_write (md, data, datalen); |
| gcry_sexp_release (l1); |
| |
| return 0; |
| } |
| |
| |
| |
| |
| /* |
| Self-test section. |
| */ |
| |
| static const char * |
| selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) |
| { |
| static const char sample_data[] = |
| "(data (flags pkcs1)" |
| " (hash sha1 #11223344556677889900aabbccddeeff10203040#))"; |
| static const char sample_data_bad[] = |
| "(data (flags pkcs1)" |
| " (hash sha1 #11223344556677889900aabbccddeeff80203040#))"; |
| |
| const char *errtxt = NULL; |
| gcry_error_t err; |
| gcry_sexp_t data = NULL; |
| gcry_sexp_t data_bad = NULL; |
| gcry_sexp_t sig = NULL; |
| |
| err = gcry_sexp_sscan (&data, NULL, |
| sample_data, strlen (sample_data)); |
| if (!err) |
| err = gcry_sexp_sscan (&data_bad, NULL, |
| sample_data_bad, strlen (sample_data_bad)); |
| if (err) |
| { |
| errtxt = "converting data failed"; |
| goto leave; |
| } |
| |
| err = gcry_pk_sign (&sig, data, skey); |
| if (err) |
| { |
| errtxt = "signing failed"; |
| goto leave; |
| } |
| err = gcry_pk_verify (sig, data, pkey); |
| if (err) |
| { |
| errtxt = "verify failed"; |
| goto leave; |
| } |
| err = gcry_pk_verify (sig, data_bad, pkey); |
| if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) |
| { |
| errtxt = "bad signature not detected"; |
| goto leave; |
| } |
| |
| |
| leave: |
| gcry_sexp_release (sig); |
| gcry_sexp_release (data_bad); |
| gcry_sexp_release (data); |
| return errtxt; |
| } |
| |
| |
| |
| /* Given an S-expression ENCR_DATA of the form: |
| |
| (enc-val |
| (rsa |
| (a a-value))) |
| |
| as returned by gcry_pk_decrypt, return the the A-VALUE. On error, |
| return NULL. */ |
| static gcry_mpi_t |
| extract_a_from_sexp (gcry_sexp_t encr_data) |
| { |
| gcry_sexp_t l1, l2, l3; |
| gcry_mpi_t a_value; |
| |
| l1 = gcry_sexp_find_token (encr_data, "enc-val", 0); |
| if (!l1) |
| return NULL; |
| l2 = gcry_sexp_find_token (l1, "rsa", 0); |
| gcry_sexp_release (l1); |
| if (!l2) |
| return NULL; |
| l3 = gcry_sexp_find_token (l2, "a", 0); |
| gcry_sexp_release (l2); |
| if (!l3) |
| return NULL; |
| a_value = gcry_sexp_nth_mpi (l3, 1, 0); |
| gcry_sexp_release (l3); |
| |
| return a_value; |
| } |
| |
| |
| static const char * |
| selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) |
| { |
| const char *errtxt = NULL; |
| gcry_error_t err; |
| const unsigned int nbits = 1000; /* Encrypt 1000 random bits. */ |
| gcry_mpi_t plaintext = NULL; |
| gcry_sexp_t plain = NULL; |
| gcry_sexp_t encr = NULL; |
| gcry_mpi_t ciphertext = NULL; |
| gcry_sexp_t decr = NULL; |
| gcry_mpi_t decr_plaintext = NULL; |
| gcry_sexp_t tmplist = NULL; |
| |
| /* Create plaintext. The plaintext is actually a big integer number. */ |
| plaintext = gcry_mpi_new (nbits); |
| gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); |
| |
| /* Put the plaintext into an S-expression. */ |
| err = gcry_sexp_build (&plain, NULL, |
| "(data (flags raw) (value %m))", plaintext); |
| if (err) |
| { |
| errtxt = "converting data failed"; |
| goto leave; |
| } |
| |
| /* Encrypt. */ |
| err = gcry_pk_encrypt (&encr, plain, pkey); |
| if (err) |
| { |
| errtxt = "encrypt failed"; |
| goto leave; |
| } |
| |
| /* Extraxt the ciphertext from the returned S-expression. */ |
| /*gcry_sexp_dump (encr);*/ |
| ciphertext = extract_a_from_sexp (encr); |
| if (!ciphertext) |
| { |
| errtxt = "gcry_pk_decrypt returned garbage"; |
| goto leave; |
| } |
| |
| /* Check that the ciphertext does no match the plaintext. */ |
| /* _gcry_log_mpidump ("plaintext", plaintext); */ |
| /* _gcry_log_mpidump ("ciphertxt", ciphertext); */ |
| if (!gcry_mpi_cmp (plaintext, ciphertext)) |
| { |
| errtxt = "ciphertext matches plaintext"; |
| goto leave; |
| } |
| |
| /* Decrypt. */ |
| err = gcry_pk_decrypt (&decr, encr, skey); |
| if (err) |
| { |
| errtxt = "decrypt failed"; |
| goto leave; |
| } |
| |
| /* Extract the decrypted data from the S-expression. Note that the |
| output of gcry_pk_decrypt depends on whether a flags lists occurs |
| in its input data. Because we passed the output of |
| gcry_pk_encrypt directly to gcry_pk_decrypt, such a flag value |
| won't be there as of today. To be prepared for future changes we |
| take care of it anyway. */ |
| tmplist = gcry_sexp_find_token (decr, "value", 0); |
| if (tmplist) |
| decr_plaintext = gcry_sexp_nth_mpi (tmplist, 1, GCRYMPI_FMT_USG); |
| else |
| decr_plaintext = gcry_sexp_nth_mpi (decr, 0, GCRYMPI_FMT_USG); |
| if (!decr_plaintext) |
| { |
| errtxt = "decrypt returned no plaintext"; |
| goto leave; |
| } |
| |
| /* Check that the decrypted plaintext matches the original plaintext. */ |
| if (gcry_mpi_cmp (plaintext, decr_plaintext)) |
| { |
| errtxt = "mismatch"; |
| goto leave; |
| } |
| |
| leave: |
| gcry_sexp_release (tmplist); |
| gcry_mpi_release (decr_plaintext); |
| gcry_sexp_release (decr); |
| gcry_mpi_release (ciphertext); |
| gcry_sexp_release (encr); |
| gcry_sexp_release (plain); |
| gcry_mpi_release (plaintext); |
| return errtxt; |
| } |
| |
| |
| static gpg_err_code_t |
| selftests_rsa (selftest_report_func_t report) |
| { |
| const char *what; |
| const char *errtxt; |
| gcry_error_t err; |
| gcry_sexp_t skey = NULL; |
| gcry_sexp_t pkey = NULL; |
| |
| /* Convert the S-expressions into the internal representation. */ |
| what = "convert"; |
| err = gcry_sexp_sscan (&skey, NULL, |
| sample_secret_key, strlen (sample_secret_key)); |
| if (!err) |
| err = gcry_sexp_sscan (&pkey, NULL, |
| sample_public_key, strlen (sample_public_key)); |
| if (err) |
| { |
| errtxt = gcry_strerror (err); |
| goto failed; |
| } |
| |
| what = "key consistency"; |
| err = gcry_pk_testkey (skey); |
| if (err) |
| { |
| errtxt = gcry_strerror (err); |
| goto failed; |
| } |
| |
| what = "sign"; |
| errtxt = selftest_sign_1024 (pkey, skey); |
| if (errtxt) |
| goto failed; |
| |
| what = "encrypt"; |
| errtxt = selftest_encr_1024 (pkey, skey); |
| if (errtxt) |
| goto failed; |
| |
| gcry_sexp_release (pkey); |
| gcry_sexp_release (skey); |
| return 0; /* Succeeded. */ |
| |
| failed: |
| gcry_sexp_release (pkey); |
| gcry_sexp_release (skey); |
| if (report) |
| report ("pubkey", GCRY_PK_RSA, what, errtxt); |
| return GPG_ERR_SELFTEST_FAILED; |
| } |
| |
| |
| /* Run a full self-test for ALGO and return 0 on success. */ |
| static gpg_err_code_t |
| run_selftests (int algo, int extended, selftest_report_func_t report) |
| { |
| gpg_err_code_t ec; |
| |
| (void)extended; |
| |
| switch (algo) |
| { |
| case GCRY_PK_RSA: |
| ec = selftests_rsa (report); |
| break; |
| default: |
| ec = GPG_ERR_PUBKEY_ALGO; |
| break; |
| |
| } |
| return ec; |
| } |
| |
| |
| |
| |
| static const char *rsa_names[] = |
| { |
| "rsa", |
| "openpgp-rsa", |
| "oid.1.2.840.113549.1.1.1", |
| NULL, |
| }; |
| |
| gcry_pk_spec_t _gcry_pubkey_spec_rsa = |
| { |
| "RSA", rsa_names, |
| "ne", "nedpqu", "a", "s", "n", |
| GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR, |
| rsa_generate, |
| rsa_check_secret_key, |
| rsa_encrypt, |
| rsa_decrypt, |
| rsa_sign, |
| rsa_verify, |
| rsa_get_nbits, |
| }; |
| pk_extra_spec_t _gcry_pubkey_extraspec_rsa = |
| { |
| run_selftests, |
| rsa_generate_ext, |
| compute_keygrip |
| }; |
| |