Crypt-Nettle

 view release on metacpan or  search on metacpan

Nettle.xs  view on Meta::CPAN



enum cnc_cipher_mode {
  CNC_MODE_UNKNOWN,
  CNC_MODE_ECB,
  CNC_MODE_CBC,
  CNC_MODE_CTR
};
struct cnc_cipher_mode_name {
  enum cnc_cipher_mode mode;
  const char * name;
};

const struct cnc_cipher_mode_name cipher_modes_available[] = {
  { CNC_MODE_ECB, "ecb" },
  { CNC_MODE_CBC, "cbc" },
  { CNC_MODE_CTR, "ctr" }
};

STATIC
enum cnc_cipher_mode
_cnc_cipher_mode_lookup(const char* name) {
  int i;
  for (i = 0; i < sizeof(cipher_modes_available)/sizeof(*cipher_modes_available); i++)
    if (0 == strcasecmp(name, cipher_modes_available[i].name))
      return cipher_modes_available[i].mode;
  croak("Crypt::Nettle::Cipher: Bad Cipher Block Mode: %s", name);
  return CNC_MODE_UNKNOWN;
};

STATIC
const char *
_cnc_cipher_mode_name_lookup(enum cnc_cipher_mode mode) {
  int i;
  for (i = 0; i < sizeof(cipher_modes_available)/sizeof(*cipher_modes_available); i++)
    if (mode == cipher_modes_available[i].mode)
      return cipher_modes_available[i].name;

  croak("Crypt::Nettle::Cipher: Bad Cipher Block ID: %d (checked %d)", mode, i);
  return NULL;
}

struct Crypt_Nettle_Hash_s {
  const struct nettle_hash * hashtype;
  int is_hmac;
  void* hash_context;
};
typedef struct Crypt_Nettle_Hash_s *Crypt_Nettle_Hash;

struct Crypt_Nettle_Cipher_s {
  const struct nettle_cipher * ciphertype;
  int is_encrypt;
  enum cnc_cipher_mode mode;
  void* cipher_context;
  void* chain_state;
};
typedef struct Crypt_Nettle_Cipher_s *Crypt_Nettle_Cipher;

struct Crypt_Nettle_RSA_s {
  struct rsa_public_key * public_key;
  struct rsa_private_key * private_key;
};
typedef struct Crypt_Nettle_RSA_s *Crypt_Nettle_RSA;

typedef int(*_cnrsa_sign_func)(const struct rsa_private_key*, void*, mpz_t);
typedef int(*_cnrsa_verify_func)(const struct rsa_public_key*, void*, const mpz_t);

struct cnrsa_hash {
   const struct nettle_hash * hash;
   _cnrsa_sign_func sign;
   int (*sign_digest)(const struct rsa_private_key*, const uint8_t*, mpz_t);
   _cnrsa_verify_func verify;
   int (*verify_digest)(const struct rsa_public_key*, const uint8_t*, const mpz_t);
};

const struct cnrsa_hash 
_cnrsa_hashes_available[] = {
  { &nettle_md5, (_cnrsa_sign_func)rsa_md5_sign, rsa_md5_sign_digest, (_cnrsa_verify_func)rsa_md5_verify, rsa_md5_verify_digest },
  { &nettle_sha1, (_cnrsa_sign_func)rsa_sha1_sign, rsa_sha1_sign_digest, (_cnrsa_verify_func)rsa_sha1_verify, rsa_sha1_verify_digest },
  { &nettle_sha256, (_cnrsa_sign_func)rsa_sha256_sign, rsa_sha256_sign_digest, (_cnrsa_verify_func)rsa_sha256_verify, rsa_sha256_verify_digest },
  { &nettle_sha512, (_cnrsa_sign_func)rsa_sha512_sign, rsa_sha512_sign_digest, (_cnrsa_verify_func)rsa_sha512_verify, rsa_sha512_verify_digest }
};

STATIC
const struct cnrsa_hash *
_cnrsa_hash_lookup(const char* name) {
  int i;
  for (i = 0; i < sizeof(_cnrsa_hashes_available)/sizeof(*_cnrsa_hashes_available); i++)
    if (0 == strcasecmp(name, _cnrsa_hashes_available[i].hash->name))
      return _cnrsa_hashes_available+i;
  croak("Crypt::Nettle::RSA: Bad Digest: %s", name);
  return NULL;
};

