diff --git a/Changes b/Changes index 3ec67cc..1684881 100755 --- a/Changes +++ b/Changes @@ -1,6 +1,10 @@ Changes for CryptX TODO: + before 0.014: + - Crypt::PK::DH/ECC - sign/verify replaced by sign_message/verify_message + sign_hash/verify_hash + - Crypt::PK::DH/ECC - new method key2hash + later: - consider: RSA->check_key, RSA password protected keys - consider: PK->encrypt|decrypt ... add 'armour' param and make it compatible with Crypt::RSA - croak with the "real caller" (Crypt::Mac::*, Crypt::Mode::*, ...) @@ -12,10 +16,11 @@ RSA: my $k = Crypt::PK::RSA->new; $k->generate_key(256, 65537); - "libtom-src/bn_mp_invmod.c", line 37: warning: statement not reached -0.014 2013/09/11 +0.013_1 2013/09/11 - Crypt::Digest::NNN + Crypt::Mac::NNN - can produce Base64-URL-Safe encoded digest/mac - Crypt::PRNG + Crypt::PRNG::NNN - Base64-URL-Safe encoded random bytes (random_bytes_b64u/bytes_b64u) - Crypt::PK::RSA/DSA - sign/verify replaced by sign_message/verify_message + sign_hash/verify_hash + - Crypt::PK::RSA/DSA - new method key2hash - documentation fixes 0.013 2013/08/28 diff --git a/lib/Crypt/PK/DSA.pm b/lib/Crypt/PK/DSA.pm index b005d54..8f4cb45 100644 --- a/lib/Crypt/PK/DSA.pm +++ b/lib/Crypt/PK/DSA.pm @@ -72,32 +72,38 @@ return $self->_decrypt($data); } +sub _truncate { + my ($self, $hash) = @_; + ### section 4.6 of FIPS 186-4 + # let N be the bit length of q + # z = the leftmost min(N, outlen) bits of Hash(M). + my $q = $self->size_q; # = size in bytes + return $hash if $q >= length($hash); + return substr($hash, 0, $q); +} + sub sign_message { my ($self, $data, $hash_name) = @_; $hash_name ||= 'SHA1'; my $data_hash = digest_data($hash_name, $data); - #XXX truncation - return $self->_sign($data_hash); + return $self->_sign($self->_truncate($data_hash)); } sub sign_hash { my ($self, $data_hash) = @_; - #XXX truncation - return $self->_sign($data_hash); + return $self->_sign($self->_truncate($data_hash)); } sub verify_message { my ($self, $sig, $data, $hash_name) = @_; $hash_name ||= 'SHA1'; my $data_hash = digest_data($hash_name, $data); - #XXX truncation - return $self->_verify($sig, $data_hash); + return $self->_verify($sig, $self->_truncate($data_hash)); } sub verify_hash { my ($self, $sig, $data_hash) = @_; - #XXX truncation - return $self->_verify($sig, $data_hash); + return $self->_verify($sig, $self->_truncate($data_hash)); } ### FUNCTIONS @@ -360,3 +366,19 @@ my $size = $pk->is_private; # returns key size in bytes or undef if no key loaded + +=head2 key2hash + + my $hash = $pk->key2hash; + + returns hash like this (or undef if no key loaded): + { + type => 1, # integer: 1 .. private, 0 .. public + qord => 30, # integer: order of the sub-group + # all the rest are hex strings + g => "847E8896D12C9BF18FE283AE7AD58ED7F3...", #generator + p => "AAF839A764E04D80824B79FA1F0496C093...", #prime used to generate the sub-group + q => "D05C4CB45F29D353442F1FEC43A6BE2BE8...", #large prime that generats the field the contains the sub-group + x => "6C801901AC74E2DC714D75A9F6969483CF...", #private key + y => "8F7604D77FA62C7539562458A63C7611B7...", #public key + } diff --git a/lib/Crypt/PK/RSA.pm b/lib/Crypt/PK/RSA.pm index 0bfa7c8..1c332b1 100644 --- a/lib/Crypt/PK/RSA.pm +++ b/lib/Crypt/PK/RSA.pm @@ -432,3 +432,21 @@ my $size = $pk->is_private; # returns key size in bytes or undef if no key loaded + +=head2 key2hash + + my $hash = $pk->key2hash; + + returns hash like this (or undef if no key loaded): + { + type => 1, # integer: 1 .. private, 0 .. public + # all the rest are hex strings + e => "10001", #public exponent + d => "9ED5C3D3F866E06957CA0E9478A273C39BBDA4EEAC5B...", #private exponent + N => "D0A5CCCAE03DF9C2F5C4C8C0CE840D62CDE279990DC6...", #modulus + p => "D3EF0028FFAB508E2773C659E428A80FB0E9211346B4...", #p factor of N + q => "FC07E46B163CAB6A83B8E467D169534B2077DCDEECAE...", #q factor of N + qP => "88C6D406F833DF73C8B734548E0385261AD51F4187CF...", #1/q mod p CRT param + dP => "486F142FEF0A1F53269AC43D2EE4D263E2841B60DA36...", #d mod (p - 1) CRT param + dQ => "4597284B2968B72C4212DB7E8F24360B987B80514DA9...", #d mod (q - 1) CRT param + } diff --git a/lib/CryptX.pm b/lib/CryptX.pm index 9fe5da0..59a6880 100644 --- a/lib/CryptX.pm +++ b/lib/CryptX.pm @@ -3,8 +3,7 @@ use strict; use warnings ; -our $VERSION = '0.014'; -$VERSION = eval $VERSION; +our $VERSION = '0.013_1'; require XSLoader; XSLoader::load('CryptX', $VERSION); diff --git a/lib/CryptX.xs b/lib/CryptX.xs index 2b6df05..9ae791d 100644 --- a/lib/CryptX.xs +++ b/lib/CryptX.xs @@ -4,6 +4,7 @@ #undef LTC_SOURCE #include "tomcrypt.h" +#include "tommath.h" typedef struct cipher_struct { /* used by Crypt::Cipher */ symmetric_key skey; diff --git a/lib/CryptX_PK_DSA.xs.inc b/lib/CryptX_PK_DSA.xs.inc index 9e81c7c..c479c68 100755 --- a/lib/CryptX_PK_DSA.xs.inc +++ b/lib/CryptX_PK_DSA.xs.inc @@ -61,6 +61,85 @@ OUTPUT: RETVAL +int +size_q(Crypt::PK::DSA self) + CODE: + if (self->key.type == -1 || self->key.qord <= 0) XSRETURN_UNDEF; + RETVAL = ltc_mp.unsigned_size(self->key.q); + OUTPUT: + RETVAL + +SV* +key2hash(Crypt::PK::DSA self) + INIT: + HV *rv_hash; + unsigned char buf[20001]; + CODE: + if (self->key.type == -1 || self->key.qord <= 0) XSRETURN_UNDEF; + rv_hash = newHV(); + /* =====> g */ + if (ltc_mp.unsigned_size(self->key.g)>10000) { + croak("FATAL: key2hash failed - 'g' too big number"); + } + if (ltc_mp.unsigned_size(self->key.g)>0) { + mp_tohex(self->key.g, buf); + hv_store(rv_hash, "g", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "g", 1, newSVpv("", 0), 0); + } + /* =====> q */ + if (ltc_mp.unsigned_size(self->key.q)>10000) { + croak("FATAL: key2hash failed - 'q' too big number"); + } + if (ltc_mp.unsigned_size(self->key.q)>0) { + mp_tohex(self->key.q, buf); + hv_store(rv_hash, "q", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "q", 1, newSVpv("", 0), 0); + } + /* =====> p */ + if (ltc_mp.unsigned_size(self->key.p)>10000) { + croak("FATAL: key2hash failed - 'p' too big number"); + } + if (ltc_mp.unsigned_size(self->key.p)>0) { + mp_tohex(self->key.p, buf); + hv_store(rv_hash, "p", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "p", 1, newSVpv("", 0), 0); + } + /* =====> x */ + if (ltc_mp.unsigned_size(self->key.x)>10000) { + croak("FATAL: key2hash failed - 'x' too big number"); + } + if (ltc_mp.unsigned_size(self->key.x)>0) { + mp_tohex(self->key.x, buf); + hv_store(rv_hash, "x", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "x", 1, newSVpv("", 0), 0); + } + /* =====> y */ + if (ltc_mp.unsigned_size(self->key.y)>10000) { + croak("FATAL: key2hash failed - 'y' too big number"); + } + if (ltc_mp.unsigned_size(self->key.y)>0) { + mp_tohex(self->key.y, buf); + hv_store(rv_hash, "y", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "y", 1, newSVpv("", 0), 0); + } + /* =====> qord */ + hv_store(rv_hash, "qord", 4, newSViv(self->key.qord), 0); + /* =====> type */ + hv_store(rv_hash, "type", 4, newSViv(self->key.type), 0); + RETVAL = newRV_noinc((SV*)rv_hash); + OUTPUT: + RETVAL + SV * export_key_der(Crypt::PK::DSA self, char * type) CODE: diff --git a/lib/CryptX_PK_RSA.xs.inc b/lib/CryptX_PK_RSA.xs.inc index 3f68e3c..f5a695a 100755 --- a/lib/CryptX_PK_RSA.xs.inc +++ b/lib/CryptX_PK_RSA.xs.inc @@ -59,6 +59,108 @@ CODE: if (self->key.type == -1 || self->key.N == NULL) XSRETURN_UNDEF; RETVAL = ltc_mp.unsigned_size(self->key.N); + OUTPUT: + RETVAL + +SV* +key2hash(Crypt::PK::RSA self) + INIT: + HV *rv_hash; + unsigned char buf[20001]; + CODE: + if (self->key.type == -1 || self->key.N == NULL) XSRETURN_UNDEF; + rv_hash = newHV(); + /* =====> e */ + if (ltc_mp.unsigned_size(self->key.e)>10000) { + croak("FATAL: key2hash failed - 'e' too big number"); + } + if (ltc_mp.unsigned_size(self->key.e)>0) { + mp_tohex(self->key.e, buf); + hv_store(rv_hash, "e", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "e", 1, newSVpv("", 0), 0); + } + /* =====> d */ + if (ltc_mp.unsigned_size(self->key.d)>10000) { + croak("FATAL: key2hash failed - 'd' too big number"); + } + if (ltc_mp.unsigned_size(self->key.d)>0) { + mp_tohex(self->key.d, buf); + hv_store(rv_hash, "d", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "d", 1, newSVpv("", 0), 0); + } + /* =====> N */ + if (ltc_mp.unsigned_size(self->key.N)>10000) { + croak("FATAL: key2hash failed - 'N' too big number"); + } + if (ltc_mp.unsigned_size(self->key.N)>0) { + mp_tohex(self->key.N, buf); + hv_store(rv_hash, "N", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "N", 1, newSVpv("", 0), 0); + } + /* =====> q */ + if (ltc_mp.unsigned_size(self->key.q)>10000) { + croak("FATAL: key2hash failed - 'q' too big number"); + } + if (ltc_mp.unsigned_size(self->key.q)>0) { + mp_tohex(self->key.q, buf); + hv_store(rv_hash, "q", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "q", 1, newSVpv("", 0), 0); + } + /* =====> p */ + if (ltc_mp.unsigned_size(self->key.p)>10000) { + croak("FATAL: key2hash failed - 'p' too big number"); + } + if (ltc_mp.unsigned_size(self->key.p)>0) { + mp_tohex(self->key.p, buf); + hv_store(rv_hash, "p", 1, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "p", 1, newSVpv("", 0), 0); + } + /* =====> qP */ + if (ltc_mp.unsigned_size(self->key.qP)>10000) { + croak("FATAL: key2hash failed - 'qP' too big number"); + } + if (ltc_mp.unsigned_size(self->key.qP)>0) { + mp_tohex(self->key.qP, buf); + hv_store(rv_hash, "qP", 2, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "qP", 2, newSVpv("", 0), 0); + } + /* =====> dP */ + if (ltc_mp.unsigned_size(self->key.dP)>10000) { + croak("FATAL: key2hash failed - 'dP' too big number"); + } + if (ltc_mp.unsigned_size(self->key.dP)>0) { + mp_tohex(self->key.dP, buf); + hv_store(rv_hash, "dP", 2, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "dP", 2, newSVpv("", 0), 0); + } + /* =====> dQ */ + if (ltc_mp.unsigned_size(self->key.dQ)>10000) { + croak("FATAL: key2hash failed - 'dQ' too big number"); + } + if (ltc_mp.unsigned_size(self->key.dQ)>0) { + mp_tohex(self->key.dQ, buf); + hv_store(rv_hash, "dQ", 2, newSVpv(buf, strlen(buf)), 0); + } + else{ + hv_store(rv_hash, "dQ", 2, newSVpv("", 0), 0); + } + /* =====> type */ + hv_store(rv_hash, "type", 4, newSViv(self->key.type), 0); + RETVAL = newRV_noinc((SV*)rv_hash); OUTPUT: RETVAL diff --git a/t/pk_dsa.t b/t/pk_dsa.t index cdfbf23..0b265cd 100755 --- a/t/pk_dsa.t +++ b/t/pk_dsa.t @@ -2,7 +2,7 @@ use warnings; use Test::More; -use Crypt::PK::DSA qw(dsa_encrypt dsa_decrypt dsa_sign dsa_verify); +use Crypt::PK::DSA qw(dsa_encrypt dsa_decrypt dsa_sign_message dsa_verify_message); { my $k; @@ -68,9 +68,9 @@ ok(length $ct > 200, 'encrypt ' . length($ct)); is($pt, "secret message", 'decrypt'); - my $sig = $pr1->sign("message"); + my $sig = $pr1->sign_message("message"); ok(length $sig > 60, 'sign ' . length($sig)); - ok($pu1->verify($sig, "message"), 'verify'); + ok($pu1->verify_message($sig, "message"), 'verify'); my $pr2 = Crypt::PK::DSA->new; $pr2->import_key('t/data/cryptx_priv_dsa2.der'); @@ -98,9 +98,9 @@ ok($ct, 'dsa_encrypt'); my $pt = dsa_decrypt('t/data/cryptx_priv_dsa1.der', $ct); ok($pt, 'dsa_decrypt'); - my $sig = dsa_sign('t/data/cryptx_priv_dsa1.der', 'test string'); - ok($sig, 'dsa_sign'); - ok(dsa_verify('t/data/cryptx_pub_dsa1.der', $sig, 'test string'), 'dsa_verify'); + my $sig = dsa_sign_message('t/data/cryptx_priv_dsa1.der', 'test string'); + ok($sig, 'dsa_sign_message'); + ok(dsa_verify_message('t/data/cryptx_pub_dsa1.der', $sig, 'test string'), 'dsa_verify_message'); } done_testing;