https://github.com/henrycg/earand
Raw File
Tip revision: 362625f3847ddd2e2d5a90cf5f93b4b3ea76e059 authored by Henry Corrigan-Gibbs on 21 May 2018, 19:54:59 UTC
Merge branch 'master' of github.com:henrycg/earand
Tip revision: 362625f
rsa_params.c
#include <stdbool.h>

#include <openssl/pem.h>

#include "integer_group.h"
#include "rsa_params.h"
#include "util.h"

static const char str_modulus_bits[] = "modulus_bits";

static void ReadPublicKey(EVP_PKEY** dst, const char* filename);
static void ReadPrivateKey(EVP_PKEY** dst, const char* filename);
static bool Sign(EVP_PKEY* key, unsigned char* sig, int* sig_len,
    const unsigned char* msg, int msg_len);
static bool Verify(EVP_PKEY* key, const unsigned char* sig, int sig_len,
    const unsigned char* msg, int msg_len);

struct rsa_params {
  int modulus_bits;
  IntegerGroup group;
  BN_CTX* ctx;

  EVP_PKEY* ca_public_key;
  EVP_PKEY* ca_private_key;

  EVP_PKEY* ea_public_key;
  EVP_PKEY* ea_private_key;
};

RsaParams RsaParams_New(int modulus_bits)
{
  CHECK_CALL(modulus_bits > 10);

  RsaParams params = safe_malloc(sizeof(*params));
  params->modulus_bits = modulus_bits;
  params->group = IntegerGroup_Generate(modulus_bits+100);
  CHECK_CALL(params->ctx = BN_CTX_new());

  ReadPublicKey(&(params->ca_public_key), CA_PUBLIC_KEY_FILE);
  ReadPrivateKey(&(params->ca_private_key), CA_PRIVATE_KEY_FILE);

  ReadPublicKey(&(params->ea_public_key), EA_PUBLIC_KEY_FILE);
  ReadPrivateKey(&(params->ea_private_key), EA_PRIVATE_KEY_FILE);
  
  return params;
}

RsaParams RsaParams_Read(const char* filename)
{
  // Read common system parameters;
  FILE* fp = fopen(filename, "r");
  CHECK_CALL(fp);

  RsaParams params = RsaParams_Unserialize(fp);
  CHECK_CALL(params);
  fclose(fp);

  return params;
}

void RsaParams_Free(RsaParams params) 
{
  IntegerGroup_Free(params->group);
  
  EVP_PKEY_free(params->ca_public_key);
  EVP_PKEY_free(params->ca_private_key);

  EVP_PKEY_free(params->ea_public_key);
  EVP_PKEY_free(params->ea_private_key);

  BN_CTX_free(params->ctx);

  free(params);
}

int RsaParams_Serialize(const_RsaParams params, FILE* file)
{
  if(!((fprintf(file, "%s", str_modulus_bits) == (sizeof(str_modulus_bits)-1)) &&
    putc(':', file) &&
    fprintf(file, "%d", params->modulus_bits) &&
    putc('\n', file))) return false;

  if(!IntegerGroup_Serialize(params->group, file))
    return false;

  if(!PEM_write_PUBKEY(file, params->ca_public_key))
    return false;

  if(!PEM_write_PrivateKey(file, params->ca_private_key, NULL, NULL, 0, 0, NULL))
    return false;

  if(!PEM_write_PUBKEY(file, params->ea_public_key))
    return false;

  if(!PEM_write_PrivateKey(file, params->ea_private_key, NULL, NULL, 0, 0, NULL))
    return false;

  return true;
}

RsaParams RsaParams_Unserialize(FILE* file)
{
  RsaParams params = safe_malloc(sizeof(*params));
  CHECK_CALL(params->ctx = BN_CTX_new());

  // Read the "modulus_bits" tag
  for(const char *p = str_modulus_bits; *p; p++) {
    int c = getc(file);
    if(c < 0 || c != *p) {
      free(params);
      return NULL;
    }
  }

  if(fscanf(file, ":%d\n", &(params->modulus_bits)) != 1) {
    free(params);
    return NULL;
  }

  params->group = IntegerGroup_Unserialize(file);
  if(!params->group) {
    free(params);
    return NULL;
  }

  if(!((params->ca_public_key = PEM_read_PUBKEY(file, NULL, NULL, NULL)) &&
    (params->ca_private_key = PEM_read_PrivateKey(file, NULL, NULL, NULL)) &&
    (params->ea_public_key = PEM_read_PUBKEY(file, NULL, NULL, NULL)) &&
    (params->ea_private_key = PEM_read_PrivateKey(file, NULL, NULL, NULL)))) {
    free(params);
    return NULL;
  }

  return params;
}

int RsaParams_CaSignatureLength(const_RsaParams params)
{
  return EVP_PKEY_size(params->ca_public_key);
}

