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
dsa_params.c
#include <stdbool.h>

#include <openssl/pem.h>

#include "dsa_params.h"
#include "util.h"

static const char str_curve_name[] = "curve_name";

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 dsa_params {
  EC_GROUP* group;
  BIGNUM* order;
  BN_CTX* ctx;

  EC_POINT* commit_g;
  EC_POINT* commit_h;

  EVP_PKEY* ca_public_key;
  EVP_PKEY* ca_private_key;

  EVP_PKEY* ea_public_key;
  EVP_PKEY* ea_private_key;
};

void SetupCurve(DsaParams params, const char* curve_name)
{
  const int nid = OBJ_txt2nid(curve_name);
  CHECK_CALL(nid > 0);
  CHECK_CALL(params->group = EC_GROUP_new_by_curve_name(nid));
  CHECK_CALL(params->ctx = BN_CTX_new());

  const EC_POINT* gen = EC_GROUP_get0_generator(params->group);
  CHECK_CALL(gen);
  CHECK_CALL(params->commit_g = EC_POINT_dup(gen, params->group));
  CHECK_CALL(params->commit_h = EC_POINT_new(params->group));

  // For h value just pick some random constant point
  BIGNUM* tmp = BN_new();
  CHECK_CALL(tmp);
  BN_one(tmp);
  BN_add_word(tmp, 5);

  do {
    CHECK_CALL(params->commit_h);
    BN_add_word(tmp, 1);
  } while(!(EC_POINT_set_compressed_coordinates_GFp(params->group, params->commit_h, tmp, 1, params->ctx)
      && EC_POINT_is_on_curve(params->group, params->commit_h, params->ctx)));
  BN_clear_free(tmp);
}


DsaParams DsaParams_New(const char* curve_name)
{
  DsaParams params = safe_malloc(sizeof(*params));
  SetupCurve(params, curve_name);
  CHECK_CALL(params->order = BN_new());
  CHECK_CALL(EC_GROUP_get_order(params->group, params->order, params->ctx));

  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;
}

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

  DsaParams params = DsaParams_Unserialize(fp);
  CHECK_CALL(params);
  fclose(fp);

  return params;
}

void DsaParams_Free(DsaParams params) 
{
  EC_POINT_clear_free(params->commit_g);
  EC_POINT_clear_free(params->commit_h);
  EC_GROUP_clear_free(params->group);
  BN_clear_free(params->order);
  BN_CTX_free(params->ctx);
  
  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);

  free(params);
}

