diff options
-rw-r--r-- | inc/CryptX_PK_DH.xs.inc | 215 | ||||
-rw-r--r-- | lib/Crypt/PK/DH.pm | 257 | ||||
-rw-r--r-- | src/ltc/headers/tomcrypt_pk.h | 6 | ||||
-rw-r--r-- | src/ltc/pk/dh/dh.c | 210 | ||||
-rwxr-xr-x | src/ltc/pk/dh/dh_static.c | 2 | ||||
-rwxr-xr-x | src/ltc/pk/dh/dh_static.h | 2 | ||||
-rwxr-xr-x | src/ltc/pk/dh/dh_sys.c | 53 | ||||
-rw-r--r-- | t/data/cryptx_priv_dh_pg1.bin | bin | 0 -> 791 bytes | |||
-rw-r--r-- | t/data/cryptx_priv_dh_pg2.bin | bin | 0 -> 791 bytes | |||
-rw-r--r-- | t/data/cryptx_pub_dh_pg1.bin | bin | 0 -> 531 bytes | |||
-rw-r--r-- | t/data/cryptx_pub_dh_pg2.bin | bin | 0 -> 531 bytes | |||
-rw-r--r-- | t/pk_dh.t | 127 |
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 Binary files differnew file mode 100644 index 00000000..5e9bd0e1 --- /dev/null +++ b/t/data/cryptx_priv_dh_pg1.bin diff --git a/t/data/cryptx_priv_dh_pg2.bin b/t/data/cryptx_priv_dh_pg2.bin Binary files differnew file mode 100644 index 00000000..9344acb8 --- /dev/null +++ b/t/data/cryptx_priv_dh_pg2.bin diff --git a/t/data/cryptx_pub_dh_pg1.bin b/t/data/cryptx_pub_dh_pg1.bin Binary files differnew file mode 100644 index 00000000..9323f593 --- /dev/null +++ b/t/data/cryptx_pub_dh_pg1.bin diff --git a/t/data/cryptx_pub_dh_pg2.bin b/t/data/cryptx_pub_dh_pg2.bin Binary files differnew file mode 100644 index 00000000..cd650251 --- /dev/null +++ b/t/data/cryptx_pub_dh_pg2.bin @@ -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'); +} |