bool RsaParams_CaSign(const_RsaParams params, unsigned char* sig, int* sig_len,
    const unsigned char* msg, int msg_len)
{
  return Sign(params->ca_private_key, sig, sig_len, msg, msg_len);
}

bool RsaParams_CaVerify(const_RsaParams params, const unsigned char* sig, int sig_len,
    const unsigned char* msg, int msg_len)
{
  return Verify(params->ca_public_key, sig, sig_len, msg, msg_len);
}

EVP_PKEY* RsaParams_GetCaPrivateKey(const_RsaParams params)
{
  return params->ca_private_key;
}

EVP_PKEY* RsaParams_GetCaPublicKey(const_RsaParams params)
{
  return params->ca_public_key;
}

EVP_PKEY* RsaParams_GetEaPrivateKey(const_RsaParams params)
{
  return params->ea_private_key;
}

EVP_PKEY* RsaParams_GetEaPublicKey(const_RsaParams params)
{
  return params->ea_public_key;
}

int RsaParams_EaSignatureLength(const_RsaParams params)
{
  return EVP_PKEY_size(params->ea_public_key);
}

bool RsaParams_EaSign(const_RsaParams params, unsigned char* sig, int* sig_len,
    const unsigned char* msg, int msg_len)
{
  return Sign(params->ea_private_key, sig, sig_len, msg, msg_len);
}

bool RsaParams_EaVerify(const_RsaParams params, const unsigned char* sig, int sig_len,
    const unsigned char* msg, int msg_len)
{
  return Verify(params->ea_public_key, sig, sig_len, msg, msg_len);
}

bool RsaParams_InRange(const_RsaParams params, const BIGNUM* value)
{
  BIGNUM* min = BN_new();
  BIGNUM* max = BN_new();

  const int prime_bits = RsaParams_GetModulusBits(params)/2;

  // min = 2^k
  BN_one(min); 
  CHECK_CALL(BN_lshift(min, min, prime_bits));

  // max = 2^{k+1}
  BN_one(max); 
  CHECK_CALL(BN_lshift(max, max, prime_bits+1));
    
  bool result = (BN_cmp(min, value) == -1) &&
   ( BN_cmp(value, max) == -1);

  BN_free(min);
  BN_free(max);

  return result;
}

int RsaParams_GetDeltaMax(const_RsaParams params)
{
  // According to Juels paper, the
  // probability that we will fail to find a prime
  // in range [r, r+l) is at most:
  //    exp(-lambda)
  // where
  //    e is the RSA encryption exponent (65537)!!!!
  //    l = lambda * ln(r) * 2e / (e-1)
  //
  // Taking lambda = 80 and (2e / (e-1)) ~ 2,
  // we need 160 * prime_bits
  return (160 * (params->modulus_bits/2));
}

int RsaParams_GetModulusBits(const_RsaParams params)
{
  return params->modulus_bits;
}

IntegerGroup RsaParams_GetGroup(const_RsaParams params)
{
  return params->group;
}

BN_CTX* RsaParams_GetCtx(const_RsaParams params)
{
  return params->ctx;
}

BIGNUM* RsaParams_RandomLargeValue(const_RsaParams params) 
{
  BIGNUM *result = BN_new();

  CHECK_CALL(result);
  CHECK_CALL(BN_rand(result, (params->modulus_bits/2)+1, 0, 0));

  return result;
}

static void ReadPublicKey(EVP_PKEY** dst, const char* filename)
{
  FILE* fp = fopen(filename, "r");
  CHECK_CALL(fp);
  CHECK_CALL((*dst) = PEM_read_PUBKEY(fp, NULL, NULL, NULL));
  CHECK_CALL(*dst);
  fclose(fp);
}

static void ReadPrivateKey(EVP_PKEY** dst, const char* filename)
{
  FILE* fp = fopen(filename, "r");
  CHECK_CALL(fp);
  CHECK_CALL((*dst) = PEM_read_PrivateKey(fp, NULL, NULL, NULL));
  CHECK_CALL(*dst);
  fclose(fp);
}

bool Sign(EVP_PKEY* key, unsigned char* sig, int* sig_len,
    const unsigned char* msg, int msg_len)
{
  EVP_MD_CTX ctx;
  EVP_SignInit(&ctx, EVP_sha1());

  bool retval = EVP_SignUpdate(&ctx, msg, msg_len) &&
    EVP_SignFinal(&ctx, sig, (unsigned int*)sig_len, key);

  EVP_MD_CTX_cleanup(&ctx);

  return retval;
}

bool Verify(EVP_PKEY* key, const unsigned char* sig, int sig_len,
    const unsigned char* msg, int msg_len)
{
  EVP_MD_CTX ctx;
  bool retval = EVP_VerifyInit(&ctx, EVP_sha1()) &&
    EVP_VerifyUpdate(&ctx, msg, msg_len) &&
    (EVP_VerifyFinal(&ctx, sig, sig_len, key) == 1);

  EVP_MD_CTX_cleanup(&ctx);

  return retval;
}
back to top