STATIC
const struct cnrsa_hash *
_cnrsa_hash_lookup_by_hash(const struct nettle_hash * hash) {
  int i;
  if (NULL == hash)
     croak("Crypt::Nettle::RSA: Bad (NULL) Digest");
  for (i = 0; i < sizeof(_cnrsa_hashes_available)/sizeof(*_cnrsa_hashes_available); i++)
    if (hash == _cnrsa_hashes_available[i].hash)
      return _cnrsa_hashes_available+i;
  croak("Crypt::Nettle::RSA: Bad Digest: %s", hash->name);
  return NULL;
};

struct Crypt_Nettle_Yarrow_s {
  struct yarrow256_ctx  yarrow_ctx;
  /* FIXME: include sources here? */
};
typedef struct Crypt_Nettle_Yarrow_s *Crypt_Nettle_Yarrow;

STATIC
Crypt_Nettle_Hash
dereference_cnh(SV* sv_cnh) {
    if (!sv_derived_from(sv_cnh, "Crypt::Nettle::Hash"))
        croak("Not a Crypt::Nettle::Hash object");
    IV tmp = SvIV((SV*)SvRV(sv_cnh));
    return INT2PTR(Crypt_Nettle_Hash, tmp);
}

STATIC
Crypt_Nettle_Cipher
dereference_cnc(SV* sv_cnc) {
    if (!sv_derived_from(sv_cnc, "Crypt::Nettle::Cipher"))
        croak("Not a Crypt::Nettle::Cipher object");
    IV tmp = SvIV((SV*)SvRV(sv_cnc));
    return INT2PTR(Crypt_Nettle_Cipher, tmp);
}

Nettle.xs  view on Meta::CPAN

  int i;
  if (NULL == name)
    return NULL;
  for (i = 0; i < sizeof(cipher_algos_available)/sizeof(*cipher_algos_available); i++)
    if (0 == strncasecmp(name, cipher_algos_available[i]->name, 20))
      return cipher_algos_available[i];
  return NULL;
}



STATIC
void
_cnc_process(Crypt_Nettle_Cipher cnc, int datalen, const uint8_t * databuf, uint8_t * outbuf) {
  switch(cnc->mode) {
  case CNC_MODE_ECB:
    if (cnc->is_encrypt)
      cnc->ciphertype->encrypt(cnc->cipher_context, datalen, outbuf, databuf);
    else
      cnc->ciphertype->decrypt(cnc->cipher_context, datalen, outbuf, databuf);
    break;
  case CNC_MODE_CTR: /* encrypt and decrypt are the same function by definition in CTR mode */
    ctr_crypt(cnc->cipher_context, 
              cnc->ciphertype->encrypt,
              cnc->ciphertype->block_size,
              cnc->chain_state, 
              datalen,
              outbuf,
              databuf);
    break;
  case CNC_MODE_CBC:
    if (cnc->is_encrypt)
      cbc_encrypt(cnc->cipher_context, 
                  cnc->ciphertype->encrypt,
                  cnc->ciphertype->block_size,
                  cnc->chain_state, 
                  datalen,
                  outbuf,
                  databuf);
    else
      cbc_decrypt(cnc->cipher_context, 
                  cnc->ciphertype->encrypt,
                  cnc->ciphertype->block_size,
                  cnc->chain_state, 
                  datalen,
                  outbuf,
                  databuf);
    break;
  }
};


STATIC
void
_cnrsa_wipe(Crypt_Nettle_RSA cnrsa) {
  if (cnrsa->public_key) {
      rsa_public_key_clear(cnrsa->public_key);
      Safefree(cnrsa->public_key);
      cnrsa->public_key = NULL;
  }
  if (cnrsa->private_key) {
     rsa_private_key_clear(cnrsa->private_key);
     Safefree(cnrsa->private_key);
     cnrsa->private_key = NULL;
   }
   Safefree(cnrsa);
   cnrsa = NULL;
}


/* returns 1 if successful, 0 if there was a problem parsing */
STATIC
int
_mpz_setSV(mpz_t dst, SV* src) {
  if (SVt_IV == SvTYPE(src)) {
    mpz_set_ui(dst, SvIV(src));
    return 1;
  } else if (SVt_PV == SvTYPE(src)) {
    return (0 == mpz_set_str(dst, SvPV_nolen(src), 0));
  }
  return 0;
}

