summaryrefslogtreecommitdiff
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
parent82e9371dc4f76a68747db1dbd7035f4eaa694b33 (diff)
Enhance Crypt::PK::DH (#10)
Crypt::PK::DH - accept base/prime values
-rw-r--r--inc/CryptX_PK_DH.xs.inc215
-rw-r--r--lib/Crypt/PK/DH.pm257
-rw-r--r--src/ltc/headers/tomcrypt_pk.h6
-rw-r--r--src/ltc/pk/dh/dh.c210
-rwxr-xr-xsrc/ltc/pk/dh/dh_static.c2
-rwxr-xr-xsrc/ltc/pk/dh/dh_static.h2
-rwxr-xr-xsrc/ltc/pk/dh/dh_sys.c53
-rw-r--r--t/data/cryptx_priv_dh_pg1.binbin0 -> 791 bytes
-rw-r--r--t/data/cryptx_priv_dh_pg2.binbin0 -> 791 bytes
-rw-r--r--t/data/cryptx_pub_dh_pg1.binbin0 -> 531 bytes
-rw-r--r--t/data/cryptx_pub_dh_pg2.binbin0 -> 531 bytes
-rw-r--r--t/pk_dh.t127
12 files changed, 787 insertions, 85 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:
diff --git a/lib/Crypt/PK/DH.pm b/lib/Crypt/PK/DH.pm
index 8aab025a..85a0fcfc 100644
--- a/lib/Crypt/PK/DH.pm
+++ b/lib/Crypt/PK/DH.pm
@@ -11,7 +11,160 @@ our @EXPORT = qw();
use Carp;
use CryptX;
use Crypt::Digest 'digest_data';
-use Crypt::Misc qw(read_rawfile encode_b64u decode_b64u encode_b64 decode_b64);
+use Crypt::Misc qw(read_rawfile);
+
+my %DH_PARAMS = (
+ ike768 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF'
+ },
+ ike1024 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381'.
+ 'FFFFFFFFFFFFFFFF'
+ },
+ ike1536 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D'.
+ 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F'.
+ '83655D23DCA3AD961C62F356208552BB9ED529077096966D'.
+ '670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF'
+ },
+ ike2048 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D'.
+ 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F'.
+ '83655D23DCA3AD961C62F356208552BB9ED529077096966D'.
+ '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B'.
+ 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9'.
+ 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510'.
+ '15728E5A8AACAA68FFFFFFFFFFFFFFFF'
+ },
+ ike3072 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D'.
+ 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F'.
+ '83655D23DCA3AD961C62F356208552BB9ED529077096966D'.
+ '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B'.
+ 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9'.
+ 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510'.
+ '15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64'.
+ 'ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7'.
+ 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B'.
+ 'F12FFA06D98A0864D87602733EC86A64521F2B18177B200C'.
+ 'BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31'.
+ '43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF'
+ },
+ ike4096 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D'.
+ 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F'.
+ '83655D23DCA3AD961C62F356208552BB9ED529077096966D'.
+ '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B'.
+ 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9'.
+ 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510'.
+ '15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64'.
+ 'ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7'.
+ 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B'.
+ 'F12FFA06D98A0864D87602733EC86A64521F2B18177B200C'.
+ 'BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31'.
+ '43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7'.
+ '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA'.
+ '2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6'.
+ '287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED'.
+ '1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9'.
+ '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199'.
+ 'FFFFFFFFFFFFFFFF'
+ },
+ ike6144 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D'.
+ 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F'.
+ '83655D23DCA3AD961C62F356208552BB9ED529077096966D'.
+ '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B'.
+ 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9'.
+ 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510'.
+ '15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64'.
+ 'ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7'.
+ 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B'.
+ 'F12FFA06D98A0864D87602733EC86A64521F2B18177B200C'.
+ 'BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31'.
+ '43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7'.
+ '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA'.
+ '2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6'.
+ '287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED'.
+ '1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9'.
+ '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492'.
+ '36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD'.
+ 'F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831'.
+ '179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B'.
+ 'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF'.
+ '5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6'.
+ 'D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3'.
+ '23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA'.
+ 'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328'.
+ '06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C'.
+ 'DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE'.
+ '12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF'
+ },
+ ike8192 => { g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1'.
+ '29024E088A67CC74020BBEA63B139B22514A08798E3404DD'.
+ 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245'.
+ 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED'.
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D'.
+ 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F'.
+ '83655D23DCA3AD961C62F356208552BB9ED529077096966D'.
+ '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B'.
+ 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9'.
+ 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510'.
+ '15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64'.
+ 'ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7'.
+ 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B'.
+ 'F12FFA06D98A0864D87602733EC86A64521F2B18177B200C'.
+ 'BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31'.
+ '43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7'.
+ '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA'.
+ '2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6'.
+ '287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED'.
+ '1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9'.
+ '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492'.
+ '36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD'.
+ 'F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831'.
+ '179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B'.
+ 'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF'.
+ '5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6'.
+ 'D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3'.
+ '23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA'.
+ 'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328'.
+ '06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C'.
+ 'DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE'.
+ '12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4'.
+ '38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300'.
+ '741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568'.
+ '3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9'.
+ '22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B'.
+ '4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A'.
+ '062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36'.
+ '4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1'.
+ 'B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92'.
+ '4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47'.
+ '9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71'.
+ '60C980DD98EDD3DFFFFFFFFFFFFFFFFF'
+ }
+);
sub new {
my ($class, $f) = @_;
@@ -37,6 +190,34 @@ sub import_key {
return $self->_import($data);
}
+sub import_key_raw {
+ my ($self, $raw_bytes, $type, $param) = @_;
+ my ($g, $p, $x, $y);
+
+ if (ref $param eq 'HASH') {
+ $g = $param->{g} or croak "FATAL: 'g' param not specified";
+ $p = $param->{p} or croak "FATAL: 'p' param not specified";
+ $g =~ s/^0x//;
+ $p =~ s/^0x//;
+ } elsif (my $dhparam = $DH_PARAMS{$param}) {
+ $g = $dhparam->{g};
+ $p = $dhparam->{p};
+ } else {
+ croak "FATAL: invalid parameter";
+ }
+
+ if ($type eq 'private') {
+ $type = 1;
+ } elsif ($type eq 'public') {
+ $type = 0;
+ } else {
+ croak "FATAL: invalid key type '$type'";
+ }
+ my $rv = $self->_import_raw($raw_bytes, $type, $g, $p);
+ croak "FATAL: invalid public key" unless $self->_is_pubkey_valid;
+ return $rv;
+}
+
sub encrypt {
my ($self, $data, $hash_name) = @_;
$hash_name = Crypt::Digest::_trans_digest_name($hash_name||'SHA1');
@@ -72,6 +253,24 @@ sub verify_hash {
return $self->_verify($sig, $data_hash);
}
+sub generate_key {
+ my ($key,$param) = @_;
+
+ if (!ref $param) {
+ if (my $dhparam = $DH_PARAMS{$param}) {
+ $param = $dhparam;
+ } else {
+ croak "FATAL: invalid key length" unless ($param >= 96 || $param <= 512);
+ return $key->_generate_key($param);
+ }
+ }
+ my $g = $param->{g} or croak "FATAL: 'g' param not specified";
+ my $p = $param->{p} or croak "FATAL: 'p' param not specified";
+ $g =~ s/^0x//;
+ $p =~ s/^0x//;
+ return $key->_generate_key_ex($g, $p);
+}
+
### FUNCTIONS
sub dh_encrypt {
@@ -166,6 +365,20 @@ Crypt::PK::DH - Public key cryptography based on Diffie-Hellman
my $private = $pk->export_key('private');
my $public = $pk->export_key('public');
+ or
+
+ my $pk = Crypt::PK::DH->new();
+ $pk->generate_key('ike2048');
+ my $private = $pk->export_key('private');
+ my $public = $pk->export_key('public');
+
+ or
+
+ my $pk = Crypt::PK::DH->new();
+ $pk->generate_key({ p => $p, g => $g });
+ my $private = $pk->export_key('private');
+ my $public = $pk->export_key('public');
+
### Functional interface
#Encryption: Alice
@@ -208,6 +421,21 @@ random data taken from C</dev/random> (UNIX) or C<CryptGenRandom> (Win32).
# 384 => DH-3072
# 512 => DH-4096
+ $pk->generate_key($name)
+ ### $name corresponds to values defined in RFC7296 and RFC3526
+ # ike768 => 768-bit MODP (Group 1)
+ # ike1024 => 1024-bit MODP (Group 2)
+ # ike1536 => 1536-bit MODP (Group 5)
+ # ike2048 => 2048-bit MODP (Group 14)
+ # ike3072 => 3072-bit MODP (Group 15)
+ # ike4096 => 4096-bit MODP (Group 16)
+ # ike6144 => 6144-bit MODP (Group 17)
+ # ike8192 => 8192-bit MODP (Group 18)
+
+ $pk->generate_key($param_hash)
+ ## $param_hash is { g => $g, p => $p }
+ ## where $g is the generator (base) in a hex string and $p is the prime in a hex string
+
=head2 import_key
Loads private or public key (exported by L</export_key>).
@@ -216,12 +444,26 @@ Loads private or public key (exported by L</export_key>).
#or
$pk->import_key(\$buffer_containing_key);
+=head2 import_key_raw
+
+ $pk->import_key_raw($raw_bytes, $type, $params)
+ ### $raw_bytes is a binary string containing the key
+ ### $type is either 'private' or 'public'
+ ### $param is either a name ('ike2038') or hash containing the p,g values { g=>$g, p=>$p }
+ ### in hex strings
+
=head2 export_key
my $private = $pk->export_key('private');
#or
my $public = $pk->export_key('public');
+=head2 export_key_raw
+
+ $raw_bytes = $dh->export_key_raw('public')
+ #or
+ $raw_bytes = $dh->export_key_raw('private')
+
=head2 encrypt
my $pk = Crypt::PK::DH->new($pub_key_filename);
@@ -296,9 +538,20 @@ Loads private or public key (exported by L</export_key>).
{
type => 0, # integer: 1 .. private, 0 .. public
size => 256, # integer: key size in bytes
- name => "DH-2048", # internal libtomcrypt name
x => "FBC1062F73B9A17BB8473A2F5A074911FA7F20D28FB...", #private key
y => "AB9AAA40774D3CD476B52F82E7EE2D8A8D40CD88BF4...", #public key
+ g => "2", # generator/base
+ p => "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80D...", # prime
+}
+
+=head2 params2hash
+
+ my $params = $pk->params2hash;
+
+ # returns hash like this (or undef if no key loaded):
+ {
+ g => "2", # generator/base
+ p => "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80D...", # prime
}
=head1 FUNCTIONS
diff --git a/src/ltc/headers/tomcrypt_pk.h b/src/ltc/headers/tomcrypt_pk.h
index e18e9efa..8ad65ccc 100644
--- a/src/ltc/headers/tomcrypt_pk.h
+++ b/src/ltc/headers/tomcrypt_pk.h
@@ -176,6 +176,8 @@ typedef struct Dh_key {
int idx, type;
void *x;
void *y;
+ void *base;
+ void *prime;
} dh_key;
int dh_compat_test(void);
@@ -183,10 +185,14 @@ void dh_sizes(int *low, int *high);
int dh_get_size(dh_key *key);
int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key);
+int dh_make_key_ex(prng_state *prng, int wprng, const char *g, const char *p, dh_key *key);
+int dh_make_key_ex_main(prng_state *prng, int wprng, dh_key *key);
void dh_free(dh_key *key);
int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key);
int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key);
+int dh_import_raw(unsigned char *in, unsigned long inlen, int type,
+ const char *base, const char *prime, dh_key *key);
int dh_shared_secret(dh_key *private_key, dh_key *public_key,
unsigned char *out, unsigned long *outlen);
diff --git a/src/ltc/pk/dh/dh.c b/src/ltc/pk/dh/dh.c
index ec14b6dd..3b407687 100644
--- a/src/ltc/pk/dh/dh.c
+++ b/src/ltc/pk/dh/dh.c
@@ -95,6 +95,9 @@ void dh_sizes(int *low, int *high)
int dh_get_size(dh_key *key)
{
LTC_ARGCHK(key != NULL);
+ if (key->idx == SUPPLIED_PRIME) {
+ return mp_unsigned_bin_size(key->prime);
+ }
if (dh_is_valid_idx(key->idx) == 1) {
return sets[key->idx].size;
} else {
@@ -112,18 +115,9 @@ int dh_get_size(dh_key *key)
*/
int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key)
{
- unsigned char *buf;
unsigned long x;
- void *p, *g;
int err;
- LTC_ARGCHK(key != NULL);
-
- /* good prng? */
- if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
- return err;
- }
-
/* find key size */
for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++);
#ifdef FAST_PK
@@ -136,6 +130,72 @@ int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key)
}
key->idx = x;
+ if ((err = mp_init_multi(&key->base, &key->prime, NULL)) != CRYPT_OK) {
+ goto error;
+ }
+ if ((err = mp_read_radix(key->base, sets[key->idx].base, 64)) != CRYPT_OK) { goto error; }
+ if ((err = mp_read_radix(key->prime, sets[key->idx].prime, 64)) != CRYPT_OK) { goto error; }
+ return dh_make_key_ex_main(prng, wprng, key);
+error:
+ mp_clear_multi(key->base, key->prime, NULL);
+ return err;
+}
+
+/**
+ Make a DH key [private key pair] from provided base and prime
+ @param prng An active PRNG state
+ @param wprng The index for the PRNG you desire to use
+ @param keysize The key size (octets) desired
+ @param base The base (generator) to create the key from
+ @param prime The prime to create the key from
+ @param key [out] Where the newly created DH key will be stored
+ @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
+*/
+int dh_make_key_ex(prng_state *prng, int wprng, const char *base, const char *prime, dh_key *key)
+{
+ int err;
+
+ LTC_ARGCHK(base != NULL);
+ LTC_ARGCHK(prime != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* good prng? */
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = mp_init_multi(&key->base, &key->prime, NULL)) != CRYPT_OK) {
+ goto error;
+ }
+ if ((err = mp_read_radix(key->base, base, 16)) != CRYPT_OK) { goto error; }
+ if ((err = mp_read_radix(key->prime, prime, 16)) != CRYPT_OK) { goto error; }
+ key->idx = SUPPLIED_PRIME;
+ return dh_make_key_ex_main(prng, wprng, key);
+error:
+ mp_clear_multi(key->base, key->prime, NULL);
+ return err;
+}
+
+
+int dh_make_key_ex_main(prng_state *prng, int wprng, dh_key *key)
+{
+ unsigned char *buf;
+ int err, keysize;
+
+ LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(key->prime != NULL);
+ LTC_ARGCHK(key->base != NULL);
+
+ /* init parameters */
+ if ((err = mp_init_multi(&key->x, &key->y, NULL)) != CRYPT_OK) {
+ goto error;
+ }
+
+ keysize = dh_get_size(key);
+ if (keysize < 96) {
+ return CRYPT_INVALID_KEYSIZE;
+ }
+
/* allocate buffer */
buf = XMALLOC(keysize);
if (buf == NULL) {
@@ -143,8 +203,8 @@ int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key)
}
/* make up random string */
- if ( rng_make_prng( keysize, wprng, prng, NULL) != CRYPT_OK) {
- err = CRYPT_ERROR_READPRNG;
+ if ( (err = rng_make_prng( keysize, wprng, prng, NULL)) != CRYPT_OK) {
+ /*err = CRYPT_ERROR_READPRNG;*/
goto error2;
}
@@ -153,26 +213,17 @@ int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key)
goto error2;
}
- /* init parameters */
- if ((err = mp_init_multi(&g, &p, &key->x, &key->y, NULL)) != CRYPT_OK) {
- goto error;
- }
-
- if ((err = mp_read_radix(g, sets[key->idx].base, 64)) != CRYPT_OK) { goto error; }
- if ((err = mp_read_radix(p, sets[key->idx].prime, 64)) != CRYPT_OK) { goto error; }
-
/* load the x value */
- if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) { goto error; }
- if ((err = mp_exptmod(g, key->x, p, key->y)) != CRYPT_OK) { goto error; }
+ if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) { goto error; }
+ if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK) { goto error; }
key->type = PK_PRIVATE;
/* free up ram */
err = CRYPT_OK;
goto done;
error:
- mp_clear_multi(key->x, key->y, NULL);
+ mp_clear_multi(key->base, key->prime, key->x, key->y, NULL);
done:
- mp_clear_multi(p, g, NULL);
error2:
#ifdef LTC_CLEAN_STACK
zeromem(buf, keysize);
@@ -188,13 +239,21 @@ error2:
void dh_free(dh_key *key)
{
LTC_ARGCHKVD(key != NULL);
+ if ( key->base ) {
+ mp_clear( key->base );
+ key->base = NULL;
+ }
+ if ( key->prime ) {
+ mp_clear( key->prime );
+ key->prime = NULL;
+ }
if ( key->x ) {
- mp_clear( key->x );
- key->x = NULL;
+ mp_clear( key->x );
+ key->x = NULL;
}
if ( key->y ) {
- mp_clear( key->y );
- key->y = NULL;
+ mp_clear( key->y );
+ key->y = NULL;
}
}
@@ -229,7 +288,9 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
/* header */
out[y++] = type;
- out[y++] = (unsigned char)(sets[key->idx].size / 8);
+ out[y++] = key->idx == SUPPLIED_PRIME ?
+ SUPPLIED_PRIME :
+ (unsigned char)(sets[key->idx].size / 8);
/* export y */
OUTPUT_BIGNUM(key->y, out, y, z);
@@ -238,6 +299,11 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
/* export x */
OUTPUT_BIGNUM(key->x, out, y, z);
}
+ /* export g and p */
+ if (key->idx == SUPPLIED_PRIME) {
+ OUTPUT_BIGNUM(key->base, out, y, z);
+ OUTPUT_BIGNUM(key->prime, out, y, z);
+ }
/* store header */
packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_KEY);
@@ -248,6 +314,52 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
}
/**
+ Import a DH key from a binary string
+ @param in The string to read
+ @param inlen The length of the input packet
+ @param type The type of key. PK_PRIVATE or PK_PUBLIC
+ @param base The base (generator) in hex string
+ @param prime The prime in hex string
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int dh_import_raw(unsigned char *in, unsigned long inlen, int type,
+ const char *base, const char *prime, dh_key *key)
+{
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(base != NULL);
+ LTC_ARGCHK(prime != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+ goto error;
+ }
+ if ((err = mp_read_radix(key->base, base, 16)) != CRYPT_OK) { goto error; }
+ if ((err = mp_read_radix(key->prime, prime, 16)) != CRYPT_OK) { goto error; }
+ key->idx = SUPPLIED_PRIME;
+
+ if (type == PK_PRIVATE) {
+ /* load the x value */
+ if ((err = mp_read_unsigned_bin(key->x, in, inlen)) != CRYPT_OK) { goto error; }
+ if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK) { goto error; }
+ key->type = PK_PRIVATE;
+ } else {
+ /* load the y value */
+ if ((err = mp_read_unsigned_bin(key->y, in, inlen)) != CRYPT_OK) { goto error; }
+ key->type = PK_PUBLIC;
+ mp_clear(key->x);
+ key->x = NULL;
+ }
+ key->idx = SUPPLIED_PRIME;
+ return CRYPT_OK;
+error:
+ mp_clear_multi(key->y, key->x, key->base, key->prime, NULL);
+ return err;
+}
+
+/**
Import a DH key from a binary packet
@param in The packet to read
@param inlen The length of the input packet
@@ -256,7 +368,7 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
*/
int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
{
- unsigned long x, y, s;
+ long x, y, s;
int err;
LTC_ARGCHK(in != NULL);
@@ -273,7 +385,7 @@ int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
}
/* init */
- if ((err = mp_init_multi(&key->x, &key->y, NULL)) != CRYPT_OK) {
+ if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
return err;
}
@@ -284,14 +396,22 @@ int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
key->type = (int)in[y++];
/* key size in bytes */
- s = (unsigned long)in[y++] * 8;
-
- for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++);
- if (sets[x].size == 0) {
- err = CRYPT_INVALID_KEYSIZE;
- goto error;
+ s = (int)in[y++];
+
+ if (s == SUPPLIED_PRIME) {
+ /* key from provided p,g values */
+ key->idx = SUPPLIED_PRIME;
+ } else {
+ s *= 8;
+ for (x = 0; (s > sets[x].size) && (sets[x].size != 0); x++);
+ if (sets[x].size == 0) {
+ err = CRYPT_INVALID_KEYSIZE;
+ goto error;
+ }
+ key->idx = (int)x;
+ if ((err = mp_read_radix(key->base, (char *)sets[x].base, 64)) != CRYPT_OK) { goto error; }
+ if ((err = mp_read_radix(key->prime, (char *)sets[x].prime, 64)) != CRYPT_OK) { goto error; }
}
- key->idx = (int)x;
/* type check both values */
if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) {
@@ -310,6 +430,11 @@ int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
if (key->type == PK_PRIVATE) {
INPUT_BIGNUM(key->x, in, x, y, inlen);
+ /* if idx = SUPPLIED_PRIME then prime is not from static table */
+ }
+ if (key->idx == SUPPLIED_PRIME) {
+ INPUT_BIGNUM(key->base, in, x, y, inlen);
+ INPUT_BIGNUM(key->prime, in, x, y, inlen);
}
/* eliminate private key if public */
@@ -320,7 +445,7 @@ int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
return CRYPT_OK;
error:
- mp_clear_multi(key->y, key->x, NULL);
+ mp_clear_multi(key->y, key->x, key->base, key->prime, NULL);
return err;
}
@@ -335,7 +460,7 @@ error:
int dh_shared_secret(dh_key *private_key, dh_key *public_key,
unsigned char *out, unsigned long *outlen)
{
- void *tmp, *p;
+ void *tmp;
unsigned long x;
int err;
@@ -355,12 +480,11 @@ int dh_shared_secret(dh_key *private_key, dh_key *public_key,
}
/* compute y^x mod p */
- if ((err = mp_init_multi(&tmp, &p, NULL)) != CRYPT_OK) {
+ if ((err = mp_init(&tmp)) != CRYPT_OK) {
return err;
}
- if ((err = mp_read_radix(p, (char *)sets[private_key->idx].prime, 64)) != CRYPT_OK) { goto error; }
- if ((err = mp_exptmod(public_key->y, private_key->x, p, tmp)) != CRYPT_OK) { goto error; }
+ if ((err = mp_exptmod(public_key->y, private_key->x, private_key->prime, tmp)) != CRYPT_OK) { goto error; }
/* enough space for output? */
x = (unsigned long)mp_unsigned_bin_size(tmp);
@@ -374,7 +498,7 @@ int dh_shared_secret(dh_key *private_key, dh_key *public_key,
goto done;
error:
done:
- mp_clear_multi(p, tmp, NULL);
+ mp_clear(tmp);
return err;
}
diff --git a/src/ltc/pk/dh/dh_static.c b/src/ltc/pk/dh/dh_static.c
index d1540178..117835fd 100755
--- a/src/ltc/pk/dh/dh_static.c
+++ b/src/ltc/pk/dh/dh_static.c
@@ -152,6 +152,8 @@ int dh_is_valid_idx(int n)
{
int x;
+ if (n == SUPPLIED_PRIME)
+ return 1;
for (x = 0; sets[x].size; x++);
if ((n < 0) || (n >= x)) {
return 0;
diff --git a/src/ltc/pk/dh/dh_static.h b/src/ltc/pk/dh/dh_static.h
index df026932..ebc9a380 100755
--- a/src/ltc/pk/dh/dh_static.h
+++ b/src/ltc/pk/dh/dh_static.h
@@ -69,6 +69,8 @@
y += x; \
}
+#define SUPPLIED_PRIME 255
+
static void packet_store_header (unsigned char *dst, int section, int subsection)
{
LTC_ARGCHKVD(dst != NULL);
diff --git a/src/ltc/pk/dh/dh_sys.c b/src/ltc/pk/dh/dh_sys.c
index 63cad606..ff47dbfb 100755
--- a/src/ltc/pk/dh/dh_sys.c
+++ b/src/ltc/pk/dh/dh_sys.c
@@ -78,7 +78,13 @@ int dh_encrypt_key(const unsigned char *in, unsigned long inlen,
}
/* make a random key and export the public copy */
- if ((err = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) {
+ pubkey.idx = key->idx;
+ if ((err = mp_init_multi(&pubkey.base, &pubkey.prime, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_copy(key->base, pubkey.base)) != CRYPT_OK) { goto LBL_ERR; }
+ if ((err = mp_copy(key->prime, pubkey.prime)) != CRYPT_OK) { goto LBL_ERR; }
+ if ((err = dh_make_key_ex_main(prng, wprng, &pubkey)) != CRYPT_OK) {
goto LBL_ERR;
}
@@ -307,7 +313,7 @@ int dh_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, dh_key *key)
{
- void *a, *b, *k, *m, *g, *p, *p1, *tmp;
+ void *a, *b, *k, *m, *p1, *tmp;
unsigned char *buf;
unsigned long x, y;
int err;
@@ -338,32 +344,27 @@ int dh_sign_hash(const unsigned char *in, unsigned long inlen,
* since the order of the group is prime
* we need not check if gcd(k, r) is 1
*/
- if (prng_descriptor[wprng].read(buf, sets[key->idx].size, prng) !=
- (unsigned long)(sets[key->idx].size)) {
+ if (prng_descriptor[wprng].read(buf, dh_get_size(key), prng) !=
+ (unsigned long)(dh_get_size(key))) {
err = CRYPT_ERROR_READPRNG;
goto LBL_ERR_1;
}
/* init bignums */
- if ((err = mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL)) != CRYPT_OK) {
+ if ((err = mp_init_multi(&a, &b, &k, &m, &p1, &tmp, NULL)) != CRYPT_OK) {
goto LBL_ERR;
}
- /* load k and m */
- if ((err = mp_read_unsigned_bin(m, (unsigned char *)in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
- if ((err = mp_read_unsigned_bin(k, buf, sets[key->idx].size)) != CRYPT_OK) { goto LBL_ERR; }
-
- /* load g, p and p1 */
- if ((err = mp_read_radix(g, sets[key->idx].base, 64)) != CRYPT_OK) { goto LBL_ERR; }
- if ((err = mp_read_radix(p, sets[key->idx].prime, 64)) != CRYPT_OK) { goto LBL_ERR; }
- if ((err = mp_sub_d(p, 1, p1)) != CRYPT_OK) { goto LBL_ERR; }
- if ((err = mp_div_2(p1, p1)) != CRYPT_OK) { goto LBL_ERR; } /* p1 = (p-1)/2 */
-
+ /* load k, m and p1 */
+ if ((err = mp_read_unsigned_bin(m, (unsigned char *)in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+ if ((err = mp_read_unsigned_bin(k, buf, dh_get_size(key))) != CRYPT_OK) { goto LBL_ERR; }
+ if ((err = mp_sub_d(key->prime, 1, p1)) != CRYPT_OK) { goto LBL_ERR; }
+ if ((err = mp_div_2(p1, p1)) != CRYPT_OK) { goto LBL_ERR; } /* p1 = (p-1)/2 */
/* now get a = g^k mod p */
- if ((err = mp_exptmod(g, k, p, a)) != CRYPT_OK) { goto LBL_ERR; }
+ if ((err = mp_exptmod(key->base, k, key->prime, a)) != CRYPT_OK) { goto LBL_ERR; }
/* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */
- if ((err = mp_invmod(k, p1, k)) != CRYPT_OK) { goto LBL_ERR; } /* k = 1/k mod p1 */
+ if ((err = mp_invmod(k, p1, k)) != CRYPT_OK) { goto LBL_ERR; } /* k = 1/k mod p1 */
if ((err = mp_mulmod(a, key->x, p1, tmp)) != CRYPT_OK) { goto LBL_ERR; } /* tmp = xa */
if ((err = mp_submod(m, tmp, p1, tmp)) != CRYPT_OK) { goto LBL_ERR; } /* tmp = M - xa */
if ((err = mp_mulmod(k, tmp, p1, b)) != CRYPT_OK) { goto LBL_ERR; } /* b = (M - xa)/k */
@@ -400,7 +401,7 @@ int dh_sign_hash(const unsigned char *in, unsigned long inlen,
err = CRYPT_OK;
LBL_ERR:
- mp_clear_multi(tmp, p1, g, p, m, k, b, a, NULL);
+ mp_clear_multi(tmp, p1, m, k, b, a, NULL);
LBL_ERR_1:
XFREE(buf);
@@ -449,7 +450,7 @@ int dh_verify_hash(const unsigned char *sig, unsigned long siglen,
y = PACKET_SIZE;
/* init all bignums */
- if ((err = mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL)) != CRYPT_OK) {
+ if ((err = mp_init_multi(&a, &b, &m, &tmp, NULL)) != CRYPT_OK) {
return err;
}
@@ -457,20 +458,16 @@ int dh_verify_hash(const unsigned char *sig, unsigned long siglen,
INPUT_BIGNUM(a, sig, x, y, siglen);
INPUT_BIGNUM(b, sig, x, y, siglen);
- /* load p and g */
- if ((err = mp_read_radix(p, sets[key->idx].prime, 64)) != CRYPT_OK) { goto error1; }
- if ((err = mp_read_radix(g, sets[key->idx].base, 64)) != CRYPT_OK) { goto error1; }
-
/* load m */
if ((err = mp_read_unsigned_bin(m, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error1; }
/* find g^m mod p */
- if ((err = mp_exptmod(g, m, p, m)) != CRYPT_OK) { goto error1; } /* m = g^m mod p */
+ if ((err = mp_exptmod(key->base, m, key->prime, m)) != CRYPT_OK) { goto error1; } /* m = g^m mod p */
/* find y^a * a^b */
- if ((err = mp_exptmod(key->y, a, p, tmp)) != CRYPT_OK) { goto error1; } /* tmp = y^a mod p */
- if ((err = mp_exptmod(a, b, p, a)) != CRYPT_OK) { goto error1; } /* a = a^b mod p */
- if ((err = mp_mulmod(a, tmp, p, a)) != CRYPT_OK) { goto error1; } /* a = y^a * a^b mod p */
+ if ((err = mp_exptmod(key->y, a, key->prime, tmp)) != CRYPT_OK) { goto error1; } /* tmp = y^a mod p */
+ if ((err = mp_exptmod(a, b, key->prime, a)) != CRYPT_OK) { goto error1; } /* a = a^b mod p */
+ if ((err = mp_mulmod(a, tmp, key->prime, a)) != CRYPT_OK) { goto error1; } /* a = y^a * a^b mod p */
/* y^a * a^b == g^m ??? */
if (mp_cmp(a, m) == 0) {
@@ -483,7 +480,7 @@ int dh_verify_hash(const unsigned char *sig, unsigned long siglen,
error1:
error:
done:
- mp_clear_multi(tmp, m, g, p, b, a, NULL);
+ mp_clear_multi(tmp, m, b, a, NULL);
return err;
}
diff --git a/t/data/cryptx_priv_dh_pg1.bin b/t/data/cryptx_priv_dh_pg1.bin
new file mode 100644
index 00000000..5e9bd0e1
--- /dev/null
+++ b/t/data/cryptx_priv_dh_pg1.bin
Binary files differ
diff --git a/t/data/cryptx_priv_dh_pg2.bin b/t/data/cryptx_priv_dh_pg2.bin
new file mode 100644
index 00000000..9344acb8
--- /dev/null
+++ b/t/data/cryptx_priv_dh_pg2.bin
Binary files differ
diff --git a/t/data/cryptx_pub_dh_pg1.bin b/t/data/cryptx_pub_dh_pg1.bin
new file mode 100644
index 00000000..9323f593
--- /dev/null
+++ b/t/data/cryptx_pub_dh_pg1.bin
Binary files differ
diff --git a/t/data/cryptx_pub_dh_pg2.bin b/t/data/cryptx_pub_dh_pg2.bin
new file mode 100644
index 00000000..cd650251
--- /dev/null
+++ b/t/data/cryptx_pub_dh_pg2.bin
Binary files differ
diff --git a/t/pk_dh.t b/t/pk_dh.t
index a1e23335..ec0b82e1 100644
--- a/t/pk_dh.t
+++ b/t/pk_dh.t
@@ -1,6 +1,6 @@
use strict;
use warnings;
-use Test::More tests => 28;
+use Test::More tests => 74;
use Crypt::PK::DH qw(dh_encrypt dh_decrypt dh_sign_message dh_verify_message dh_sign_hash dh_verify_hash dh_shared_secret);
@@ -27,6 +27,28 @@ use Crypt::PK::DH qw(dh_encrypt dh_decrypt dh_sign_message dh_verify_message dh_
}
{
+ my $k;
+
+ $k = Crypt::PK::DH->new('t/data/cryptx_priv_dh_pg1.bin');
+ ok($k, 'load cryptx_priv_dh_pg1.bin');
+ ok($k->is_private, 'is_private cryptx_priv_dh_pg1.bin');
+ is($k->size, 256, 'size');
+ is(uc($k->key2hash->{x}), '29BB37065071D1C23AE0D8C555E24E5E546954B985260ECC6A1A21252FCFD2D633B0580F6A00B80ED75123EC37A3E784F888EE026C1034CD930CA58464EB6A59A090D1113855AFA48C9A79631E2534D7F33FAD4DC8FF48E88C865E517B67DAD4B40D64BD67CBFE52F56FBC6764D0629E5EFF63351AF19FF398375BDCE22FBDF3A044DAB2B6EAAA44D1A78F4FF74088175E6B5F184222F116F4C6188547F90B0ADCA3255EA7148CB57E5E852E79F438F995CFC3AC79A01D2C329C0750D55FDADCC6FAF6D6850892EEC073FD77CC7F98D8D317D402E2A89E4161001DAEF43DAC0F386E48870D457FB12CC5B70E6F5719609631CB8B439DB6D2F04CF8A774678F68', 'key2hash');
+
+ $k = Crypt::PK::DH->new('t/data/cryptx_priv_dh_pg2.bin');
+ ok($k, 'load cryptx_priv_dh_pg2.bin');
+ ok($k->is_private, 'is_private cryptx_priv_dh_pg2.bin');
+
+ $k = Crypt::PK::DH->new('t/data/cryptx_pub_dh_pg1.bin');
+ ok($k, 'load cryptx_pub_dh_pg1.bin');
+ ok(!$k->is_private, 'is_private cryptx_pub_dh_pg1.bin');
+
+ $k = Crypt::PK::DH->new('t/data/cryptx_pub_dh_pg2.bin');
+ ok($k, 'load cryptx_pub_dh_pg2.bin');
+ ok(!$k->is_private, 'is_private cryptx_pub_dh_pg2.bin');
+}
+
+{
my $pr1 = Crypt::PK::DH->new;
$pr1->import_key('t/data/cryptx_priv_dh1.bin');
my $pu1 = Crypt::PK::DH->new;
@@ -57,6 +79,73 @@ use Crypt::PK::DH qw(dh_encrypt dh_decrypt dh_sign_message dh_verify_message dh_
}
{
+ my $pr1 = Crypt::PK::DH->new;
+ $pr1->import_key('t/data/cryptx_priv_dh_pg1.bin');
+ my $pu1 = Crypt::PK::DH->new;
+ $pu1->import_key('t/data/cryptx_pub_dh_pg1.bin');
+
+ my $ct = $pu1->encrypt("secret message");
+ my $pt = $pr1->decrypt($ct);
+ ok(length $ct > 100, 'encrypt ' . length($ct));
+ is($pt, "secret message", 'decrypt');
+
+ my $sig = $pr1->sign_message("message");
+ ok(length $sig > 60, 'sign_message ' . length($sig));
+ ok($pu1->verify_message($sig, "message"), 'verify_message');
+
+ my $hash = pack("H*","04624fae618e9ad0c5e479f62e1420c71fff34dd");
+ $sig = $pr1->sign_hash($hash, 'SHA1');
+ ok(length $sig > 60, 'sign_hash ' . length($sig));
+ ok($pu1->verify_hash($sig, $hash, 'SHA1'), 'verify_hash');
+
+ my $pr2 = Crypt::PK::DH->new;
+ $pr2->import_key('t/data/cryptx_priv_dh_pg2.bin');
+ my $pu2 = Crypt::PK::DH->new;
+ $pu2->import_key('t/data/cryptx_pub_dh_pg2.bin');
+
+ my $ss1 = $pr1->shared_secret($pu2);
+ my $ss2 = $pr2->shared_secret($pu1);
+ is(unpack("H*",$ss1), unpack("H*",$ss2), 'shared_secret');
+}
+
+{
+ my $pr1 = Crypt::PK::DH->new;
+ $pr1->import_key_raw(pack('H*','5F7EF8D4F7D80C2D88ADADDFE57F4F4DC578259E3B5F42D82838D5905FF6D2BECDC489452D3F5807EF4E2361821089DDC9B27198D79E9C22EE249318688FE250CCC69E49C5F985777405A76264C5EF0D83AEA1C368B1E1A48DC0E04D6E0C884F0C95A3949B29A05437A6179E7AADCC4D095A55C03046296C02AA9991EFD17745615726D52B8B8A12DAC7218265DBB4B760176C27E644AD2EC15B238980326BE1B27D5AC28EA2B2DC5F24FD6A315CA2193A23370B130B541D54C470AD91BE20ECD697B01C2DAEE00E0027A9EBD2D87404E20ADE1DE3B92798928B837AC5EFB305C168823D362A1162C7A709A70E6619F01AF113E316376B3561F88AC2B6F647B2'),'private','ike2048');
+ my $pu1 = Crypt::PK::DH->new;
+ $pu1->import_key_raw(pack('H*','4B9ECB56202EDBC6578072A4519EBE625DE8972877462240F62393C59A6C04AA159E56505156E7DF645FF6EC588E0778A96B78B26A0793D90A4B5C5EC4C61EA69D21C630843ACC2BFD3864CD9DA9600BA8F1B7D8542B01F7251AA3AC257C7AC65A1D2BCF51A8E3E67D9544599B0956710E2B052CDA9B565CDD121CC123364B480E9E7E2237D3D6B5B1E200C7BF858C54CCD3175736DB28336210A16F8F0ACEC08847EF7905FAB7E97E626CFD13CBDF167441FEEB72CB6E7407DFC59F03249F79312A94DA89B1D61196B41E90C08D2C801FD7BEA02A47A1CDA1581F57BA700C1BCDDE6338718E19079055194CAF176D85464957D405B04CC3DD9756C211E11BF2'),'public','ike2048');
+ ok($pr1, 'import_key_raw private1');
+ ok($pu1, 'import_key_raw public1');
+ ok($pr1->is_private, 'is_private private1');
+ ok(!$pu1->is_private, 'is_private public1');
+ is(uc(unpack('H*',$pr1->export_key_raw('private'))),'5F7EF8D4F7D80C2D88ADADDFE57F4F4DC578259E3B5F42D82838D5905FF6D2BECDC489452D3F5807EF4E2361821089DDC9B27198D79E9C22EE249318688FE250CCC69E49C5F985777405A76264C5EF0D83AEA1C368B1E1A48DC0E04D6E0C884F0C95A3949B29A05437A6179E7AADCC4D095A55C03046296C02AA9991EFD17745615726D52B8B8A12DAC7218265DBB4B760176C27E644AD2EC15B238980326BE1B27D5AC28EA2B2DC5F24FD6A315CA2193A23370B130B541D54C470AD91BE20ECD697B01C2DAEE00E0027A9EBD2D87404E20ADE1DE3B92798928B837AC5EFB305C168823D362A1162C7A709A70E6619F01AF113E316376B3561F88AC2B6F647B2');
+ is(uc(unpack('H*',$pr1->export_key_raw('public'))),'4B9ECB56202EDBC6578072A4519EBE625DE8972877462240F62393C59A6C04AA159E56505156E7DF645FF6EC588E0778A96B78B26A0793D90A4B5C5EC4C61EA69D21C630843ACC2BFD3864CD9DA9600BA8F1B7D8542B01F7251AA3AC257C7AC65A1D2BCF51A8E3E67D9544599B0956710E2B052CDA9B565CDD121CC123364B480E9E7E2237D3D6B5B1E200C7BF858C54CCD3175736DB28336210A16F8F0ACEC08847EF7905FAB7E97E626CFD13CBDF167441FEEB72CB6E7407DFC59F03249F79312A94DA89B1D61196B41E90C08D2C801FD7BEA02A47A1CDA1581F57BA700C1BCDDE6338718E19079055194CAF176D85464957D405B04CC3DD9756C211E11BF2');
+ is(uc(unpack('H*',$pu1->export_key_raw('public'))),'4B9ECB56202EDBC6578072A4519EBE625DE8972877462240F62393C59A6C04AA159E56505156E7DF645FF6EC588E0778A96B78B26A0793D90A4B5C5EC4C61EA69D21C630843ACC2BFD3864CD9DA9600BA8F1B7D8542B01F7251AA3AC257C7AC65A1D2BCF51A8E3E67D9544599B0956710E2B052CDA9B565CDD121CC123364B480E9E7E2237D3D6B5B1E200C7BF858C54CCD3175736DB28336210A16F8F0ACEC08847EF7905FAB7E97E626CFD13CBDF167441FEEB72CB6E7407DFC59F03249F79312A94DA89B1D61196B41E90C08D2C801FD7BEA02A47A1CDA1581F57BA700C1BCDDE6338718E19079055194CAF176D85464957D405B04CC3DD9756C211E11BF2');
+
+ my $ct = $pu1->encrypt("secret message");
+ my $pt = $pr1->decrypt($ct);
+ ok(length $ct > 100, 'encrypt ' . length($ct));
+ is($pt, "secret message", 'decrypt');
+
+ my $sig = $pr1->sign_message("message");
+ ok(length $sig > 60, 'sign_message ' . length($sig));
+ ok($pu1->verify_message($sig, "message"), 'verify_message');
+
+ my $hash = pack("H*","04624fae618e9ad0c5e479f62e1420c71fff34dd");
+ $sig = $pr1->sign_hash($hash, 'SHA1');
+ ok(length $sig > 60, 'sign_hash ' . length($sig));
+ ok($pu1->verify_hash($sig, $hash, 'SHA1'), 'verify_hash');
+
+ my $pr2 = Crypt::PK::DH->new;
+ $pr2->import_key_raw(pack('H*','473156C909EBB0A6F61F707CDDD7E6401BFDE22BC57B8D3CCC30C4CD3FF7678CCD9B022167AA774786F367FE5B5924A3C1E09AA71264F94E7ABA87FFA888913BB9592613F8AD87FBE82E99064B00CE3294CFD410BCFB4C88A46F5F8532633458C317DF40F395C2F08A822D84BF4291A1A63DE1F6D0F460DB81C685ADD0F26262307823227C17B4671BCF74A6337738BB4596337644656A060F1BB109640878D23F56E493719D6EF60FEA7AC85123CFB6E476392789AC1FE4F4CA371DB2863192ADE424F3EFDEE52D4CB445B99B10566A4B6F6DC813C265DC0052D710AEAA0969392BD478A46AB9C7A0E2FA27964A759938904FCEFAC4CE061C9927764AAB57DC'),'private','ike2048');
+ my $pu2 = Crypt::PK::DH->new;
+ $pu2->import_key_raw(pack('H*','774A01FF19C1603040DFBB5C8A44F11CE8719F757C2AF6B2921EDDDEF27F77D5F2DAF9539BCBCB30F80D76E054C489C9E6533051767E6220539C871F23D3B6F80D84037A6FBAB3AE6AF8F214A60A816D6F0F6C3F31801DCD6EA771F41A2A5618BC333D650F46F22FEA81A94F4E00CD05B83F8FE257A2607E62519D9BF8B8C96D0587FB2BCEC8D18DDCF66EBBB8A56623953531EE27C68C8C37E6413FD2C98339F491A0472E5D4DFADC7BF30E89A2CE2081EE3CF9F9B0FFCD902A3021CAC14A4AD7E00F6202C8A9AB93BF96E33838FB9178DC8A8F995ABD81F28F5A137A78E813ABD185498A3A50CB3021CF58BE9D0200C19928AA097D306ABAD9874E0F217482'),'public','ike2048');
+
+ my $ss1 = $pr1->shared_secret($pu2);
+ my $ss2 = $pr2->shared_secret($pu1);
+ is(unpack("H*",$ss1), unpack("H*",$ss2), 'shared_secret');
+}
+
+{
my $k = Crypt::PK::DH->new;
$k->generate_key(256);
ok($k, 'generate_key');
@@ -66,6 +155,24 @@ use Crypt::PK::DH qw(dh_encrypt dh_decrypt dh_sign_message dh_verify_message dh_
}
{
+ my $k = Crypt::PK::DH->new;
+ $k->generate_key({g => 2, p => 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'});
+ ok($k, 'generate_key');
+ ok($k->is_private, 'is_private');
+ ok($k->export_key('private'), 'export_key_pem pri gp');
+ ok($k->export_key('public'), 'export_key_pem pub gp');
+}
+
+{
+ my $k = Crypt::PK::DH->new;
+ $k->generate_key('ike2048');
+ ok($k, 'generate_key');
+ ok($k->is_private, 'is_private');
+ ok($k->export_key('private'), 'export_key_pem pri ike2048');
+ ok($k->export_key('public'), 'export_key_pem pub ike2048');
+}
+
+{
my $ct = dh_encrypt('t/data/cryptx_pub_dh1.bin', 'test string');
ok($ct, 'dh_encrypt');
my $pt = dh_decrypt('t/data/cryptx_priv_dh1.bin', $ct);
@@ -82,3 +189,21 @@ use Crypt::PK::DH qw(dh_encrypt dh_decrypt dh_sign_message dh_verify_message dh_
my $ss2 = dh_shared_secret('t/data/cryptx_priv_dh2.bin', 't/data/cryptx_pub_dh1.bin');
is(unpack("H*",$ss1), unpack("H*",$ss2), 'shared_secret');
}
+
+{
+ my $ct = dh_encrypt('t/data/cryptx_pub_dh_pg1.bin', 'test string');
+ ok($ct, 'dh_encrypt');
+ my $pt = dh_decrypt('t/data/cryptx_priv_dh_pg1.bin', $ct);
+ ok($pt, 'dh_decrypt');
+ my $sig = dh_sign_message('t/data/cryptx_priv_dh_pg1.bin', 'test string');
+ ok($sig, 'dh_sign_message');
+ ok(dh_verify_message('t/data/cryptx_pub_dh_pg1.bin', $sig, 'test string'), 'dh_verify_message');
+ my $hash = pack("H*","04624fae618e9ad0c5e479f62e1420c71fff34dd");
+ $sig = dh_sign_hash('t/data/cryptx_priv_dh_pg1.bin', $hash, 'SHA1');
+ ok($sig, 'dh_sign_hash');
+ ok(dh_verify_hash('t/data/cryptx_pub_dh_pg1.bin', $sig, $hash, 'SHA1'), 'dh_verify_hash');
+
+ my $ss1 = dh_shared_secret('t/data/cryptx_priv_dh_pg1.bin', 't/data/cryptx_pub_dh_pg2.bin');
+ my $ss2 = dh_shared_secret('t/data/cryptx_priv_dh_pg2.bin', 't/data/cryptx_pub_dh_pg1.bin');
+ is(unpack("H*",$ss1), unpack("H*",$ss2), 'shared_secret');
+}