//Wrapper methods for C implementations of RSA and MPI. //To be used / called from Ada so that the C part remains well separated. //S.MG, 2018 #include "c_wrappers.h" #include "mpi.h" #include "smg_rsa.h" #include #include //for memmove... //Wrapper for comparing the given arrays of octets as MPIs //Steps: //1. allocate space for 2 MPIs u and v //2. set buffer of u to content of a, buffer of v to content of b //3. call mpi_cmp(u,v) and store result //4. de-allocate u and v //5. return result int mpi_cmp_octets(char *a, unsigned int len_a, char *b, unsigned int len_b) { //variable to hold the final result of comparing a to b as MPIs int result; //calculate how much space is needed for each MPI unsigned int nlimbs_a = mpi_nlimb_hint_from_nbytes( len_a ); unsigned int nlimbs_b = mpi_nlimb_hint_from_nbytes( len_b ); //allocate space for the 2 MPIs MPI u = mpi_alloc(nlimbs_a); MPI v = mpi_alloc(nlimbs_b); //set the given octets as the values of the 2 MPIs and normalize //the sign is set to 0 (last parameter). mpi_set_normalized(u, a, len_a, 0); mpi_set_normalized(v, b, len_b, 0); //compare the MPIs as numbers and store the result result = mpi_cmp(u, v); //tidy up: free the memory allocated for the 2 MPIs mpi_free(u); mpi_free(v); //return the result comparing a to b as MPIs return result; } //Encryption of given input with a public RSA key: n and e given as octets too. //Steps: //1. create (allocate memory for) MPIs for out and input; //2. set the input as buffer for the corresponding MPI; //3. create and set the public key structure with n,e as contents; //4. call rsa/public_rsa and retrieve the result storing it in out; //5. free allocated memory for all the MPIs. //6. return the actual length of the encrypted result int public_rsa_octets( char *out , unsigned int len_out, char *input, unsigned int len_input, char *n , unsigned int len_n, char *e , unsigned int len_e) { // precondition: output has enough memory allocated assert( len_out >= KEY_LENGTH_OCTETS ); //allocate memory for input and output MPIs unsigned int nlimbs_in = mpi_nlimb_hint_from_nbytes( len_input ); unsigned int nlimbs_out = mpi_nlimb_hint_from_nbytes( len_out ); MPI in_mpi = mpi_alloc(nlimbs_in); MPI out_mpi = mpi_alloc(nlimbs_out); //set input as buffer for in_mpi mpi_set_normalized(in_mpi, input, len_input, 0); //create public key structure and set its contents to given n, e RSA_public_key pk; unsigned int nlimbs_n = mpi_nlimb_hint_from_nbytes( len_n ); unsigned int nlimbs_e = mpi_nlimb_hint_from_nbytes( len_e ); pk.n = mpi_alloc(nlimbs_n); pk.e = mpi_alloc(nlimbs_e); //NB MPI lib gets STUCK on 0-leading MPIs so set + normalize mpi_set_normalized(pk.n, n, len_n, 0); mpi_set_normalized(pk.e, e, len_e, 0); //call rsa public_key encryption and retrieve the result, storing it in out public_rsa( out_mpi, in_mpi, &pk); int len = len_out; mpi_to_octets( out, &len, out_mpi ); //tidy up: free allocated memory for ALL MPIs. mpi_free(in_mpi); mpi_free(out_mpi); mpi_free(pk.n); mpi_free(pk.e); //return actual length return len; } //Decryption of given input with the private key given through its components. //Steps: //1. create (allocate memory for) MPIs for out and input; //2. set the input as buffer for the corresponding MPI; //3. create and set the private key structure with n,e,d,p,q,u as contents; //4. call rsa/private_rsa and retrieve the result storing it in out; //5. free allocated memory for all the MPIs. //6. return the actual length of the result int private_rsa_octets( char *out, unsigned int len_out, char *input, unsigned int len_input, char *n , unsigned int len_n, char *e , unsigned int len_e, char *d , unsigned int len_d, char *p , unsigned int len_p, char *q , unsigned int len_q, char *u , unsigned int len_u) { // precondition: output has enough memory allocated assert( len_out >= KEY_LENGTH_OCTETS ); //allocate memory for input and output MPIs unsigned int nlimbs_in = mpi_nlimb_hint_from_nbytes( len_input ); unsigned int nlimbs_out = mpi_nlimb_hint_from_nbytes( len_out ); MPI in_mpi = mpi_alloc(nlimbs_in); MPI out_mpi = mpi_alloc(nlimbs_out); //set input as buffer for in_mpi mpi_set_normalized(in_mpi, input, len_input, 0); //create private key structure and set its contents to given n,e,d,p,q,u RSA_secret_key sk; unsigned int nlimbs_n = mpi_nlimb_hint_from_nbytes( len_n ); unsigned int nlimbs_e = mpi_nlimb_hint_from_nbytes( len_e ); unsigned int nlimbs_d = mpi_nlimb_hint_from_nbytes( len_d ); unsigned int nlimbs_p = mpi_nlimb_hint_from_nbytes( len_p ); unsigned int nlimbs_q = mpi_nlimb_hint_from_nbytes( len_q ); unsigned int nlimbs_u = mpi_nlimb_hint_from_nbytes( len_u ); sk.n = mpi_alloc(nlimbs_n); sk.e = mpi_alloc(nlimbs_e); sk.d = mpi_alloc(nlimbs_d); sk.p = mpi_alloc(nlimbs_p); sk.q = mpi_alloc(nlimbs_q); sk.u = mpi_alloc(nlimbs_u); //HAVE TO set AND normalize those or lib MPI gets stuck idiotically on 0-led mpi_set_normalized(sk.n, n, len_n, 0); mpi_set_normalized(sk.e, e, len_e, 0); mpi_set_normalized(sk.d, d, len_d, 0); mpi_set_normalized(sk.p, p, len_p, 0); mpi_set_normalized(sk.q, q, len_q, 0); mpi_set_normalized(sk.u, u, len_u, 0); //call rsa secret_key encryption and retrieve the result, storing it in out secret_rsa( out_mpi, in_mpi, &sk ); int len = len_out; mpi_to_octets( out, &len, out_mpi ); //tidy up: free memory previously allocated for MPIs mpi_free(in_mpi); mpi_free(out_mpi); mpi_free(sk.n); mpi_free(sk.e); mpi_free(sk.d); mpi_free(sk.p); mpi_free(sk.q); mpi_free(sk.u); //return number of octets copied in out - real length of result return len; } //Generates a new RSA key and stores its components at the specified locations. void gen_rsa_octets( char *n, unsigned int *len_n, char *e, unsigned int *len_e, char *d, unsigned int *len_d, char *p, unsigned int *len_p, char *q, unsigned int *len_q, char *u, unsigned int *len_u) { // precondition: all pointers have enough memory allocated assert( *len_n >= KEY_LENGTH_OCTETS ); assert( *len_e >= KEY_LENGTH_OCTETS ); assert( *len_d >= KEY_LENGTH_OCTETS ); assert( *len_p >= KEY_LENGTH_OCTETS / 2); assert( *len_q >= KEY_LENGTH_OCTETS / 2); assert( *len_u >= KEY_LENGTH_OCTETS / 2); //the secret key structure that will hold generated key components RSA_secret_key sk; int nlimbs = mpi_nlimb_hint_from_nbytes( KEY_LENGTH_OCTETS ); int nlimbs_pq = mpi_nlimb_hint_from_nbytes( KEY_LENGTH_OCTETS / 2 ); sk.n = mpi_alloc(nlimbs); sk.e = mpi_alloc(nlimbs); sk.d = mpi_alloc(nlimbs); sk.p = mpi_alloc(nlimbs_pq); sk.q = mpi_alloc(nlimbs_pq); sk.u = mpi_alloc(nlimbs_pq); //generate the rsa key pair - this may take a while! gen_keypair(&sk); //copy components to their place mpi_to_octets( n, len_n, sk.n ); mpi_to_octets( e, len_e, sk.e ); mpi_to_octets( d, len_d, sk.d ); mpi_to_octets( p, len_p, sk.p ); mpi_to_octets( q, len_q, sk.q ); mpi_to_octets( u, len_u, sk.u ); //tidy up: free ALL MPIs mpi_free(sk.n); mpi_free(sk.e); mpi_free(sk.d); mpi_free(sk.p); mpi_free(sk.q); mpi_free(sk.u); } void mpi_to_octets( char *out, unsigned int *len_out, MPI m) { //copy the components as raw octets to the given pointers int len = 0; int sign; unsigned char * buffer = mpi_get_buffer( m, &len, &sign ); //check and don't copy MORE than there is allocated space in out! assert( len <= *len_out ); memmove( out, buffer, len ); *len_out = len; //save actual length of the component xfree( buffer ); //free the buffer that was allocated by mpi_get_buffer } void mpi_set_normalized(MPI m, const char *buffer, unsigned int noctets, int sign) { mpi_set_buffer( m, buffer, noctets, sign ); mpi_normalize( m ); }