STATIC
int
_mpz_setSVraw(mpz_t dst, SV* src) {
  const char* sigdata;
  int siglen;
  char* hexdata;
  int ret;

  if (SVt_PV == SvTYPE(src)) {
    sigdata = SvPV(src, siglen);
    Newx(hexdata, BASE16_ENCODE_LENGTH(siglen) + 1, char);
    hexdata[BASE16_ENCODE_LENGTH(siglen)] = '\0';
    base16_encode_update(hexdata, siglen, sigdata);
    ret = (0 == mpz_set_str(dst, hexdata, 16));
    Safefree(hexdata);
    return ret;
  }
  return _mpz_setSV(dst, src);
}

STATIC
SV *
_newSV_from_mpz(mpz_t src) {
    int sz;
    char* buf;
    SV * ret;
    int offset = 0;

    sz = mpz_sizeinbase(src, 16) + 4;
 /* add two bytes for leading '0x' plus one byte for minus sign (shouldn't ever be set?)
    and for the trailing NULL */
    ret = newSVpv("", sz);
    buf = (char*) SvPV_nolen(ret);
    mpz_get_str(buf + 2, 16, src);
    if (mpz_sgn(src) < 0) {
      offset = 1;
      buf[0] = '-';
    }
    buf[offset] = '0';
    buf[offset + 1] = 'x';
    SvCUR_set(ret, sz - (2 - offset)); /* get rid of the trailing NULL */

Nettle.xs  view on Meta::CPAN

    PREINIT:
        uint8_t * outbuf;
    CODE:
        RETVAL = newSVpv("", len);
        outbuf = SvPV_nolen(RETVAL);
        yarrow256_random(&cny->yarrow_ctx, len, outbuf);
    OUTPUT:
        RETVAL

int
cny_is_seeded(cny)
    Crypt_Nettle_Yarrow cny;
    CODE:
        RETVAL=yarrow256_is_seeded(&cny->yarrow_ctx);
    OUTPUT:
        RETVAL

void
cny_DESTROY(cny)
  Crypt_Nettle_Yarrow cny;
CODE:
{
  Safefree(cny);
  cny = NULL;
}


MODULE = Crypt::Nettle        PACKAGE = Crypt::Nettle::RSA    PREFIX = cnrsa_

void
cnrsa_hashes_available()
    PREINIT:
        int i;
    PPCODE:
        for (i = 0; i < sizeof(_cnrsa_hashes_available)/sizeof(*_cnrsa_hashes_available); i++)
          XPUSHs(sv_2mortal(newSVpv(_cnrsa_hashes_available[i].hash->name, 0)));


Crypt_Nettle_RSA
cnrsa_new_public_key(classname, n, e)
    const char * classname;
    SV * n;
    SV * e;
    CODE:
        if (0 != strcmp("Crypt::Nettle::RSA", classname))
            croak("Crypt::Nettle::RSA->new_public_key() was somehow called wrong");
        Newxz(RETVAL, 1, struct Crypt_Nettle_RSA_s);
        Newxz(RETVAL->public_key, 1, struct rsa_public_key);
        rsa_public_key_init(RETVAL->public_key);
        if (_mpz_setSV(RETVAL->public_key->n, n) &&
            _mpz_setSV(RETVAL->public_key->e, e) &&
            rsa_public_key_prepare(RETVAL->public_key)) {
          /* success setting everything up!  we don't need to do anything */
        } else {
          _cnrsa_wipe(RETVAL); XSRETURN_UNDEF;
        }
    OUTPUT:
        RETVAL

Crypt_Nettle_RSA
cnrsa_new_private_key(classname, d, p, q)
    const char * classname;
    SV * d;
    SV * p;
    SV * q;
    PREINIT:
        mpz_t p1,q1,phi;
    CODE:
        if (0 != strcmp("Crypt::Nettle::RSA", classname))
            croak("Crypt::Nettle::RSA->new_private_key() was somehow called wrong");
        Newxz(RETVAL, 1, struct Crypt_Nettle_RSA_s);
        Newxz(RETVAL->private_key, 1, struct rsa_private_key);
        Newxz(RETVAL->public_key, 1, struct rsa_public_key);
        rsa_private_key_init(RETVAL->private_key);
        rsa_public_key_init(RETVAL->public_key);
        if (_mpz_setSV(RETVAL->private_key->d, d) &&
            _mpz_setSV(RETVAL->private_key->p, p) &&
            _mpz_setSV(RETVAL->private_key->q, q) &&
            mpz_invert(RETVAL->private_key->c, RETVAL->private_key->q, RETVAL->private_key->p) /* c = q^{-1} (mod p) */
           ) {
          /* success setting up the standard parameters!
             now fill in the auxiliary ones: */
          mpz_init(p1); mpz_init(q1); mpz_init(phi);
          mpz_sub_ui(p1, RETVAL->private_key->p, 1);
          mpz_sub_ui(q1, RETVAL->private_key->q, 1);
          mpz_mul(phi, p1, q1);
          /* a = d % (p-1) */
          mpz_fdiv_r(RETVAL->private_key->a, RETVAL->private_key->d, p1);
          /* b = d % (q-1) */
          mpz_fdiv_r(RETVAL->private_key->b, RETVAL->private_key->d, q1);
          mpz_mul(RETVAL->public_key->n, RETVAL->private_key->p, RETVAL->private_key->q);
          mpz_invert(RETVAL->public_key->e, RETVAL->private_key->d, phi);
          mpz_clear(p1); mpz_clear(q1); mpz_clear(phi);
          if (!(rsa_private_key_prepare(RETVAL->private_key) &&
                rsa_public_key_prepare(RETVAL->public_key))) {
            _cnrsa_wipe(RETVAL); XSRETURN_UNDEF;
          }
        } else {
            _cnrsa_wipe(RETVAL); XSRETURN_UNDEF;
        }
    OUTPUT:
        RETVAL


Crypt_Nettle_RSA
cnrsa_generate_keypair(classname, y, n_size, e=65537)
    const char * classname;
    Crypt_Nettle_Yarrow y;
    unsigned n_size;
    unsigned e;
    CODE:
        if (0 != strcmp("Crypt::Nettle::RSA", classname))
            croak("Crypt::Nettle::RSA->new_private_key() was somehow called wrong");
        Newxz(RETVAL, 1, struct Crypt_Nettle_RSA_s);
        Newxz(RETVAL->private_key, 1, struct rsa_private_key);
        rsa_private_key_init(RETVAL->private_key);
        Newxz(RETVAL->public_key, 1, struct rsa_public_key);
        rsa_public_key_init(RETVAL->public_key);
        mpz_set_ui(RETVAL->public_key->e, e);
        if (!rsa_generate_keypair(RETVAL->public_key,
                                  RETVAL->private_key,
                                  &y->yarrow_ctx, /* yarrow the only PRNG we allow at the moment */
                                  (nettle_random_func *) yarrow256_random,
                                  NULL, NULL, /* No progress meters */
                                  n_size, 0)) {
           _cnrsa_wipe(RETVAL); XSRETURN_UNDEF;
        }
    OUTPUT:
        RETVAL

SV *
cnrsa_rsa_sign_hash_context(cnrsa, cnh)
    Crypt_Nettle_RSA cnrsa;
    Crypt_Nettle_Hash cnh;
    PREINIT:
        mpz_t sig;
        const struct cnrsa_hash * hashtype;
        int ret;
    CODE:
        if (NULL == cnrsa->private_key)
           XSRETURN_UNDEF;
        if (cnh->is_hmac)
           XSRETURN_UNDEF;
        hashtype = _cnrsa_hash_lookup_by_hash(cnh->hashtype);
        if (NULL == hashtype)
           XSRETURN_UNDEF;
        mpz_init(sig);
        ret = hashtype->sign(cnrsa->private_key, cnh->hash_context, sig);
        if (0 == ret) {
           mpz_clear(sig);
           XSRETURN_UNDEF;
        }        
        RETVAL = _newSVraw_from_mpz(sig);
        mpz_clear(sig);
OUTPUT:
    RETVAL

SV *
cnrsa_rsa_sign_digest(cnrsa, algo, digest)
    Crypt_Nettle_RSA cnrsa;
    const char * algo;
    SV * digest;
    PREINIT:
        mpz_t sig;
        int ret;
        const struct cnrsa_hash * hashtype;
        int digestlen;
        const char* digestdata;
    CODE:
        if (NULL == cnrsa->private_key)
           XSRETURN_UNDEF;
        hashtype = _cnrsa_hash_lookup(algo);
        if (NULL == hashtype)
           XSRETURN_UNDEF;
        digestdata = SvPV(digest, digestlen);
        if (digestlen != hashtype->hash->digest_size) {
           croak("Digest should have been %d length; was %d", hashtype->hash->digest_size, digestlen); XSRETURN_UNDEF;
        }
        mpz_init(sig);
        ret = hashtype->sign_digest(cnrsa->private_key, digestdata, sig);
        if (0 == ret) {
           mpz_clear(sig);
           XSRETURN_UNDEF;
        }        
        RETVAL = _newSVraw_from_mpz(sig);
        mpz_clear(sig);
OUTPUT:
    RETVAL

int
cnrsa_rsa_verify_hash_context(cnrsa, cnh, signature)
    Crypt_Nettle_RSA cnrsa;
    Crypt_Nettle_Hash cnh;
    SV * signature;
    PREINIT:
        mpz_t sig;
        const struct cnrsa_hash * hashtype;
    CODE:
        if (NULL == cnrsa->public_key)
           XSRETURN_UNDEF;
        if (cnh->is_hmac)
           XSRETURN_UNDEF;
        hashtype = _cnrsa_hash_lookup_by_hash(cnh->hashtype);
        if (NULL == hashtype)
           XSRETURN_UNDEF;
        mpz_init(sig);
        if (!_mpz_setSVraw(sig, signature)) {
           mpz_clear(sig); XSRETURN_UNDEF;
        }
        RETVAL = hashtype->verify(cnrsa->public_key, cnh->hash_context, sig);
        mpz_clear(sig);
OUTPUT:
    RETVAL

int
cnrsa_rsa_verify_digest(cnrsa, algo, digest, signature)
    Crypt_Nettle_RSA cnrsa;
    const char* algo;
    SV * digest;
    SV * signature;
    PREINIT:
        mpz_t sig;
        int digestlen;
        const char* digestdata;
        const struct cnrsa_hash * hashtype;
    CODE:
        if (NULL == cnrsa->public_key)
           XSRETURN_UNDEF;
        hashtype = _cnrsa_hash_lookup(algo);
        if (NULL == hashtype)
           XSRETURN_UNDEF;
        digestdata = SvPV(digest, digestlen);
        if (digestlen != hashtype->hash->digest_size) {
           croak("Digest should have been %d length; was %d", hashtype->hash->digest_size, digestlen); XSRETURN_UNDEF;
        }

        mpz_init(sig);
        if (!_mpz_setSVraw(sig, signature)) {
           mpz_clear(sig); XSRETURN_UNDEF;
        }
        RETVAL = hashtype->verify_digest(cnrsa->public_key, digestdata, sig);
        mpz_clear(sig);
OUTPUT:
    RETVAL



SV *
cnrsa_key_params(cnrsa)
    Crypt_Nettle_RSA cnrsa;
    PREINIT:
        HV * targ;
    CODE:
        targ = (HV *)sv_2mortal((SV *)newHV());
        if (NULL != cnrsa->public_key) {
           if (mpz_sgn(cnrsa->public_key->n)) hv_store(targ, "n", 1, _newSV_from_mpz(cnrsa->public_key->n), 0);
           if (mpz_sgn(cnrsa->public_key->e)) hv_store(targ, "e", 1, _newSV_from_mpz(cnrsa->public_key->e), 0);
        }
        if (NULL != cnrsa->private_key) {
           if (mpz_sgn(cnrsa->private_key->d)) hv_store(targ, "d", 1, _newSV_from_mpz(cnrsa->private_key->d), 0);
           if (mpz_sgn(cnrsa->private_key->p)) hv_store(targ, "p", 1, _newSV_from_mpz(cnrsa->private_key->p), 0);
           if (mpz_sgn(cnrsa->private_key->q)) hv_store(targ, "q", 1, _newSV_from_mpz(cnrsa->private_key->q), 0);
           if (mpz_sgn(cnrsa->private_key->a)) hv_store(targ, "a", 1, _newSV_from_mpz(cnrsa->private_key->a), 0);
           if (mpz_sgn(cnrsa->private_key->b)) hv_store(targ, "b", 1, _newSV_from_mpz(cnrsa->private_key->b), 0);
           if (mpz_sgn(cnrsa->private_key->c)) hv_store(targ, "c", 1, _newSV_from_mpz(cnrsa->private_key->c), 0);
         }
        RETVAL = newRV((SV*)targ);
    OUTPUT:
        RETVAL

void
cnrsa_DESTROY(cnrsa)
    Crypt_Nettle_RSA cnrsa;
    CODE:
        _cnrsa_wipe(cnrsa);



( run in 2.471 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )