summaryrefslogtreecommitdiff
path: root/inc
diff options
context:
space:
mode:
authorLance Kinley <lkinley@loyaltymethods.com>2016-05-04 10:18:39 -0700
committerkarel-m <karel.miko@gmail.com>2016-05-04 19:18:39 +0200
commit6d2813f83821ca3be2732007b124541e5e58c88b (patch)
tree14f99a999fbfad7aed4963cac7bc75bb7af4032b /inc
parent82e9371dc4f76a68747db1dbd7035f4eaa694b33 (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.inc215
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: