/* smg_rsa.h * S.MG, 2017 */ #ifndef SMG_RSA_H #define SMG_RSA_H #include "mpi.h" #include "knobs.h" /* A way to determine endianness at runtime. * Required for diddling a float's mantissa for instance. */ static const int onect = 1; #define is_bigendian() ( (*(char*)&onect) == 0 ) /* * These are constants as per Eulora's protocol specification, NOT knobs! * Eulora uses RSA keys of 3920 bits (490 octets); * The above key length means 2 primes of 1960 bits (245 octets) each. * NB: if you choose here an odd key length in octets you might end up with a smaller actual key, read the code. */ static const int KEY_LENGTH_OCTETS = 490; typedef struct { MPI n; /* modulus */ MPI e; /* public exponent */ } RSA_public_key; typedef struct { MPI n; /* public modulus */ MPI e; /* public exponent */ MPI d; /* private exponent: e*d=1 mod phi */ MPI p; /* prime p */ MPI q; /* prime q */ MPI u; /* inverse of p mod q */ } RSA_secret_key; /*********truerandom.c*********/ /* * Opens and configures (as per FG requirements) the specified entropy source (e.g. "/dev/ttyUSB0") * @param source_name the name of the file to open (e.g. "/dev/ttyUSB0") * @return the descriptor of the open file when successful; negative value otherwise */ int open_entropy_source(char* source_name); /* * Returns noctets random octets (i.e. 8*noctets bits in total) as obtained from EuCrypt's preferred source. * Preferred source is defined in knobs.h as ENTROPY_SOURCE and should be a TRNG (e.g. Fuckgoats). * @param nboctets the length of desired random sequence, in octets * @param out pointer to allocated memory space for the requested random noctets; NB: this method does NOT allocate space! * @return the actual number of octets that were obtained from the currently configured entropy source (this is equal to noctets on successful read of required noctets) */ int get_random_octets(int noctets, unsigned char *out); /* Returns noctets random octets as obtained from the specified "from" source; * NB: the "from" source is considered to be the handle of an already opened stream; * This method will simply attempt to read from the source as needed! * * @param noctets the length of desired random sequence, in octets * @param out pointer to allocated memory space for the requested random octets; * NB: this method does NOT allocate space! * @param from handle of an already opened entropy source - this method will just READ from it as needed * @return the actual number of octets that were obtained */ int get_random_octets_from(int noctets, unsigned char *out, int from); /* Returns (in parameter *n) a *potentially biased* random float between 0 and 1 * Uses bits from ENTROPY_SOURCE but it rounds when converting to float * NB: This function rounds impredictably. Use it ONLY if LSB normalization is insignificant to you! * This function uses rng_uint64 below. * * @param n - a float value (LSB rounded) between 0 and 1, obtained using * a 64-bit random integer (64 bits from ENTROPY_SOURCE) * @return - a positive value on success and a negative value in case of error * main possible cause for error: failure to open ENTROPY_SOURCE. * NB: a non-responsive/malconfigured source can result in blocking */ int rng_dirty_float(float *n); /* Returns (in parameter *n) a randomly generated float between 1 and 2 using: * - the IEEE 754/1985 format for single float representation * - ENTROPY_SOURCE to obtain bits that are *directly* used as mantissa * NB: this value is between 1 and 2 due to the normalised format that includes * an implicit 1 ( i.e. value is (-1)^sign * 2^(e-127) * (1.mantissa) ) * * From IEEE 754/1985, a description of the single float format: * msb means most significant bit * lsb means least significant bit * 1 8 23 ... widths * +-+-------+-----------------------+ * |s| e | f | * +-+-------+-----------------------+ * msb lsb msb lsb ... order * A 32-bit single format number X is divided as shown in the figure above. The * value v of X is inferred from its constituent fields thus: * 1. If e = 255 and f != 0 , then v is NaN regardless of s * 2. If e = 255 and f = 0 , then v = (-1)^s INFINITY * 3. If 0 < e < 255 , then v = (-1)^s * 2^(e-127) * ( 1.f ) * 4. If e = 0 and f != 0 , then v = (-1)^s * 2^(-126) * ( 0.f ) (denormalized * numbers) * 5. If e = 0 and f = 0 , then v = ( -1 )^s * 0 (zero) * * @param n - the address of an IEEE 754/1985 float: its mantissa will be set to * random bits obtained from ENTROPY_SOURCE; its sign will be set * to 0; its exponent will be set to 127 (the bias value so * that the actual exponent is 0). * @return - a positive value on success and a negative value in case of error * main possible cause for error: failure to open ENTROPY_SOURCE. * NB: a non-responsive/malconfigured source can result in blocking */ int rng_float_754_1985(float *n); /* Returns (in parameter *n) a random unsigned integer value on 32 bits. * Uses random bits from ENTROPY_SOURCE that are directly interpreted as int * * @param n - it will contain the random integer obtained by interpreting 32 * bits from ENTROPY_SOURCE as an unsigned int value on 32 bits. * @return - a positive value on success and a negative value in case of error */ int rng_uint32( uint32_t *n ); /* Returns (in parameter *n) a random unsigned integer value on 64 bits. * Uses random bits from ENTROPY_SOURCE that are directly interpreted as int * * @param n - it will contain the random integer obtained by interpreting 64 * bits from ENTROPY_SOURCE as an unsigned int value on 64 bits. * @return - a positive value on success and a negative value in case of error */ int rng_uint64( uint64_t *n ); /*********primegen.c*********/ /* * This is an implementation of the Miller-Rabin probabilistic primality test: * checking the specified number of randomly-chosen candidate witnesses * (i.e. with an outer bound of (1/4)^nwitnesses). * NB: a 1 result from this test means that the given n is indeed composite (non-prime) but a 0 result does not fully guarantee that n is prime! If this doesn't make sense to you, read more on probabilistic primality tests. * @param n the candidate prime number; the function will investigate whether this number is composite or *likely* to be prime. How likely? It depends on the number of witnesses checked, see next parameter. * @param nwitnesses this is the number of randomly chosen candidate witnesses to the compositeness of n that will be checked; the outer bound of the algorithm depends on this. * @param entropy_source the source of entropy (ready to read from) that will be used to choose candidate witnesses to the compositeness of n. * @return 1 if at least one witness to the compositeness of n has been found (i.e. n is certainly composite); 0 if no witness to the compositeness of n was found (i.e. it is likely that n is prime) * NB: the probability that n is *not* prime although this function returned 0 is less than (1/4)^nwitnesses, but it is NOT zero. */ int is_composite( MPI n, int nwitnesses, int entropy_source); /** * Generates a random number that has passed the Miller-Rabin test for primality (see function is_composite above). * NB: top 2 bits and bottom bit are ALWAYS 1! (i.e. a mask 110....01 is applied to the random bits) * a prime of 8*noctets long will have only (8*noctets-3) bits that are randomly chosen! * NB: this method does NOT allocate space for the requested MPI; it is the caller's responsibility to allocate it! * The source of randomness is ENTROPY_SOURCE in eucrypt/smg_rsa/include/knobs.h * The number of witnesses checked by Miller-Rabin is M_R_ITERATIONS in eucrypt/smg_rsa/include/knobs.h * Preconditions: * noctets > 0 (at least one octet!) * output has known allocated memory for at least nlimbs(noctets) * successful access to the entropy source * @param noctets the length of the desired prime number, in octets * @param output an MPI with sufficient memory allocated for a number that is noctets long */ void gen_random_prime( unsigned int noctets, MPI output); /*********rsa.c*********/ /* * Generates a pair of public+private RSA keys using directly the entropy source * specified in include/knobs.h * * ALL RSA keys are 8*KEY_LENGTH_OCTETS bits out of * 2 8*KEY_LENGTH_OCTETS/2 bits primes, as per TMSR spec. * * @param sk a fully-allocated structure to hold the generated keypair (secret key structure holds all the elements anyway, public key is a subset of this) * * NB: this procedure does NOT allocate memory for components in sk! * caller should ALLOCATE enough memory for all the MPIs in sk * Precondition: * MPIs in sk have known allocated memory for the nlimbs fitting their TMSR size */ void gen_keypair( RSA_secret_key *sk ); /**************** * Public key operation. Encrypt input with pk and store result into output. * * output = input^e mod n , where e,n are elements of pkey. * NB: caller should allocate *sufficient* memory for output to hold the result. * NB: NO checks are made on input! * * @param output MPI with enough allocated memory to hold result of encryption * @param input MPI containing content to encrypt; it *has to be* different from output! * @param pk the public key that will be used to encrypt input * * Precondition: * output != input * Output and input have to be two distinct MPIs because of the sorry state of the underlying mpi lib that can't handle properly the case when those are the same. */ void public_rsa( MPI output, MPI input, RSA_public_key *pk ); /**************** * Secret key operation. Decrypt input with sk and store result in output. * * output = input^d mod n , where d, n are elements of skey. * * This implementation uses the Chinese Remainder Theorem (CRT): * * out1 = input ^ (d mod (p-1)) mod p * out2 = input ^ (d mod (q-1)) mod q * h = u * (out2 - out1) mod q * output = out1 + h * p * * where out1, out2 and h are intermediate values, d,n,p,q,u are elements of skey. By using CRT, encryption is *faster*. Decide for yourself if this fits your needs though! * NB: it is the caller's responsibility to allocate memory for output! * NB: NO checks are made on input! * * @param output MPI with enough allocated memory to hold result of decryption * @param input MPI containing content to decrypt * @param sk the secret key that will be used to decrypt input */ void secret_rsa( MPI output, MPI input, RSA_secret_key *sk ); #endif /*SMG_RSA*/