int DsaParams_Serialize(const_DsaParams params, FILE* file)
{
  int nid = EC_GROUP_get_curve_name(params->group);
  CHECK_CALL(nid > 0);
  const char* curve_name = OBJ_nid2sn(nid);
  CHECK_CALL(curve_name);
  if(!((fprintf(file, "%s", str_curve_name) == (sizeof(str_curve_name)-1)) &&
    putc(':', file) &&
    fprintf(file, "%s", curve_name) &&
    putc('\n', 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;
}

DsaParams DsaParams_Unserialize(FILE* file)
{
  DsaParams params = safe_malloc(sizeof(*params));

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

  char curve_name[1024];

  if(!(1 == fscanf(file, ":%s\n", curve_name))) return NULL;

  SetupCurve(params, curve_name);
  CHECK_CALL(params->order = BN_new());
  CHECK_CALL(EC_GROUP_get_order(params->group, params->order, params->ctx));

  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 DsaParams_CaSignatureLength(const_DsaParams params)
{
  return EVP_PKEY_size(params->ca_public_key);
}

bool DsaParams_CaSign(const_DsaParams 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 DsaParams_CaVerify(const_DsaParams 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* DsaParams_GetCaPrivateKey(const_DsaParams params)
{
  return params->ca_private_key;
}

EVP_PKEY* DsaParams_GetCaPublicKey(const_DsaParams params)
{
  return params->ca_public_key;
}

EVP_PKEY* DsaParams_GetEaPrivateKey(const_DsaParams params)
{
  return params->ea_private_key;
}

EVP_PKEY* DsaParams_GetEaPublicKey(const_DsaParams params)
{
  return params->ea_public_key;
}
int DsaParams_EaSignatureLength(const_DsaParams params)
{
  return EVP_PKEY_size(params->ea_public_key);
}

bool DsaParams_EaSign(const_DsaParams 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 DsaParams_EaVerify(const_DsaParams 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);
}

BIGNUM* DsaParams_RandomExponent(const_DsaParams params)
{
  BIGNUM *result = BN_new();

  CHECK_CALL(result);
  CHECK_CALL(BN_rand_range(result, params->order));

  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;
}

EC_POINT* DsaParams_Commit(const_DsaParams params, const BIGNUM* v, const BIGNUM* r)
{
  EC_POINT* res = EC_POINT_new(params->group);
  CHECK_CALL(res);

  const EC_POINT* points[2];
  const BIGNUM* muls[2];

  points[0] = params->commit_g;
  points[1] = params->commit_h;

  muls[0] = v;
  muls[1] = r;

  // Commit = g^v h^r
  CHECK_CALL(EC_POINTs_mul(params->group, res, NULL, 2, points, muls, params->ctx));
  return res;
}

EC_GROUP* DsaParams_GetCurve(const_DsaParams params)
{
  return params->group;
}

const EC_POINT* DsaParams_GetG(const_DsaParams params)
{
  return params->commit_g;
}

const EC_POINT* DsaParams_GetH(const_DsaParams params)
{
  return params->commit_h;
}

const BIGNUM* DsaParams_GetQ(const_DsaParams params)
{
  return params->order;
}

BN_CTX* DsaParams_GetCtx(DsaParams params)
{
  return params->ctx;
}

unsigned char* DsaParams_PointToString(const_DsaParams params, const EC_POINT* point, int* buf_len)
{
  *buf_len = (int)EC_POINT_point2oct(params->group, 
      point, POINT_CONVERSION_UNCOMPRESSED,
      NULL, 0, params->ctx);

  unsigned char* buf = safe_malloc(*buf_len * sizeof(unsigned char));

  CHECK_CALL(*buf_len == EC_POINT_point2oct(params->group, 
      point, POINT_CONVERSION_UNCOMPRESSED,
      buf, *buf_len, params->ctx));

  return buf;
}

EC_POINT* DsaParams_MultiplyG(const_DsaParams params, const BIGNUM* exp)
{
  return DsaParams_Multiply(params, params->commit_g, exp);
}

EC_POINT* DsaParams_MultiplyH(const_DsaParams params, const BIGNUM* exp)
{
  return DsaParams_Multiply(params, params->commit_h, exp);
}

EC_POINT* DsaParams_Multiply(const_DsaParams params, const EC_POINT* point, 
    const BIGNUM* exp)
{
  EC_POINT* ret = EC_POINT_new(params->group);
  CHECK_CALL(EC_POINT_mul(params->group, ret, NULL, point, exp, params->ctx));
  return ret;
}

void DsaParams_Invert(const_DsaParams params, EC_POINT* a)
{
  CHECK_CALL(EC_POINT_invert(params->group, a, params->ctx));
}

EC_POINT* DsaParams_Add(const_DsaParams params, const EC_POINT* a, const EC_POINT* b)
{
  EC_POINT* res = EC_POINT_new(params->group);
  CHECK_CALL(res);
  CHECK_CALL(a);
  CHECK_CALL(b);
  CHECK_CALL(params->ctx);
  EC_DEBUG("a", params->group, a, params->ctx);
  EC_DEBUG("b", params->group, b, params->ctx);
  CHECK_CALL(EC_POINT_add(params->group, res, a, b, params->ctx));
  return res;
}

back to top