diff options
author | Lance Kinley <lkinley@loyaltymethods.com> | 2016-05-04 10:18:39 -0700 |
---|---|---|
committer | karel-m <karel.miko@gmail.com> | 2016-05-04 19:18:39 +0200 |
commit | 6d2813f83821ca3be2732007b124541e5e58c88b (patch) | |
tree | 14f99a999fbfad7aed4963cac7bc75bb7af4032b /inc | |
parent | 82e9371dc4f76a68747db1dbd7035f4eaa694b33 (diff) |
Enhance Crypt::PK::DH (#10)
Crypt::PK::DH - accept base/prime values
Diffstat (limited to 'inc')
-rw-r--r-- | inc/CryptX_PK_DH.xs.inc | 215 |
1 files changed, 204 insertions, 11 deletions
diff --git a/inc/CryptX_PK_DH.xs.inc b/inc/CryptX_PK_DH.xs.inc index 0b84056d..52d14a45 100644 --- a/inc/CryptX_PK_DH.xs.inc +++ b/inc/CryptX_PK_DH.xs.inc @@ -17,7 +17,7 @@ _new() RETVAL void -generate_key(Crypt::PK::DH self, int key_size=256) +_generate_key(Crypt::PK::DH self, int key_size=256) PPCODE: { int rv; @@ -31,6 +31,28 @@ generate_key(Crypt::PK::DH self, int key_size=256) } void +_generate_key_ex(Crypt::PK::DH self, SV * g, SV * p) + PPCODE: + { + int rv; + STRLEN p_len = 0; + STRLEN g_len = 0; + unsigned char *p_ptr=NULL; + unsigned char *g_ptr=NULL; + + p_ptr = (unsigned char *)SvPVbyte(p, p_len); + g_ptr = (unsigned char *)SvPVbyte(g, g_len); + + /* add a small random entropy before generating key - not necessary as we have initialized prng with 256bit entropy in _new() */ + rv = rng_make_prng(64, self->yarrow_prng_index, &self->yarrow_prng_state, NULL); + if (rv != CRYPT_OK) croak("FATAL: rng_make_prng failed: %s", error_to_string(rv)); + /* gen the key */ + rv = dh_make_key_ex(&self->yarrow_prng_state, self->yarrow_prng_index, (const char *) g_ptr, (const char *) p_ptr, &self->key); + if (rv != CRYPT_OK) croak("FATAL: dh_make_key_ex failed: %s", error_to_string(rv)); + XPUSHs(ST(0)); /* return self */ + } + +void _import(Crypt::PK::DH self, SV * key_data) PPCODE: { @@ -45,6 +67,33 @@ _import(Crypt::PK::DH self, SV * key_data) XPUSHs(ST(0)); /* return self */ } +void +_import_raw(Crypt::PK::DH self, SV * raw_key, int type, char * g, char * p) + PPCODE: + { + int rv; + unsigned char *data=NULL; + STRLEN data_len=0; + + data = (unsigned char *)SvPVbyte(raw_key, data_len); + if (self->key.type != -1) { dh_free(&self->key); self->key.type = -1; } + /* public */ + if (type == 0) { + rv = dh_import_raw(data, (unsigned long)data_len, PK_PUBLIC, g, p, &self->key); + if (rv != CRYPT_OK) croak("FATAL: dh_import_raw failed: %s", error_to_string(rv)); + } + /* private */ + else if (type == 1) { + rv = dh_import_raw(data, (unsigned long)data_len, PK_PRIVATE, g, p, &self->key); + if (rv != CRYPT_OK) croak("FATAL: dh_import_raw failed: %s", error_to_string(rv)); + } + else { + croak("FATAL: import_raw invalid type '%d'", type); + } + + XPUSHs(ST(0)); /* return self */ + } + int is_private(Crypt::PK::DH self) CODE: @@ -95,9 +144,31 @@ key2hash(Crypt::PK::DH self) else{ not_used = hv_store(rv_hash, "y", 1, newSVpv("", 0), 0); } - /* =====> name */ - snprintf(buf, sizeof(buf), "DH-%d", dh_get_size(&self->key)*8); - not_used = hv_store(rv_hash, "name", 4, newSVpv(buf, strlen(buf)), 0); + /* =====> p */ + siz = (self->key.prime) ? mp_unsigned_bin_size(self->key.prime) : 0; + if (siz>10000) { + croak("FATAL: key2hash failed - 'p' too big number"); + } + if (siz>0) { + mp_tohex(self->key.prime, buf); + not_used = hv_store(rv_hash, "p", 1, newSVpv(buf, strlen(buf)), 0); + } + else { + not_used = hv_store(rv_hash, "p", 1, newSVpv("", 0), 0); + } + + /* =====> g */ + siz = (self->key.base) ? mp_unsigned_bin_size(self->key.base) : 0; + if (siz>10000) { + croak("FATAL: key2hash failed - 'g' too big number"); + } + if (siz>0) { + mp_tohex(self->key.base, buf); + not_used = hv_store(rv_hash, "g", 1, newSVpv(buf, strlen(buf)), 0); + } + else { + not_used = hv_store(rv_hash, "g", 1, newSVpv("", 0), 0); + } /* =====> size */ not_used = hv_store(rv_hash, "size", 4, newSViv(dh_get_size(&self->key)), 0); /* =====> type */ @@ -107,13 +178,53 @@ key2hash(Crypt::PK::DH self) OUTPUT: RETVAL +SV* +params2hash(Crypt::PK::DH self) + PREINIT: + HV *rv_hash; + long siz; + char buf[20001]; + SV **not_used; + CODE: + if (self->key.type == -1) XSRETURN_UNDEF; + rv_hash = newHV(); + /* =====> p */ + siz = (self->key.prime) ? mp_unsigned_bin_size(self->key.prime) : 0; + if (siz>10000) { + croak("FATAL: key2hash failed - 'p' too big number"); + } + if (siz>0) { + mp_tohex(self->key.prime, buf); + not_used = hv_store(rv_hash, "p", 1, newSVpv(buf, strlen(buf)), 0); + } + else { + not_used = hv_store(rv_hash, "p", 1, newSVpv("", 0), 0); + } + + /* =====> g */ + siz = (self->key.base) ? mp_unsigned_bin_size(self->key.base) : 0; + if (siz>10000) { + croak("FATAL: key2hash failed - 'g' too big number"); + } + if (siz>0) { + mp_tohex(self->key.base, buf); + not_used = hv_store(rv_hash, "g", 1, newSVpv(buf, strlen(buf)), 0); + } + else { + not_used = hv_store(rv_hash, "g", 1, newSVpv("", 0), 0); + } + if (not_used) not_used = NULL; /* just silence the warning: variable 'not_used' set but not used */ + RETVAL = newRV_noinc((SV*)rv_hash); + OUTPUT: + RETVAL + SV * export_key(Crypt::PK::DH self, char * type) CODE: { int rv; - unsigned char out[4096]; unsigned long int out_len = 4096; + unsigned char out[out_len]; RETVAL = newSVpvn(NULL, 0); /* undef */ if (strnEQ(type, "private", 7)) { @@ -140,8 +251,8 @@ _encrypt(Crypt::PK::DH self, SV * data, char * hash_name) int rv, hash_id; unsigned char *data_ptr=NULL; STRLEN data_len=0; - unsigned char buffer[1024]; unsigned long buffer_len = 1024; + unsigned char buffer[buffer_len]; data_ptr = (unsigned char *)SvPVbyte(data, data_len); @@ -163,13 +274,13 @@ _decrypt(Crypt::PK::DH self, SV * data) int rv; unsigned char *data_ptr=NULL; STRLEN data_len=0; - unsigned char buffer[1024]; unsigned long buffer_len = 1024; + unsigned char buffer[buffer_len]; data_ptr = (unsigned char *)SvPVbyte(data, data_len); rv = dh_decrypt_key(data_ptr, (unsigned long)data_len, buffer, &buffer_len, &self->key); - if (rv != CRYPT_OK) croak("FATAL: dh_decrypt_key_ex failed: %s", error_to_string(rv)); + if (rv != CRYPT_OK) croak("FATAL: dh_decrypt_key failed: %s", error_to_string(rv)); RETVAL = newSVpvn((char*)buffer, buffer_len); } OUTPUT: @@ -182,15 +293,15 @@ _sign(Crypt::PK::DH self, SV * data) int rv; unsigned char *data_ptr=NULL; STRLEN data_len=0; - unsigned char buffer[1024]; unsigned long buffer_len = 1024; + unsigned char buffer[buffer_len]; data_ptr = (unsigned char *)SvPVbyte(data, data_len); rv = dh_sign_hash(data_ptr, (unsigned long)data_len, buffer, &buffer_len, &self->yarrow_prng_state, self->yarrow_prng_index, &self->key); - if (rv != CRYPT_OK) croak("FATAL: dh_sign_hash_ex failed: %s", error_to_string(rv)); + if (rv != CRYPT_OK) croak("FATAL: dh_sign_hash failed: %s", error_to_string(rv)); RETVAL = newSVpvn((char*)buffer, buffer_len); } OUTPUT: @@ -221,8 +332,8 @@ shared_secret(Crypt::PK::DH self, Crypt::PK::DH pubkey) CODE: { int rv; - unsigned char buffer[1024]; unsigned long buffer_len = 1024; + unsigned char buffer[buffer_len]; rv = dh_shared_secret(&self->key, &pubkey->key, buffer, &buffer_len); if (rv != CRYPT_OK) croak("FATAL: dh_shared_secret failed: %s", error_to_string(rv)); @@ -231,6 +342,88 @@ shared_secret(Crypt::PK::DH self, Crypt::PK::DH pubkey) OUTPUT: RETVAL +SV * +export_key_raw(Crypt::PK::DH self, char * type) + CODE: + { + int rv, len; + unsigned long buffer_len = 1024; + unsigned char buffer[buffer_len]; + void *key; + + RETVAL = newSVpvn(NULL, 0); /* undef */ + if (strnEQ(type, "private", 7)) { + key = self->key.x; + } + else if (strnEQ(type, "public", 6)) { + key = self->key.y; + } + else { + croak("FATAL: export_key_raw: invalid type '%s'", type); + } + + len = (unsigned long)mp_unsigned_bin_size(key); + if (buffer_len < len) { + croak("FATAL: %s", error_to_string(CRYPT_BUFFER_OVERFLOW)); + } + rv = mp_to_unsigned_bin(key, buffer); + if (rv != CRYPT_OK) croak("FATAL: %s", error_to_string(rv)); + RETVAL = newSVpvn((char*)buffer, len); + } + OUTPUT: + RETVAL + +int +_is_pubkey_valid(Crypt::PK::DH self); + CODE: + { + int rv, i, bits_set = 0; + mp_int one, two, p1, *y; + mp_digit digit; + + if ((rv = mp_init_multi(&one, &two, &p1, NULL)) != MP_OKAY) { + croak("FATAL: %s", error_to_string(rv)); + } + + y = self->key.y; + mp_set(&one, 1); + mp_set(&two, 2); + + /* p1 = p-1 */ + if ((rv = mp_sub(self->key.prime, &one, &p1)) != MP_OKAY) { + croak("FATAL: %s", error_to_string(rv)); + } + /* valid public key cannot be negative */ + if (y->sign == MP_NEG) { + RETVAL = 0; + } + /* valid public key != 1 */ + else if (mp_cmp(y, &one) == MP_EQ) { + RETVAL = 0; + } + /* public key cannot be > p-1 */ + else if (mp_cmp(y, &p1) == MP_GT) { + RETVAL = 0; + } + /* if base == 2, public must have more than one bit set */ + else if (mp_cmp(self->key.base, &two) == MP_EQ) { + for (i = 0; i < y->used; i++) { + digit = y->dp[i]; + while (digit > ((mp_digit) 0)) { + if (digit & ((mp_digit) 1)) + bits_set++; + digit >>= ((mp_digit) 1); + } + } + if (bits_set > 1) + RETVAL = 1; + else RETVAL = 0; + } + else RETVAL = 1; + } + OUTPUT: + RETVAL + void DESTROY(Crypt::PK::DH self) CODE: |