201 lines
4.8 KiB
C
201 lines
4.8 KiB
C
|
#include "rsa.h"
|
||
|
#include <gmp.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
static int random_prime(mpz_t prime, const size_t size) {
|
||
|
u8 tmp[size];
|
||
|
FILE *urandom = fopen("/dev/urandom", "rb");
|
||
|
|
||
|
if((urandom == NULL) || (prime == NULL))
|
||
|
return 0;
|
||
|
|
||
|
fread(tmp, 1, size, urandom);
|
||
|
mpz_import(prime, size, 1, 1, 1, 0, tmp);
|
||
|
mpz_nextprime(prime, prime);
|
||
|
|
||
|
fclose(urandom);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int rsa_keygen(rsa_key *key) {
|
||
|
// null pointer handling
|
||
|
if(key == NULL)
|
||
|
return 0;
|
||
|
|
||
|
// init bignums
|
||
|
mpz_init_set_ui(key->e, 65537);
|
||
|
mpz_inits(key->p, key->q, key->n, key->d, NULL);
|
||
|
|
||
|
// prime gen
|
||
|
if ((!random_prime(key->p, MODULUS_SIZE/2)) || (!random_prime(key->q, MODULUS_SIZE/2)))
|
||
|
return 0;
|
||
|
|
||
|
// compute n
|
||
|
mpz_mul(key->n, key->p, key->q);
|
||
|
|
||
|
// compute phi(n)
|
||
|
mpz_t phi_n; mpz_init(phi_n);
|
||
|
mpz_sub_ui(key->p, key->p, 1);
|
||
|
mpz_sub_ui(key->q, key->q, 1);
|
||
|
mpz_mul(phi_n, key->p, key->q);
|
||
|
mpz_add_ui(key->p, key->p, 1);
|
||
|
mpz_add_ui(key->q, key->q, 1);
|
||
|
|
||
|
// compute d
|
||
|
if(mpz_invert(key->d, key->e, phi_n) == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// free temporary phi_n and return true
|
||
|
mpz_clear(phi_n);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int rsa_export(rsa_key *key) {
|
||
|
|
||
|
}
|
||
|
|
||
|
static int rsa_import(rsa_key *key) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int rsa_init(rsa_key *key) {
|
||
|
if(rsa_import(key)) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return rsa_keygen(key);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int rsa_public_init(rsa_public_key *key) {
|
||
|
// null pointer handling
|
||
|
if(key == NULL)
|
||
|
return 0;
|
||
|
|
||
|
mpz_init_set_ui(key->e, 65537);
|
||
|
mpz_init_set_str(key->n, "", 0);
|
||
|
}
|
||
|
|
||
|
void rsa_free(rsa_key *key) {
|
||
|
// free bignums
|
||
|
mpz_clears(key->p, key->q, key->n, key->e, key->d, NULL);
|
||
|
}
|
||
|
|
||
|
void rsa_public_free(rsa_public_key *key) {
|
||
|
// free bignums
|
||
|
mpz_clears(key->e, key->n, NULL);
|
||
|
}
|
||
|
|
||
|
static int pkcs1(mpz_t message, const u8 *data, const size_t length) {
|
||
|
// temporary buffer
|
||
|
u8 padded_bytes[MODULUS_SIZE];
|
||
|
|
||
|
// calculate padding size (how many 0xff bytes)
|
||
|
size_t padding_length = MODULUS_SIZE - length - 3;
|
||
|
|
||
|
if ((padding_length < 8) || (message == NULL) || (data == NULL)) {
|
||
|
// message to big
|
||
|
// or null pointer
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// set padding bytes
|
||
|
padded_bytes[0] = 0x00;
|
||
|
padded_bytes[1] = 0x01;
|
||
|
padded_bytes[2 + padding_length] = 0x00;
|
||
|
|
||
|
for (size_t i = 2; i < padding_length + 2; i++) {
|
||
|
padded_bytes[i] = 0xff;
|
||
|
}
|
||
|
|
||
|
// copy message bytes
|
||
|
memcpy(padded_bytes + padding_length + 3, data, length);
|
||
|
|
||
|
// convert padded message to mpz_t
|
||
|
mpz_import(message, MODULUS_SIZE, 1, 1, 0, 0, padded_bytes);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
size_t rsa_sign(u8 *sig, const u8 *sha256, const rsa_key *key) {
|
||
|
// null pointer handling
|
||
|
if((sig == NULL) || (sha256 == NULL) || (key == NULL))
|
||
|
return 0;
|
||
|
|
||
|
// init bignum message
|
||
|
mpz_t message; mpz_init(message);
|
||
|
mpz_t blinder; mpz_init(blinder);
|
||
|
|
||
|
// get random blinder
|
||
|
random_prime(blinder, MODULUS_SIZE - 10);
|
||
|
|
||
|
// add padding
|
||
|
if(!pkcs1(message, sha256, 32)) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// blind
|
||
|
mpz_mul(message, message, blinder);
|
||
|
mpz_mod(message, message, key->n);
|
||
|
mpz_invert(blinder, blinder, key->n);
|
||
|
mpz_powm(blinder, blinder, key->d, key->n);
|
||
|
|
||
|
// compute signature
|
||
|
mpz_powm(message, message, key->d, key->n);
|
||
|
|
||
|
// unblind
|
||
|
mpz_mul(message, message, blinder);
|
||
|
mpz_mod(message, message, key->n);
|
||
|
|
||
|
// export signature
|
||
|
size_t size = (mpz_sizeinbase(message, 2) + 7) / 8;
|
||
|
mpz_export(sig, &size, 1, 1, 0, 0, message);
|
||
|
|
||
|
// free bignum and return true
|
||
|
mpz_clears(message, blinder, NULL);
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
int rsa_verify(const u8 *sig, const size_t sig_length, const u8 *sha256, const rsa_public_key *pk) {
|
||
|
// null pointer handling
|
||
|
if((sig == NULL) || (sha256 == NULL) || (pk == NULL))
|
||
|
return 0;
|
||
|
|
||
|
// initialize bignums
|
||
|
mpz_t signature, message;
|
||
|
mpz_inits(signature, message, NULL);
|
||
|
|
||
|
// import signature
|
||
|
mpz_import(signature, (sig_length < MODULUS_SIZE) ? sig_length : MODULUS_SIZE, 1, 1, 0, 0, sig);
|
||
|
|
||
|
// revert rsa signing process
|
||
|
mpz_powm(signature, signature, pk->e, pk->n);
|
||
|
|
||
|
// rebuild signed message
|
||
|
if(!pkcs1(message, sha256, 32))
|
||
|
return 0;
|
||
|
|
||
|
// compare signature with expected value
|
||
|
if(mpz_cmp(signature, message) != 0)
|
||
|
return 0;
|
||
|
|
||
|
// free bignums and return valid signature
|
||
|
mpz_clears(signature, message, NULL);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void rsa_print(const rsa_key *key) {
|
||
|
gmp_printf("%Zx\n", key->p);
|
||
|
gmp_printf("%Zx\n", key->q);
|
||
|
gmp_printf("%Zx\n", key->n);
|
||
|
gmp_printf("%Zx\n", key->e);
|
||
|
gmp_printf("%Zx\n", key->d);
|
||
|
}
|
||
|
|
||
|
void rsa_public_print(const rsa_public_key *pk) {
|
||
|
gmp_printf("%Zx\n", pk->e);
|
||
|
gmp_printf("%Zx\n", pk->n);
|
||
|
}
|