-
+ 388A33BE262FAA152FB74089B6AC814C7E5C6248A5B52F91A8C69C0E19EC9F9EEA12B0551B0AADC751F73CDD5AC4004C8C493AA1E6041118A922070EAD3A7ECB
smg_comms/rsa/rsa.c
(0 . 0)(1 . 140)
9013 /*
9014 * An implementation of TMSR RSA
9015 * S.MG, 2018
9016 */
9017
9018 #include "smg_rsa.h"
9019 #include <assert.h>
9020
9021 void gen_keypair( RSA_secret_key *sk ) {
9022 /* precondition: sk is not null */
9023 assert(sk != NULL);
9024
9025 /* precondition: enough memory allocated, corresponding to key size */
9026 int noctets_pq = KEY_LENGTH_OCTETS / 2;
9027 unsigned int nlimbs_pq = mpi_nlimb_hint_from_nbytes( noctets_pq);
9028 unsigned int nlimbs_n = mpi_nlimb_hint_from_nbytes( KEY_LENGTH_OCTETS);
9029 assert( mpi_get_alloced( sk->n) >= nlimbs_n);
9030 assert( mpi_get_alloced( sk->p) >= nlimbs_pq);
9031 assert( mpi_get_alloced( sk->q) >= nlimbs_pq);
9032
9033 /* helper variables for calculating Euler's totient phi=(p-1)*(q-1) */
9034 MPI p_minus1 = mpi_alloc(nlimbs_pq);
9035 MPI q_minus1 = mpi_alloc(nlimbs_pq);
9036 MPI phi = mpi_alloc(nlimbs_n);
9037
9038 /* generate 2 random primes, p and q*/
9039 /* gen_random_prime sets top 2 bits to 1 so p*q will have KEY_LENGTH bits */
9040 /* in the extremely unlikely case that p = q, discard and generate again */
9041 do {
9042 gen_random_prime( noctets_pq, sk->p);
9043 gen_random_prime( noctets_pq, sk->q);
9044 } while ( mpi_cmp( sk->p, sk->q) == 0);
9045
9046 /* swap if needed, to ensure p < q for calculating u */
9047 if ( mpi_cmp( sk->p, sk->q) > 0)
9048 mpi_swap( sk->p, sk->q);
9049
9050 /* calculate helper for Chinese Remainder Theorem:
9051 u = p ^ -1 ( mod q )
9052 this is used to speed-up decryption.
9053 */
9054 mpi_invm( sk->u, sk->p, sk->q);
9055
9056 /* calculate modulus n = p * q */
9057 mpi_mul( sk->n, sk->p, sk->q);
9058
9059 /* calculate Euler totient: phi = (p-1)*(q-1) */
9060 mpi_sub_ui( p_minus1, sk->p, 1);
9061 mpi_sub_ui( q_minus1, sk->q, 1);
9062 mpi_mul( phi, p_minus1, q_minus1);
9063
9064 /* choose random prime e, public exponent, with 3 < e < phi */
9065 /* because e is prime, gcd(e, phi) is always 1 so no need to check it */
9066 do {
9067 gen_random_prime( noctets_pq, sk->e);
9068 } while ( (mpi_cmp_ui(sk->e, 3) < 0) || (mpi_cmp(sk->e, phi) > 0));
9069
9070 /* calculate private exponent d, 1 < d < phi, where e * d = 1 mod phi */
9071 mpi_invm( sk->d, sk->e, phi);
9072
9073 /* tidy up: free locally allocated memory for helper variables */
9074 mpi_free(phi);
9075 mpi_free(p_minus1);
9076 mpi_free(q_minus1);
9077 }
9078
9079 void public_rsa( MPI output, MPI input, RSA_public_key *pk ) {
9080
9081 /* mpi_powm can't handle output and input being same */
9082 assert (output != input);
9083
9084 /* the actual rsa op */
9085 mpi_powm( output, input, pk->e, pk->n );
9086
9087 }
9088
9089 void secret_rsa( MPI output, MPI input, RSA_secret_key *skey ) {
9090 /* at its simplest, this would be input ^ d (mod n), hence:
9091 * mpi_powm( output, input, skey->d, skey->n );
9092 * for faster decryption though, we'll use CRT and Garner's algorithm, hence:
9093 * u = p ^ (-1) (mod q) , already calculated and stored in skey
9094 * dp = d mod (p-1)
9095 * dq = d mod (q-1)
9096 * m1 = input ^ dp (mod p)
9097 * m2 = input ^ dq (mod q)
9098 * h = u * (m2 - m1) mod q
9099 * output = m1 + h * p
9100 * Note that same CRT speed up isn't available for encryption because at
9101 encryption time not enough information is available (only e and n are known).
9102 */
9103
9104 /* allocate memory for all local, helper MPIs */
9105 MPI p_minus1 = mpi_alloc( mpi_get_nlimbs( skey->p) );
9106 MPI q_minus1 = mpi_alloc( mpi_get_nlimbs( skey->q) );
9107 int nlimbs = mpi_get_nlimbs( skey->n ) + 1;
9108 MPI dp = mpi_alloc( nlimbs );
9109 MPI dq = mpi_alloc( nlimbs );
9110 MPI m1 = mpi_alloc( nlimbs );
9111 MPI m2 = mpi_alloc( nlimbs );
9112 MPI h = mpi_alloc( nlimbs );
9113
9114 /* p_minus1 = p - 1 */
9115 mpi_sub_ui( p_minus1, skey->p, 1 );
9116
9117 /* dp = d mod (p - 1) aka remainder of d / (p - 1) */
9118 mpi_fdiv_r( dp, skey->d, p_minus1 );
9119
9120 /* m1 = input ^ dp (mod p) */
9121 mpi_powm( m1, input, dp, skey->p );
9122
9123 /* q_minus1 = q - 1 */
9124 mpi_sub_ui( q_minus1, skey->q, 1 );
9125
9126 /* dq = d mod (q - 1) aka remainder of d / (q - 1) */
9127 mpi_fdiv_r( dq, skey->d, q_minus1 );
9128
9129 /* m2 = input ^ dq (mod q) */
9130 mpi_powm( m2, input, dq, skey->q );
9131
9132 /* h = u * ( m2 - m1 ) mod q */
9133 mpi_sub( h, m2, m1 );
9134 if ( mpi_is_neg( h ) )
9135 mpi_add ( h, h, skey->q );
9136 mpi_mulm( h, skey->u, h, skey->q );
9137
9138 /* output = m1 + h * p */
9139 mpi_mul ( h, h, skey->p );
9140 mpi_add ( output, m1, h );
9141
9142 /* tidy up */
9143 mpi_free ( p_minus1 );
9144 mpi_free ( q_minus1 );
9145 mpi_free ( dp );
9146 mpi_free ( dq );
9147 mpi_free ( m1 );
9148 mpi_free ( m2 );
9149 mpi_free ( h );
9150
9151 }
9152