Crypt-Nettle

 view release on metacpan or  search on metacpan

Nettle.xs  view on Meta::CPAN

  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 }

Nettle.xs  view on Meta::CPAN



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) {

Nettle.xs  view on Meta::CPAN

            _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 *

Nettle.xs  view on Meta::CPAN

    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

Nettle.xs  view on Meta::CPAN

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

lib/Crypt/Nettle/RSA.pm  view on Meta::CPAN

 my @algos = Crypt::Nettle::RSA::hashes_available();

=head1 KEY CREATION

=head2 new_public_key($n, $e)

Create a new public key from the modulus and the exponent of the
public key. (see DATA REPRESENTATIONS below for how to format $n and
$e)

=head2 new_private_key($d, $p, $q)

Create a new private key from the private exponent and the two prime
factors. (see DATA REPRESENTATIONS below for how to format $d, $p and
$q)

=head2 generate_keypair($yarrow, $bits, $e = 65537)

Create a new private key of size $bits from a well-seeded random
number generator (see Crypt::Nettle::Yarrow).  You can select the
exponent manually via $e, though the default is probably fine.


=head1 KEY USE

=head2 rsa_sign($digest_algo, $data)

Return a packed binary string that is the key's signature over $data.

 my $sig = $private_key->rsa_sign('sha1', 'This is a test message');
 printf('Signature: 0x%s\n', unpack('H*', $sig));

Returns undefined if there was an error.

=head2 rsa_verify($digest_algo, $data, $signature)

Returns 1 if this public key was the author of $signature over $data.

Returns 0 if the signature did not check out.

Return undefined if there was an error.

 my $ret = $private_key->rsa_verify('sha1', 'This is a test message', $sig);
 printf('Signature: %s\n', (defined($ret) ? ($ret ? 'OK' : 'BAD') : 'ERROR'));

=head2 rsa_sign_hash_context($hash_ctx)

=head2 rsa_verify_hash_context($hash_ctx, $signature)

These functions let you pass a Crypt::Nettle::Digest object for RSA
signature/verification instead of needing to keep the entire $data in
memory.  Here's signing:

 my $hash = Crypt::Nettle::Hash->new('sha1');
 $hash->update($data);
 # ... more update()s ...
 my $sig = $private_key->rsa_sign_hash_context($hash);

And verifying:

 my $hash = Crypt::Nettle::Hash->new('sha1');
 $hash->update($data);
 # ... more update()s ...
 my $ok = $public_key->rsa_verify_hash_context($hash, $sig);

Note that the $hash_ctx will be re-initialized after calling either of
these functions.  If you don't want that to happen, consider passing

lib/Crypt/Nettle/RSA.pm  view on Meta::CPAN

=head2 rsa_verify_hash_context($hash_ctx, $signature)

These functions let you pass a raw digest for RSA
signature/verification instead of needing to keep the entire $data in
memory.  Here's signing:

 my $hash = Crypt::Nettle::Hash->new('sha1');
 $hash->update($data);
 # ... more update()s ...
 my $digest = $hash->digest();
 my $sig = $private_key->rsa_sign_digest('sha1', $digest);

And verifying:

 my $hash = Crypt::Nettle::Hash->new('sha1');
 $hash->update($data);
 # ... more update()s ...
 my $digest = $hash->digest();
 my $ok = $public_key->rsa_verify_hash_context($digest, $sig);

=head2 WARNING ABOUT CRYPTOGRAPHIC BLINDING

t/05-rsa.t  view on Meta::CPAN

my @digests = sort(@{$digest_algos});
while (@reported_digests) {
  my $modea = shift(@digests);
  my $modeb = shift(@reported_digests);
  ok($modea eq $modeb);
}
ok(0 == scalar(@digests));


my $pubkey = Crypt::Nettle::RSA->new_public_key($n, $e);
my $privkey = Crypt::Nettle::RSA->new_private_key($d, $p, $q);

ok(defined($pubkey));
ok(defined($privkey));

ok($n eq $pubkey->key_params()->{'n'});
ok($e eq $pubkey->key_params()->{'e'});

ok($n eq $privkey->key_params()->{'n'});
ok($e eq $privkey->key_params()->{'e'});
ok($p eq $privkey->key_params()->{'p'});



( run in 0.271 second using v1.01-cache-2.11-cpan-a5abf4f5562 )