Blame CryptX-0.053-Disable-ECC-and-unbundle-libtomcrypt.patch

a31df49
From c67172aeb9c38c139d05023aef7ac9470f2e4bff Mon Sep 17 00:00:00 2001
a31df49
From: perl-Git-CPAN-Patch Owner <perl-Git-CPAN-Patch-owner@fedoraproject.org>
a31df49
Date: Thu, 15 Feb 2018 15:39:55 +0100
a31df49
Subject: [PATCH] Disable ECC and unbundle libtomcrypt
a31df49
a31df49
CryptX bundles patched libtomcrypt.
a31df49
a31df49
Vanilla CryptX-0.053 requires some ECC features (import DH curves) not yet
a31df49
available in the latest vanilla libtomcrypt-1.18.1.
a31df49
a31df49
This removes Crypt::PK::ECC module from CryptX and changes CryptX to use system
a31df49
libtomcrypt.
a31df49
a31df49
<https://bugzilla.redhat.com/show_bug.cgi?id=1543336#c8>
a31df49
<https://bugzilla.redhat.com/show_bug.cgi?id=1479864>
a31df49
---
a31df49
 CryptX.xs                       |    6 +-
a31df49
 Makefile.PL                     |   18 +-
a31df49
 lib/Crypt/PK/ECC.pm             | 1398 ---------------------------------------
a31df49
 t/001_compile.t                 |    2 +-
a31df49
 t/003_all_pm_pod.t              |    4 +-
a31df49
 t/jwk.t                         |    3 +
a31df49
 t/pk_ecc.t                      |    7 +-
a31df49
 t/pk_ecc_test_vectors_openssl.t |    6 +-
a31df49
 t/pk_enc_pem.t                  |   10 +-
a31df49
 t/pkcs8.t                       |   16 +-
a31df49
 t/sshkey.t                      |   28 +-
a31df49
 t/wycheproof.t                  |   56 +-
a31df49
 12 files changed, 92 insertions(+), 1462 deletions(-)
a31df49
 delete mode 100644 lib/Crypt/PK/ECC.pm
a31df49
a31df49
diff --git a/CryptX.xs b/CryptX.xs
a31df49
index d2957e8..ab0759b 100644
a31df49
--- a/CryptX.xs
a31df49
+++ b/CryptX.xs
a31df49
@@ -252,6 +252,8 @@ STATIC SV * sv_from_mpi(mp_int *mpi) {
a31df49
   return obj;
a31df49
 }
a31df49
 
a31df49
+#if 0 /* ECC disabled */
a31df49
+
a31df49
 ltc_ecc_set_type* _ecc_set_dp_from_SV(ltc_ecc_set_type *dp, SV *curve)
a31df49
 {
a31df49
   HV *h;
a31df49
@@ -319,6 +321,8 @@ void _ecc_free_key(ecc_key *key, ltc_ecc_set_type *dp)
a31df49
   }
a31df49
 }
a31df49
 
a31df49
+#endif
a31df49
+
a31df49
 MODULE = CryptX       PACKAGE = CryptX      PREFIX = CryptX_
a31df49
 
a31df49
 PROTOTYPES: DISABLE
a31df49
@@ -793,7 +797,7 @@ INCLUDE: inc/CryptX_PRNG.xs.inc
a31df49
 INCLUDE: inc/CryptX_PK_RSA.xs.inc
a31df49
 INCLUDE: inc/CryptX_PK_DSA.xs.inc
a31df49
 INCLUDE: inc/CryptX_PK_DH.xs.inc
a31df49
-INCLUDE: inc/CryptX_PK_ECC.xs.inc
a31df49
+#INCLUDE: inc/CryptX_PK_ECC.xs.inc
a31df49
 
a31df49
 INCLUDE: inc/CryptX_KeyDerivation.xs.inc
a31df49
 
a31df49
diff --git a/Makefile.PL b/Makefile.PL
a31df49
index 0553586..22b248c 100644
a31df49
--- a/Makefile.PL
a31df49
+++ b/Makefile.PL
a31df49
@@ -4,11 +4,11 @@ use ExtUtils::MakeMaker;
a31df49
 use Config;
a31df49
 
a31df49
 my @myobjs = map { s|.c$|$Config{obj_ext}|; $_ } grep { $_ !~ m|^src/ltc/\.*tab\.c$| } (
a31df49
-    glob('src/ltm/*.c'),
a31df49
-    glob('src/ltc/*/*.c'),
a31df49
-    glob('src/ltc/*/*/*.c'),
a31df49
-    glob('src/ltc/*/*/*/*.c'),
a31df49
-    glob('src/ltc/*/*/*/*/*.c'),
a31df49
+    #glob('src/ltm/*.c'),
a31df49
+    #glob('src/ltc/*/*.c'),
a31df49
+    #glob('src/ltc/*/*/*.c'),
a31df49
+    #glob('src/ltc/*/*/*/*.c'),
a31df49
+    #glob('src/ltc/*/*/*/*/*.c'),
a31df49
 );
a31df49
 my $myextlib = "src/liballinone$Config{lib_ext}";
a31df49
 my $mycflags = "$Config{ccflags} $Config{cccdlflags} $Config{optimize}";
a31df49
@@ -42,10 +42,10 @@ my %eumm_args = (
a31df49
   LICENSE          => 'perl_5',
a31df49
   META_MERGE       => { resources  => { repository => 'https://github.com/DCIT/perl-CryptX', bugtracker => 'https://github.com/DCIT/perl-CryptX/issues' } },
a31df49
   DEFINE           => '-DLTC_SOURCE -DLTC_NO_TEST -DLTC_NO_PROTOTYPES -DLTM_DESC',
a31df49
-  INC              => '-Isrc/ltc/headers -Isrc/ltm',
a31df49
-  LIBS             => [''],
a31df49
-  MYEXTLIB         => $myextlib,
a31df49
-  clean            => { 'FILES' => join(' ', @myobjs, $myextlib) },
a31df49
+  #INC              => '-Isrc/ltc/headers -Isrc/ltm',
a31df49
+  LIBS             => ['-ltomcrypt'],
a31df49
+  #MYEXTLIB         => $myextlib,
a31df49
+  #clean            => { 'FILES' => join(' ', @myobjs, $myextlib) },
a31df49
   dist             => { 'PREOP' => 'perldoc -u lib/CryptX.pm | pod2markdown > README.md' },
a31df49
 );
a31df49
 
a31df49
diff --git a/lib/Crypt/PK/ECC.pm b/lib/Crypt/PK/ECC.pm
a31df49
deleted file mode 100644
a31df49
index d33215c..0000000
a31df49
--- a/lib/Crypt/PK/ECC.pm
a31df49
+++ /dev/null
a31df49
@@ -1,1398 +0,0 @@
a31df49
-package Crypt::PK::ECC;
a31df49
-
a31df49
-use strict;
a31df49
-use warnings;
a31df49
-our $VERSION = '0.053';
a31df49
-
a31df49
-require Exporter; our @ISA = qw(Exporter); ### use Exporter 'import';
a31df49
-our %EXPORT_TAGS = ( all => [qw( ecc_encrypt ecc_decrypt ecc_sign_message ecc_verify_message ecc_sign_hash ecc_verify_hash ecc_shared_secret )] );
a31df49
-our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
a31df49
-our @EXPORT = qw();
a31df49
-
a31df49
-use Carp;
a31df49
-use CryptX qw(_encode_json _decode_json);
a31df49
-use Crypt::Digest qw(digest_data digest_data_b64u);
a31df49
-use Crypt::Misc qw(read_rawfile encode_b64u decode_b64u encode_b64 decode_b64 pem_to_der der_to_pem);
a31df49
-use Crypt::PK;
a31df49
-
a31df49
-our %curve = (
a31df49
-        ### http://www.ecc-brainpool.org/download/Domain-parameters.pdf (v1.0 19.10.2005)
a31df49
-        brainpoolp160r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.1',
a31df49
-            prime    => "E95E4A5F737059DC60DFC7AD95B3D8139515620F",
a31df49
-            A        => "340E7BE2A280EB74E2BE61BADA745D97E8F7C300",
a31df49
-            B        => "1E589A8595423412134FAA2DBDEC95C8D8675E58",
a31df49
-            Gx       => "BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3",
a31df49
-            Gy       => "1667CB477A1A8EC338F94741669C976316DA6321",
a31df49
-            order    => "E95E4A5F737059DC60DF5991D45029409E60FC09",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        brainpoolp192r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.3',
a31df49
-            prime    => "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297",
a31df49
-            A        => "6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF",
a31df49
-            B        => "469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9",
a31df49
-            Gx       => "C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6",
a31df49
-            Gy       => "14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F",
a31df49
-            order    => "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        brainpoolp224r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.5',
a31df49
-            prime    => "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF",
a31df49
-            A        => "68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43",
a31df49
-            B        => "2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B",
a31df49
-            Gx       => "0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D",
a31df49
-            Gy       => "58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD",
a31df49
-            order    => "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        brainpoolp256r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.7',
a31df49
-            prime    => "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377",
a31df49
-            A        => "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9",
a31df49
-            B        => "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6",
a31df49
-            Gx       => "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262",
a31df49
-            Gy       => "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997",
a31df49
-            order    => "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        brainpoolp320r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.9',
a31df49
-            prime    => "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27",
a31df49
-            A        => "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4",
a31df49
-            B        => "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6",
a31df49
-            Gx       => "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611",
a31df49
-            Gy       => "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1",
a31df49
-            order    => "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        brainpoolp384r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.11',
a31df49
-            prime    => "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53",
a31df49
-            A        => "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826",
a31df49
-            B        => "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11",
a31df49
-            Gx       => "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E",
a31df49
-            Gy       => "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315",
a31df49
-            order    => "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        brainpoolp512r1 => {
a31df49
-            oid      => '1.3.36.3.3.2.8.1.1.13',
a31df49
-            prime    => "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3",
a31df49
-            A        => "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA",
a31df49
-            B        => "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723",
a31df49
-            Gx       => "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822",
a31df49
-            Gy       => "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892",
a31df49
-            order    => "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        ### http://www.secg.org/collateral/sec2_final.pdf (September 20, 2000 - Version 1.0)
a31df49
-        secp112r1 => {
a31df49
-            oid      => '1.3.132.0.6',
a31df49
-            prime    => "DB7C2ABF62E35E668076BEAD208B",
a31df49
-            A        => "DB7C2ABF62E35E668076BEAD2088",
a31df49
-            B        => "659EF8BA043916EEDE8911702B22",
a31df49
-            Gx       => "09487239995A5EE76B55F9C2F098",
a31df49
-            Gy       => "A89CE5AF8724C0A23E0E0FF77500",
a31df49
-            order    => "DB7C2ABF62E35E7628DFAC6561C5",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp112r2 => {
a31df49
-            oid      => '1.3.132.0.7',
a31df49
-            prime    => "DB7C2ABF62E35E668076BEAD208B",
a31df49
-            A        => "6127C24C05F38A0AAAF65C0EF02C",
a31df49
-            B        => "51DEF1815DB5ED74FCC34C85D709",
a31df49
-            Gx       => "4BA30AB5E892B4E1649DD0928643",
a31df49
-            Gy       => "ADCD46F5882E3747DEF36E956E97",
a31df49
-            order    => "36DF0AAFD8B8D7597CA10520D04B",
a31df49
-            cofactor => 4,
a31df49
-        },
a31df49
-        secp128r1 => {
a31df49
-            oid      => '1.3.132.0.28',
a31df49
-            prime    => "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
a31df49
-            A        => "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC",
a31df49
-            B        => "E87579C11079F43DD824993C2CEE5ED3",
a31df49
-            Gx       => "161FF7528B899B2D0C28607CA52C5B86",
a31df49
-            Gy       => "CF5AC8395BAFEB13C02DA292DDED7A83",
a31df49
-            order    => "FFFFFFFE0000000075A30D1B9038A115",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp128r2 => {
a31df49
-            oid      => '1.3.132.0.29',
a31df49
-            prime    => "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
a31df49
-            A        => "D6031998D1B3BBFEBF59CC9BBFF9AEE1",
a31df49
-            B        => "5EEEFCA380D02919DC2C6558BB6D8A5D",
a31df49
-            Gx       => "7B6AA5D85E572983E6FB32A7CDEBC140",
a31df49
-            Gy       => "27B6916A894D3AEE7106FE805FC34B44",
a31df49
-            order    => "3FFFFFFF7FFFFFFFBE0024720613B5A3",
a31df49
-            cofactor => 4,
a31df49
-        },
a31df49
-        secp160k1 => {
a31df49
-            oid      => '1.3.132.0.9',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
a31df49
-            A        => "0000000000000000000000000000000000000000",
a31df49
-            B        => "0000000000000000000000000000000000000007",
a31df49
-            Gx       => "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB",
a31df49
-            Gy       => "938CF935318FDCED6BC28286531733C3F03C4FEE",
a31df49
-            order    => "0100000000000000000001B8FA16DFAB9ACA16B6B3",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp160r1 => {
a31df49
-            oid      => '1.3.132.0.8',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
a31df49
-            A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
a31df49
-            B        => "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
a31df49
-            Gx       => "4A96B5688EF573284664698968C38BB913CBFC82",
a31df49
-            Gy       => "23A628553168947D59DCC912042351377AC5FB32",
a31df49
-            order    => "0100000000000000000001F4C8F927AED3CA752257",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp160r2 => {
a31df49
-            oid      => '1.3.132.0.30',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
a31df49
-            A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70",
a31df49
-            B        => "B4E134D3FB59EB8BAB57274904664D5AF50388BA",
a31df49
-            Gx       => "52DCB034293A117E1F4FF11B30F7199D3144CE6D",
a31df49
-            Gy       => "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E",
a31df49
-            order    => "0100000000000000000000351EE786A818F3A1A16B",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp192k1 => {
a31df49
-            oid      => '1.3.132.0.31',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37",
a31df49
-            A        => "000000000000000000000000000000000000000000000000",
a31df49
-            B        => "000000000000000000000000000000000000000000000003",
a31df49
-            Gx       => "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D",
a31df49
-            Gy       => "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D",
a31df49
-            order    => "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp192r1 => { # == NIST P-192, X9.62 prime192v1
a31df49
-            oid      => '1.2.840.10045.3.1.1',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
a31df49
-            A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
a31df49
-            B        => "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
a31df49
-            Gx       => "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
a31df49
-            Gy       => "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
a31df49
-            order    => "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp224k1 => {
a31df49
-            oid      => '1.3.132.0.32',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D",
a31df49
-            A        => "00000000000000000000000000000000000000000000000000000000",
a31df49
-            B        => "00000000000000000000000000000000000000000000000000000005",
a31df49
-            Gx       => "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C",
a31df49
-            Gy       => "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5",
a31df49
-            order    => "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp224r1 => { # == NIST P-224
a31df49
-            oid      => '1.3.132.0.33',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
a31df49
-            A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
a31df49
-            B        => "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
a31df49
-            Gx       => "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
a31df49
-            Gy       => "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
a31df49
-            order    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp256k1 => {
a31df49
-            oid      => '1.3.132.0.10',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
a31df49
-            A        => "0000000000000000000000000000000000000000000000000000000000000000",
a31df49
-            B        => "0000000000000000000000000000000000000000000000000000000000000007",
a31df49
-            Gx       => "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
a31df49
-            Gy       => "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
a31df49
-            order    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp256r1 => { # == NIST P-256, X9.62 prime256v1
a31df49
-            oid      => '1.2.840.10045.3.1.7',
a31df49
-            prime    => "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
a31df49
-            A        => "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
a31df49
-            B        => "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
a31df49
-            Gx       => "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
a31df49
-            Gy       => "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
a31df49
-            order    => "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp384r1 => { # == NIST P-384
a31df49
-            oid      => '1.3.132.0.34',
a31df49
-            prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
a31df49
-            A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
a31df49
-            B        => "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
a31df49
-            Gx       => "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
a31df49
-            Gy       => "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
a31df49
-            order    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        secp521r1 => { # == NIST P-521
a31df49
-            oid      => '1.3.132.0.35',
a31df49
-            prime    => "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
a31df49
-            A        => "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
a31df49
-            B        => "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
a31df49
-            Gx       => "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
a31df49
-            Gy       => "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
a31df49
-            order    => "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
a31df49
-            cofactor => 1
a31df49
-        },
a31df49
-        ### http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf (July 2013)
a31df49
-        nistp192 => { # == secp192r1, X9.62 prime192v1
a31df49
-            oid      => '1.2.840.10045.3.1.1',
a31df49
-            prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF',
a31df49
-            A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC',
a31df49
-            B        => '64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1',
a31df49
-            Gx       => '188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012',
a31df49
-            Gy       => '07192B95FFC8DA78631011ED6B24CDD573F977A11E794811',
a31df49
-            order    => 'FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        nistp224 => { # == secp224r1
a31df49
-            oid      => '1.3.132.0.33',
a31df49
-            prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001',
a31df49
-            A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE',
a31df49
-            B        => 'B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4',
a31df49
-            Gx       => 'B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21',
a31df49
-            Gy       => 'BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34',
a31df49
-            order    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        nistp256 => { # == secp256r1, X9.62 prime256v1
a31df49
-            oid      => '1.2.840.10045.3.1.7',
a31df49
-            prime    => 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF',
a31df49
-            A        => 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC',
a31df49
-            B        => '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B',
a31df49
-            Gx       => '6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296',
a31df49
-            Gy       => '4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5',
a31df49
-            order    => 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        nistp384 => { # == secp384r1
a31df49
-            oid      => '1.3.132.0.34',
a31df49
-            prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF',
a31df49
-            A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC',
a31df49
-            B        => 'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF',
a31df49
-            Gx       => 'AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7',
a31df49
-            Gy       => '3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F',
a31df49
-            order    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        nistp521 => { # == secp521r1
a31df49
-            oid      => '1.3.132.0.35',
a31df49
-            prime    => '1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
a31df49
-            A        => '1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC',
a31df49
-            B        => '051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00',
a31df49
-            Gx       => '0C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66',
a31df49
-            Gy       => '11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650',
a31df49
-            order    => '1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        ### ANS X9.62 elliptic curves - http://www.flexiprovider.de/CurvesGfpX962.html
a31df49
-        prime192v1 => { # == secp192r1, NIST P-192
a31df49
-            oid      => '1.2.840.10045.3.1.1',
a31df49
-            prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF',
a31df49
-            A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC',
a31df49
-            B        => '64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1',
a31df49
-            Gx       => '188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012',
a31df49
-            Gy       => '07192B95FFC8DA78631011ED6B24CDD573F977A11E794811',
a31df49
-            order    => 'FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        prime192v2 => {
a31df49
-            oid      => '1.2.840.10045.3.1.2',
a31df49
-            prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF',
a31df49
-            A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC',
a31df49
-            B        => 'CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953',
a31df49
-            Gx       => 'EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A',
a31df49
-            Gy       => '6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15',
a31df49
-            order    => 'FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31',
a31df49
-            cofactor => 1
a31df49
-        },
a31df49
-        prime192v3 => {
a31df49
-            oid      => '1.2.840.10045.3.1.3',
a31df49
-            prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF',
a31df49
-            A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC',
a31df49
-            B        => '22123DC2395A05CAA7423DAECCC94760A7D462256BD56916',
a31df49
-            Gx       => '7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896',
a31df49
-            Gy       => '38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0',
a31df49
-            order    => 'FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        prime239v1 => {
a31df49
-            oid      => '1.2.840.10045.3.1.4',
a31df49
-            prime    => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF',
a31df49
-            A        => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC',
a31df49
-            B        => '6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A',
a31df49
-            Gx       => '0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF',
a31df49
-            Gy       => '7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE',
a31df49
-            order    => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        prime239v2 => {
a31df49
-            oid      => '1.2.840.10045.3.1.5',
a31df49
-            prime    => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF',
a31df49
-            A        => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC',
a31df49
-            B        => '617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C',
a31df49
-            Gx       => '38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7',
a31df49
-            Gy       => '5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA',
a31df49
-            order    => '7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        prime239v3 => {
a31df49
-            oid      => '1.2.840.10045.3.1.6',
a31df49
-            prime    => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF',
a31df49
-            A        => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC',
a31df49
-            B        => '255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E',
a31df49
-            Gx       => '6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A',
a31df49
-            Gy       => '1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3',
a31df49
-            order    => '7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-        prime256v1 => { # == secp256r1, NIST P-256
a31df49
-            oid      => '1.2.840.10045.3.1.7',
a31df49
-            prime    => 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF',
a31df49
-            A        => 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC',
a31df49
-            B        => '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B',
a31df49
-            Gx       => '6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296',
a31df49
-            Gy       => '4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5',
a31df49
-            order    => 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551',
a31df49
-            cofactor => 1,
a31df49
-        },
a31df49
-);
a31df49
-
a31df49
-my %jwkcrv = (
a31df49
-        'P-192'   => 'secp192r1',
a31df49
-        'P-224'   => 'secp224r1',
a31df49
-        'P-256'   => 'secp256r1',
a31df49
-        'P-384'   => 'secp384r1',
a31df49
-        'P-521'   => 'secp521r1',
a31df49
-);
a31df49
-
a31df49
-sub _import_hex {
a31df49
-  my ($self, $x, $y, $k, $crv) = @_;
a31df49
-  my $p = $curve{$crv}{prime};
a31df49
-  croak "FATAL: invalid or unknown curve" if !$p;
a31df49
-  $p =~ s/^0+//;
a31df49
-  my $hex_size = length($p) % 2 ? length($p) + 1 : length($p);
a31df49
-  if ($k) {
a31df49
-    $k =~ /^0+/;
a31df49
-    croak "FATAL: too long private key (k)" if length($k) > $hex_size;
a31df49
-    my $priv_hex = "0" x ($hex_size - length($k)) . $k;
a31df49
-    return $self->import_key_raw(pack("H*", $priv_hex), $crv);
a31df49
-  }
a31df49
-  elsif ($x && $y) {
a31df49
-    $x =~ /^0+/;
a31df49
-    $y =~ /^0+/;
a31df49
-    croak "FATAL: too long public key (x)" if length($x) > $hex_size;
a31df49
-    croak "FATAL: too long public key (y)" if length($y) > $hex_size;
a31df49
-    my $pub_hex = "04" . ("0" x ($hex_size - length($x))) . $x . ("0" x ($hex_size - length($y))) . $y;
a31df49
-    return $self->import_key_raw(pack("H*", $pub_hex), $crv);
a31df49
-  }
a31df49
-}
a31df49
-
a31df49
-sub _curve_name_lookup {
a31df49
-  my ($self, $key) = @_;
a31df49
-
a31df49
-  return $key->{curve_name} if $key->{curve_name} && exists $curve{$key->{curve_name}};
a31df49
-
a31df49
-  defined(my $A        = $key->{curve_A})        or return;
a31df49
-  defined(my $B        = $key->{curve_B})        or return;
a31df49
-  defined(my $Gx       = $key->{curve_Gx})       or return;
a31df49
-  defined(my $Gy       = $key->{curve_Gy})       or return;
a31df49
-  defined(my $order    = $key->{curve_order})    or return;
a31df49
-  defined(my $prime    = $key->{curve_prime})    or return;
a31df49
-  defined(my $cofactor = $key->{curve_cofactor}) or return;
a31df49
-  $A     =~ s/^0+//;
a31df49
-  $B     =~ s/^0+//;
a31df49
-  $Gx    =~ s/^0+//;
a31df49
-  $Gy    =~ s/^0+//;
a31df49
-  $order =~ s/^0+//;
a31df49
-  $prime =~ s/^0+//;
a31df49
-
a31df49
-  for my $k (sort keys %curve) {
a31df49
-    (my $c_A       = $curve{$k}{A}       ) =~ s/^0+//;
a31df49
-    (my $c_B       = $curve{$k}{B}       ) =~ s/^0+//;
a31df49
-    (my $c_Gx      = $curve{$k}{Gx}      ) =~ s/^0+//;
a31df49
-    (my $c_Gy      = $curve{$k}{Gy}      ) =~ s/^0+//;
a31df49
-    (my $c_order   = $curve{$k}{order}   ) =~ s/^0+//;
a31df49
-    (my $c_prime   = $curve{$k}{prime}   ) =~ s/^0+//;
a31df49
-    my $c_cofactor = $curve{$k}{cofactor};
a31df49
-    return $k if $A eq $c_A && $B eq $c_B && $Gx eq $c_Gx && $Gy eq $c_Gy &&
a31df49
-                 $order eq $c_order && $prime eq $c_prime && $cofactor == $c_cofactor;
a31df49
-  }
a31df49
-}
a31df49
-
a31df49
-sub new {
a31df49
-  my ($class, $f, $p) = @_;
a31df49
-  my $self = _new();
a31df49
-  $self->import_key($f, $p) if $f;
a31df49
-  return  $self;
a31df49
-}
a31df49
-
a31df49
-sub export_key_pem {
a31df49
-  my ($self, $type, $password, $cipher) = @_;
a31df49
-  my $key = $self->export_key_der($type||'');
a31df49
-  return unless $key;
a31df49
-  return der_to_pem($key, "EC PRIVATE KEY", $password, $cipher) if substr($type, 0, 7) eq 'private';
a31df49
-  return der_to_pem($key, "PUBLIC KEY") if substr($type,0, 6) eq 'public';
a31df49
-}
a31df49
-
a31df49
-sub export_key_jwk {
a31df49
-  my ($self, $type, $wanthash) = @_;
a31df49
-  my $kh = $self->key2hash;
a31df49
-  my $curve = $self->_curve_name_lookup($kh);
a31df49
-  $curve = 'P-192' if $curve =~ /(secp192r1|nistp192|prime192v1)/;
a31df49
-  $curve = 'P-224' if $curve =~ /(secp224r1|nistp224)/;
a31df49
-  $curve = 'P-256' if $curve =~ /(secp256r1|nistp256|prime256v1)/;
a31df49
-  $curve = 'P-384' if $curve =~ /(secp384r1|nistp384)/;
a31df49
-  $curve = 'P-521' if $curve =~ /(secp521r1|nistp521)/;
a31df49
-  if ($type && $type eq 'private') {
a31df49
-    return unless $kh->{pub_x} && $kh->{pub_y} && $kh->{k};
a31df49
-    for (qw/pub_x pub_y k/) {
a31df49
-      $kh->{$_} = "0$kh->{$_}" if length($kh->{$_}) % 2;
a31df49
-    }
a31df49
-    # NOTE: x + y are not necessary in privkey
a31df49
-    # but they are used in https://tools.ietf.org/html/rfc7517#appendix-A.2
a31df49
-    my $hash = {
a31df49
-      kty => "EC", crv=>$curve,
a31df49
-      x => encode_b64u(pack("H*", $kh->{pub_x})),
a31df49
-      y => encode_b64u(pack("H*", $kh->{pub_y})),
a31df49
-      d => encode_b64u(pack("H*", $kh->{k})),
a31df49
-    };
a31df49
-    return $wanthash ? $hash : _encode_json($hash);
a31df49
-  }
a31df49
-  elsif ($type && $type eq 'public') {
a31df49
-    return unless $kh->{pub_x} && $kh->{pub_y};
a31df49
-    for (qw/pub_x pub_y/) {
a31df49
-      $kh->{$_} = "0$kh->{$_}" if length($kh->{$_}) % 2;
a31df49
-    }
a31df49
-    my $hash = {
a31df49
-      kty => "EC", crv=>$curve,
a31df49
-      x => encode_b64u(pack("H*", $kh->{pub_x})),
a31df49
-      y => encode_b64u(pack("H*", $kh->{pub_y})),
a31df49
-    };
a31df49
-    return $wanthash ? $hash : _encode_json($hash);
a31df49
-  }
a31df49
-}
a31df49
-
a31df49
-sub export_key_jwk_thumbprint {
a31df49
-  my ($self, $hash_name) = @_;
a31df49
-  $hash_name ||= 'SHA256';
a31df49
-  my $h = $self->export_key_jwk('public', 1);
a31df49
-  my $json = _encode_json({crv=>$h->{crv}, kty=>$h->{kty}, x=>$h->{x}, y=>$h->{y}});
a31df49
-  return digest_data_b64u($hash_name, $json);
a31df49
-}
a31df49
-
a31df49
-sub import_key {
a31df49
-  my ($self, $key, $password) = @_;
a31df49
-  croak "FATAL: undefined key" unless $key;
a31df49
-
a31df49
-  # special case
a31df49
-  if (ref($key) eq 'HASH') {
a31df49
-    if (($key->{pub_x} && $key->{pub_y}) || $key->{k}) {
a31df49
-      # hash exported via key2hash
a31df49
-      my $curve = $self->_curve_name_lookup($key);
a31df49
-      croak "FATAL: invalid or unknown curve" if !$curve;
a31df49
-      return $self->_import_hex($key->{pub_x}, $key->{pub_y}, $key->{k}, $curve);
a31df49
-    }
a31df49
-    if ($key->{crv} && $key->{kty} && $key->{kty} eq "EC" && ($key->{d} || ($key->{x} && $key->{y}))) {
a31df49
-      # hash with items corresponding to JSON Web Key (JWK)
a31df49
-      $key = {%$key}; # make a copy as we will modify it
a31df49
-      for (qw/x y d/) {
a31df49
-        $key->{$_} = eval { unpack("H*", decode_b64u($key->{$_})) } if exists $key->{$_};
a31df49
-      }
a31df49
-      if (my $curve = $jwkcrv{$key->{crv}}) {
a31df49
-        return $self->_import_hex($key->{x}, $key->{y}, $key->{d}, $curve);
a31df49
-      }
a31df49
-      # curve is not JWK compliant e.g. P-192 P-224 P-256 P-384 P-521 (we'll try to import anyway)
a31df49
-      return $self->_import_hex($key->{x}, $key->{y}, $key->{d}, lc($key->{crv}));
a31df49
-    }
a31df49
-    croak "FATAL: unexpected ECC key hash";
a31df49
-  }
a31df49
-
a31df49
-  my $data;
a31df49
-  if (ref($key) eq 'SCALAR') {
a31df49
-    $data = $$key;
a31df49
-  }
a31df49
-  elsif (-f $key) {
a31df49
-    $data = read_rawfile($key);
a31df49
-  }
a31df49
-  else {
a31df49
-    croak "FATAL: non-existing file '$key'";
a31df49
-  }
a31df49
-  croak "FATAL: invalid key data" unless $data;
a31df49
-
a31df49
-  if ($data =~ /-----BEGIN (EC PRIVATE|EC PUBLIC|PUBLIC) KEY-----(.*?)-----END/sg) {
a31df49
-    $data = pem_to_der($data, $password);
a31df49
-    return $self->_import($data);
a31df49
-  }
a31df49
-  elsif ($data =~ /-----BEGIN PRIVATE KEY-----(.*?)-----END/sg) {
a31df49
-    $data = pem_to_der($data, $password);
a31df49
-    return $self->_import_pkcs8($data, $password);
a31df49
-  }
a31df49
-  elsif ($data =~ /-----BEGIN ENCRYPTED PRIVATE KEY-----(.*?)-----END/sg) {
a31df49
-    # XXX-TODO: pkcs#8 encrypted private key
a31df49
-    croak "FATAL: encrypted pkcs8 EC private keys are not supported";
a31df49
-  }
a31df49
-  elsif ($data =~ /^\s*(\{.*?\})\s*$/s) {
a31df49
-    # JSON Web Key (JWK) - http://tools.ietf.org/html/draft-ietf-jose-json-web-key
a31df49
-    my $json = "$1";
a31df49
-    my $h = _decode_json($json);
a31df49
-    if ($h && $h->{kty} eq "EC") {
a31df49
-      for (qw/x y d/) {
a31df49
-        $h->{$_} = eval { unpack("H*", decode_b64u($h->{$_})) } if exists $h->{$_};
a31df49
-      }
a31df49
-      if (my $curve = $jwkcrv{$h->{crv}}) {
a31df49
-        return $self->_import_hex($h->{x}, $h->{y}, $h->{d}, $curve);
a31df49
-      }
a31df49
-      # curve is not JWK compliant e.g. P-192 P-224 P-256 P-384 P-521 (we'll try to import anyway)
a31df49
-      return $self->_import_hex($h->{x}, $h->{y}, $h->{d}, lc($h->{crv}));
a31df49
-    }
a31df49
-  }
a31df49
-  elsif ($data =~ /---- BEGIN SSH2 PUBLIC KEY ----(.*?)---- END SSH2 PUBLIC KEY ----/sg) {
a31df49
-    $data = pem_to_der($data);
a31df49
-    my ($typ, $skip, $pubkey) = Crypt::PK::_ssh_parse($data);
a31df49
-    return $self->import_key_raw($pubkey, "$2") if $pubkey && $typ =~ /^ecdsa-(.+?)-(.*)$/;
a31df49
-  }
a31df49
-  elsif ($data =~ /(ecdsa-\S+)\s+(\S+)/) {
a31df49
-    $data = decode_b64("$2");
a31df49
-    my ($typ, $skip, $pubkey) = Crypt::PK::_ssh_parse($data);
a31df49
-    return $self->import_key_raw($pubkey, "$2") if $pubkey && $typ =~ /^ecdsa-(.+?)-(.*)$/;
a31df49
-  }
a31df49
-  else {
a31df49
-    my $rv = eval { $self->_import($data) } || eval { $self->_import_pkcs8($data, $password) };
a31df49
-    return $rv if $rv;
a31df49
-  }
a31df49
-  croak "FATAL: invalid or unsupported EC key format";
a31df49
-}
a31df49
-
a31df49
-sub encrypt {
a31df49
-  my ($self, $data, $hash_name) = @_;
a31df49
-  $hash_name = Crypt::Digest::_trans_digest_name($hash_name||'SHA1');
a31df49
-  return $self->_encrypt($data, $hash_name);
a31df49
-}
a31df49
-
a31df49
-sub decrypt {
a31df49
-  my ($self, $data) = @_;
a31df49
-  return $self->_decrypt($data);
a31df49
-}
a31df49
-
a31df49
-sub sign_message {
a31df49
-  my ($self, $data, $hash_name) = @_;
a31df49
-  $hash_name ||= 'SHA1';
a31df49
-  my $data_hash = digest_data($hash_name, $data);
a31df49
-  return $self->_sign($data_hash);
a31df49
-}
a31df49
-
a31df49
-sub sign_message_rfc7518 {
a31df49
-  my ($self, $data, $hash_name) = @_;
a31df49
-  $hash_name ||= 'SHA1';
a31df49
-  my $data_hash = digest_data($hash_name, $data);
a31df49
-  return $self->_sign_rfc7518($data_hash);
a31df49
-}
a31df49
-
a31df49
-sub verify_message {
a31df49
-  my ($self, $sig, $data, $hash_name) = @_;
a31df49
-  $hash_name ||= 'SHA1';
a31df49
-  my $data_hash = digest_data($hash_name, $data);
a31df49
-  return $self->_verify($sig, $data_hash);
a31df49
-}
a31df49
-
a31df49
-sub verify_message_rfc7518 {
a31df49
-  my ($self, $sig, $data, $hash_name) = @_;
a31df49
-  $hash_name ||= 'SHA1';
a31df49
-  my $data_hash = digest_data($hash_name, $data);
a31df49
-  return $self->_verify_rfc7518($sig, $data_hash);
a31df49
-}
a31df49
-
a31df49
-sub sign_hash {
a31df49
-  my ($self, $data_hash) = @_;
a31df49
-  return $self->_sign($data_hash);
a31df49
-}
a31df49
-
a31df49
-sub verify_hash {
a31df49
-  my ($self, $sig, $data_hash) = @_;
a31df49
-  return $self->_verify($sig, $data_hash);
a31df49
-}
a31df49
-
a31df49
-sub curve2hash {
a31df49
-  my $self = shift;
a31df49
-  my $kh = $self->key2hash;
a31df49
-  return {
a31df49
-     prime    => $kh->{curve_prime},
a31df49
-     A        => $kh->{curve_A},
a31df49
-     B        => $kh->{curve_B},
a31df49
-     Gx       => $kh->{curve_Gx},
a31df49
-     Gy       => $kh->{curve_Gy},
a31df49
-     cofactor => $kh->{curve_cofactor},
a31df49
-     order    => $kh->{curve_order}
a31df49
-  };
a31df49
-}
a31df49
-
a31df49
-### FUNCTIONS
a31df49
-
a31df49
-sub ecc_encrypt {
a31df49
-  my $key = shift;
a31df49
-  $key = __PACKAGE__->new($key) unless ref $key;
a31df49
-  carp "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
a31df49
-  return $key->encrypt(@_);
a31df49
-}
a31df49
-
a31df49
-sub ecc_decrypt {
a31df49
-  my $key = shift;
a31df49
-  $key = __PACKAGE__->new($key) unless ref $key;
a31df49
-  carp "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
a31df49
-  return $key->decrypt(@_);
a31df49
-}
a31df49
-
a31df49
-sub ecc_sign_message {
a31df49
-  my $key = shift;
a31df49
-  $key = __PACKAGE__->new($key) unless ref $key;
a31df49
-  carp "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
a31df49
-  return $key->sign_message(@_);
a31df49
-}
a31df49
-
a31df49
-sub ecc_verify_message {
a31df49
-  my $key = shift;
a31df49
-  $key = __PACKAGE__->new($key) unless ref $key;
a31df49
-  carp "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
a31df49
-  return $key->verify_message(@_);
a31df49
-}
a31df49
-
a31df49
-sub ecc_sign_hash {
a31df49
-  my $key = shift;
a31df49
-  $key = __PACKAGE__->new($key) unless ref $key;
a31df49
-  carp "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
a31df49
-  return $key->sign_hash(@_);
a31df49
-}
a31df49
-
a31df49
-sub ecc_verify_hash {
a31df49
-  my $key = shift;
a31df49
-  $key = __PACKAGE__->new($key) unless ref $key;
a31df49
-  carp "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
a31df49
-  return $key->verify_hash(@_);
a31df49
-}
a31df49
-
a31df49
-sub ecc_shared_secret {
a31df49
-  my ($privkey, $pubkey) = @_;
a31df49
-  $privkey = __PACKAGE__->new($privkey) unless ref $privkey;
a31df49
-  $pubkey  = __PACKAGE__->new($pubkey)  unless ref $pubkey;
a31df49
-  carp "FATAL: invalid 'privkey' param" unless ref($privkey) eq __PACKAGE__ && $privkey->is_private;
a31df49
-  carp "FATAL: invalid 'pubkey' param"  unless ref($pubkey)  eq __PACKAGE__;
a31df49
-  return $privkey->shared_secret($pubkey);
a31df49
-}
a31df49
-
a31df49
-sub CLONE_SKIP { 1 } # prevent cloning
a31df49
-
a31df49
-1;
a31df49
-
a31df49
-=pod
a31df49
-
a31df49
-=head1 NAME
a31df49
-
a31df49
-Crypt::PK::ECC - Public key cryptography based on EC
a31df49
-
a31df49
-=head1 SYNOPSIS
a31df49
-
a31df49
- ### OO interface
a31df49
-
a31df49
- #Encryption: Alice
a31df49
- my $pub = Crypt::PK::ECC->new('Bob_pub_ecc1.der');
a31df49
- my $ct = $pub->encrypt("secret message");
a31df49
- #
a31df49
- #Encryption: Bob (received ciphertext $ct)
a31df49
- my $priv = Crypt::PK::ECC->new('Bob_priv_ecc1.der');
a31df49
- my $pt = $priv->decrypt($ct);
a31df49
-
a31df49
- #Signature: Alice
a31df49
- my $priv = Crypt::PK::ECC->new('Alice_priv_ecc1.der');
a31df49
- my $sig = $priv->sign_message($message);
a31df49
- #
a31df49
- #Signature: Bob (received $message + $sig)
a31df49
- my $pub = Crypt::PK::ECC->new('Alice_pub_ecc1.der');
a31df49
- $pub->verify_message($sig, $message) or die "ERROR";
a31df49
-
a31df49
- #Shared secret
a31df49
- my $priv = Crypt::PK::ECC->new('Alice_priv_ecc1.der');
a31df49
- my $pub = Crypt::PK::ECC->new('Bob_pub_ecc1.der');
a31df49
- my $shared_secret = $priv->shared_secret($pub);
a31df49
-
a31df49
- #Key generation
a31df49
- my $pk = Crypt::PK::ECC->new();
a31df49
- $pk->generate_key('secp160r1');
a31df49
- my $private_der = $pk->export_key_der('private');
a31df49
- my $public_der = $pk->export_key_der('public');
a31df49
- my $private_pem = $pk->export_key_pem('private');
a31df49
- my $public_pem = $pk->export_key_pem('public');
a31df49
- my $public_raw = $pk->export_key_raw('public');
a31df49
-
a31df49
- ### Functional interface
a31df49
-
a31df49
- #Encryption: Alice
a31df49
- my $ct = ecc_encrypt('Bob_pub_ecc1.der', "secret message");
a31df49
- #Encryption: Bob (received ciphertext $ct)
a31df49
- my $pt = ecc_decrypt('Bob_priv_ecc1.der', $ct);
a31df49
-
a31df49
- #Signature: Alice
a31df49
- my $sig = ecc_sign_message('Alice_priv_ecc1.der', $message);
a31df49
- #Signature: Bob (received $message + $sig)
a31df49
- ecc_verify_message('Alice_pub_ecc1.der', $sig, $message) or die "ERROR";
a31df49
-
a31df49
- #Shared secret
a31df49
- my $shared_secret = ecc_shared_secret('Alice_priv_ecc1.der', 'Bob_pub_ecc1.der');
a31df49
-
a31df49
-=head1 DESCRIPTION
a31df49
-
a31df49
-The module provides a set of core ECC functions as well as implementation of ECDSA and ECDH.
a31df49
-
a31df49
-Supports elliptic curves C<y^2 = x^3 + a*x + b> over prime fields C<Fp = Z/pZ> (binary fields not supported).
a31df49
-
a31df49
-=head1 METHODS
a31df49
-
a31df49
-=head2 new
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new();
a31df49
- #or
a31df49
- my $pk = Crypt::PK::ECC->new($priv_or_pub_key_filename);
a31df49
- #or
a31df49
- my $pk = Crypt::PK::ECC->new(\$buffer_containing_priv_or_pub_key);
a31df49
-
a31df49
-Support for password protected PEM keys
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($priv_pem_key_filename, $password);
a31df49
- #or
a31df49
- my $pk = Crypt::PK::ECC->new(\$buffer_containing_priv_pem_key, $password);
a31df49
-
a31df49
-=head2 generate_key
a31df49
-
a31df49
-Uses Yarrow-based cryptographically strong random number generator seeded with
a31df49
-random data taken from C</dev/random> (UNIX) or C<CryptGenRandom> (Win32).
a31df49
-
a31df49
- $pk->generate_key($curve_name);
a31df49
- #or
a31df49
- $pk->generate_key($hashref_with_curve_params);
a31df49
-
a31df49
-The following pre-defined C<$curve_name> values are supported:
a31df49
-
a31df49
- # curves from http://www.ecc-brainpool.org/download/Domain-parameters.pdf
a31df49
- 'brainpoolp160r1'
a31df49
- 'brainpoolp192r1'
a31df49
- 'brainpoolp224r1'
a31df49
- 'brainpoolp256r1'
a31df49
- 'brainpoolp320r1'
a31df49
- 'brainpoolp384r1'
a31df49
- 'brainpoolp512r1'
a31df49
- # curves from http://www.secg.org/collateral/sec2_final.pdf
a31df49
- 'secp112r1'
a31df49
- 'secp112r2'
a31df49
- 'secp128r1'
a31df49
- 'secp128r2'
a31df49
- 'secp160k1'
a31df49
- 'secp160r1'
a31df49
- 'secp160r2'
a31df49
- 'secp192k1'
a31df49
- 'secp192r1'   ... same as nistp192, prime192v1
a31df49
- 'secp224k1'
a31df49
- 'secp224r1'   ... same as nistp224
a31df49
- 'secp256k1'   ... used by Bitcoin
a31df49
- 'secp256r1'   ... same as nistp256, prime256v1
a31df49
- 'secp384r1'   ... same as nistp384
a31df49
- 'secp521r1'   ... same as nistp521
a31df49
- #curves from http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
a31df49
- 'nistp192'    ... same as secp192r1, prime192v1
a31df49
- 'nistp224'    ... same as secp224r1
a31df49
- 'nistp256'    ... same as secp256r1, prime256v1
a31df49
- 'nistp384'    ... same as secp384r1
a31df49
- 'nistp521'    ... same as secp521r1
a31df49
- # curves from ANS X9.62
a31df49
- 'prime192v1'   ... same as nistp192, secp192r1
a31df49
- 'prime192v2'
a31df49
- 'prime192v3'
a31df49
- 'prime239v1'
a31df49
- 'prime239v2'
a31df49
- 'prime239v3'
a31df49
- 'prime256v1'   ... same as nistp256, secp256r1
a31df49
-
a31df49
-Using custom curve parameters:
a31df49
-
a31df49
- $pk->generate_key({ prime    => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF',
a31df49
-                     A        => 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC',
a31df49
-                     B        => '22123DC2395A05CAA7423DAECCC94760A7D462256BD56916',
a31df49
-                     Gx       => '7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896',
a31df49
-                     Gy       => '38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0',
a31df49
-                     order    => 'FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13',
a31df49
-                     cofactor => 1 });
a31df49
-
a31df49
-See L<http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf>, L<http://www.secg.org/collateral/sec2_final.pdf>, L<http://www.ecc-brainpool.org/download/Domain-parameters.pdf>
a31df49
-
a31df49
-=head2 import_key
a31df49
-
a31df49
-Loads private or public key in DER or PEM format.
a31df49
-
a31df49
- $pk->import_key($filename);
a31df49
- #or
a31df49
- $pk->import_key(\$buffer_containing_key);
a31df49
-
a31df49
-Support for password protected PEM keys:
a31df49
-
a31df49
- $pk->import_key($filename, $password);
a31df49
- #or
a31df49
- $pk->import_key(\$buffer_containing_key, $password);
a31df49
-
a31df49
-Loading private or public keys form perl hash:
a31df49
-
a31df49
- $pk->import_key($hashref);
a31df49
-
a31df49
- # the $hashref is either a key exported via key2hash
a31df49
- $pk->import_key({
a31df49
-      curve_A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
a31df49
-      curve_B        => "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
a31df49
-      curve_bits     => 160,
a31df49
-      curve_bytes    => 20,
a31df49
-      curve_cofactor => 1,
a31df49
-      curve_Gx       => "4A96B5688EF573284664698968C38BB913CBFC82",
a31df49
-      curve_Gy       => "23A628553168947D59DCC912042351377AC5FB32",
a31df49
-      curve_order    => "0100000000000000000001F4C8F927AED3CA752257",
a31df49
-      curve_prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
a31df49
-      k              => "B0EE84A749FE95DF997E33B8F333E12101E824C3",
a31df49
-      pub_x          => "5AE1ACE3ED0AEA9707CE5C0BCE014F6A2F15023A",
a31df49
-      pub_y          => "895D57E992D0A15F88D6680B27B701F615FCDC0F",
a31df49
- });
a31df49
-
a31df49
- # or with the curve defined just by name
a31df49
- $pk->import_key({
a31df49
-      curve_name => "secp160r1",
a31df49
-      k          => "B0EE84A749FE95DF997E33B8F333E12101E824C3",
a31df49
-      pub_x      => "5AE1ACE3ED0AEA9707CE5C0BCE014F6A2F15023A",
a31df49
-      pub_y      => "895D57E992D0A15F88D6680B27B701F615FCDC0F",
a31df49
- });
a31df49
-
a31df49
- # or a hash with items corresponding to JWK (JSON Web Key)
a31df49
- $pk->import_key({
a31df49
-       kty => "EC",
a31df49
-       crv => "P-256",
a31df49
-       x   => "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
a31df49
-       y   => "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
a31df49
-       d   => "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
a31df49
- });
a31df49
-
a31df49
-Supported key formats:
a31df49
-
a31df49
- # all formats can be loaded from a file
a31df49
- my $pk = Crypt::PK::ECC->new($filename);
a31df49
-
a31df49
- # or from a buffer containing the key
a31df49
- my $pk = Crypt::PK::ECC->new(\$buffer_with_key);
a31df49
-
a31df49
-=over
a31df49
-
a31df49
-=item * EC private keys with with all curve parameters
a31df49
-
a31df49
- -----BEGIN EC PRIVATE KEY-----
a31df49
- MIIB+gIBAQQwCKEAcA6cIt6CGfyLKm57LyXWv2PgTjydrHSbvhDJTOl+7bzUW8DS
a31df49
- rgSdtSPONPq1oIIBWzCCAVcCAQEwPAYHKoZIzj0BAQIxAP//////////////////
a31df49
- ///////////////////////+/////wAAAAAAAAAA/////zB7BDD/////////////
a31df49
- /////////////////////////////v////8AAAAAAAAAAP////wEMLMxL6fiPufk
a31df49
- mI4Fa+P4LRkYHZxu/oFBEgMUCI9QE4daxlY5jYou0Z0qhcjt0+wq7wMVAKM1kmqj
a31df49
- GaJ6HQCJamdzpIJ6zaxzBGEEqofKIr6LBTeOscce8yCtdG4dO2KLp5uYWfdB4IJU
a31df49
- KjhVAvJdv1UpbDpUXjhydgq3NhfeSpYmLG9dnpi/kpLcKfj0Hb0omhR86doxE7Xw
a31df49
- uMAKYLHOHX6BnXpDHXyQ6g5fAjEA////////////////////////////////x2NN
a31df49
- gfQ3Ld9YGg2ySLCneuzsGWrMxSlzAgEBoWQDYgAEeGyHPLmHcszPQ9MIIYnznpzi
a31df49
- QbvuJtYSjCqtIGxDfzgcLcc3nCc5tBxo+qX6OJEzcWdDAC0bwplY+9Z9jHR3ylNy
a31df49
- ovlHoK4ItdWkVO8NH89SLSRyVuOF8N5t3CHIo93B
a31df49
- -----END EC PRIVATE KEY-----
a31df49
-
a31df49
-=item * EC private keys with curve defined by OID (short form)
a31df49
-
a31df49
- -----BEGIN EC PRIVATE KEY-----
a31df49
- MHcCAQEEIBG1c3z52T8XwMsahGVdOZWgKCQJfv+l7djuJjgetdbDoAoGCCqGSM49
a31df49
- AwEHoUQDQgAEoBUyo8CQAFPeYPvv78ylh5MwFZjTCLQeb042TjiMJxG+9DLFmRSM
a31df49
- lBQ9T/RsLLc+PmpB1+7yPAR+oR5gZn3kJQ==
a31df49
- -----END EC PRIVATE KEY-----
a31df49
-
a31df49
-=item * EC private keys in password protected PEM format
a31df49
-
a31df49
- -----BEGIN EC PRIVATE KEY-----
a31df49
- Proc-Type: 4,ENCRYPTED
a31df49
- DEK-Info: AES-128-CBC,98245C830C9282F7937E13D1D5BA11EC
a31df49
-
a31df49
- 0Y85oZ2+BKXYwrkBjsZdj6gnhOAfS5yDVmEsxFCDug+R3+Kw3QvyIfO4MVo9iWoA
a31df49
- D7wtoRfbt2OlBaLVl553+6QrUoa2DyKf8kLHQs1x1/J7tJOMM4SCXjlrOaToQ0dT
a31df49
- o7fOnjQjHne16pjgBVqGilY/I79Ab85AnE4uw7vgEucBEiU0d3nrhwuS2Opnhzyx
a31df49
- 009q9VLDPwY2+q7tXjTqnk9mCmQgsiaDJqY09wlauSukYPgVuOJFmi1VdkRSDKYZ
a31df49
- rUUsQvz6Q6Q+QirSlfHna+NhUgQ2eyhGszwcP6NU8iqIxI+NCwfFVuAzw539yYwS
a31df49
- 8SICczoC/YRlaclayXuomQ==
a31df49
- -----END EC PRIVATE KEY-----
a31df49
-
a31df49
-=item * EC public keys with all curve parameters
a31df49
-
a31df49
- -----BEGIN PUBLIC KEY-----
a31df49
- MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD/////////////////
a31df49
- ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb
a31df49
- /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh
a31df49
- AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABITjF/nKK3jg
a31df49
- pjmBRXKWAv7ekR1Ko/Nb5FFPHXjH0sDrpS7qRxFALwJHv7ylGnekgfKU3vzcewNs
a31df49
- lvjpBYt0Yg4=
a31df49
- -----END PUBLIC KEY-----
a31df49
-
a31df49
-=item * EC public keys with curve defined by OID (short form)
a31df49
-
a31df49
- -----BEGIN PUBLIC KEY-----
a31df49
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoBUyo8CQAFPeYPvv78ylh5MwFZjT
a31df49
- CLQeb042TjiMJxG+9DLFmRSMlBQ9T/RsLLc+PmpB1+7yPAR+oR5gZn3kJQ==
a31df49
- -----END PUBLIC KEY-----
a31df49
-
a31df49
-=item * PKCS#8 private keys with all curve parameters
a31df49
-
a31df49
- -----BEGIN PRIVATE KEY-----
a31df49
- MIIBMAIBADCB0wYHKoZIzj0CATCBxwIBATAkBgcqhkjOPQEBAhkA////////////
a31df49
- /////////v//////////MEsEGP////////////////////7//////////AQYIhI9
a31df49
- wjlaBcqnQj2uzMlHYKfUYiVr1WkWAxUAxGloRDXes3jEtlypWR4qV2MFmi4EMQR9
a31df49
- KXeBAMZaHaF4NxZYjc4ri0rujiKPGJY4qQ8iY3M3M0tJ3LZqbcj5l4rKdkipQ7AC
a31df49
- GQD///////////////96YtAxyD9ClPZA7BMCAQEEVTBTAgEBBBiKolTGIsTgOCtl
a31df49
- 6dpdos0LvuaExCDFyT6hNAMyAAREwaCX0VY1LZxLW3G75tmft4p9uhc0J7/+NGaP
a31df49
- DN3Tr7SXkT9+co2a+8KPJhQy10k=
a31df49
- -----END PRIVATE KEY-----
a31df49
-
a31df49
-=item * PKCS#8 private keys with curve defined by OID (short form)
a31df49
-
a31df49
- -----BEGIN PRIVATE KEY-----
a31df49
- MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQMEVTBTAgEBBBjFP/caeQV4WO3fnWWS
a31df49
- f917PGzwtypd/t+hNAMyAATSg6pBT7RO6l/p+aKcrFsGuthUdfwJWS5V3NGcVt1b
a31df49
- lEHQYjWya2YnHaPq/iMFa7A=
a31df49
- -----END PRIVATE KEY-----
a31df49
-
a31df49
-=item * PKCS#8 encrypted private keys ARE NOT SUPPORTED YET!
a31df49
-
a31df49
- -----BEGIN ENCRYPTED PRIVATE KEY-----
a31df49
- MIGYMBwGCiqGSIb3DQEMAQMwDgQINApjTa6oFl0CAggABHi+59l4d4e6KtG9yci2
a31df49
- BSC65LEsQSnrnFAExfKptNU1zMFsDLCRvDeDQDbxc6HlfoxyqFL4SmH1g3RvC/Vv
a31df49
- NfckdL5O2L8MRnM+ljkFtV2Te4fszWcJFdd7KiNOkPpn+7sWLfzQdvhHChLKUzmz
a31df49
- 4INKZyMv/G7VpZ0=
a31df49
- -----END ENCRYPTED PRIVATE KEY-----
a31df49
-
a31df49
-=item * SSH public EC keys
a31df49
-
a31df49
- ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT...T3xYfJIs=
a31df49
-
a31df49
-=item * SSH public EC keys (RFC-4716 format)
a31df49
-
a31df49
- ---- BEGIN SSH2 PUBLIC KEY ----
a31df49
- Comment: "521-bit ECDSA, converted from OpenSSH"
a31df49
- AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFk35srteP9twCwYK
a31df49
- vU9ovMBi77Dd6lEBPrFaMEb0CZdZ5MC3nSqflGHRWkSbUpjdPdO7cYQNpK9YXHbNSO5hbU
a31df49
- 1gFZgyiGFxwJYYz8NAjedBXMgyH4JWplK5FQm5P5cvaglItC9qkKioUXhCc67YMYBtivXl
a31df49
- Ue0PgIq6kbHTqbX6+5Nw==
a31df49
- ---- END SSH2 PUBLIC KEY ----
a31df49
-
a31df49
-=item * EC private keys in JSON Web Key (JWK) format
a31df49
-
a31df49
-See L<http://tools.ietf.org/html/draft-ietf-jose-json-web-key>
a31df49
-
a31df49
- {
a31df49
-  "kty":"EC",
a31df49
-  "crv":"P-256",
a31df49
-  "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
a31df49
-  "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
a31df49
-  "d":"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
a31df49
- }
a31df49
-
a31df49
-B<BEWARE:> For JWK support you need to have L<JSON::PP>, L<JSON::XS> or L<Cpanel::JSON::XS> module.
a31df49
-
a31df49
-=item * EC public keys in JSON Web Key (JWK) format
a31df49
-
a31df49
- {
a31df49
-  "kty":"EC",
a31df49
-  "crv":"P-256",
a31df49
-  "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
a31df49
-  "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
a31df49
- }
a31df49
-
a31df49
-B<BEWARE:> For JWK support you need to have L<JSON::PP>, L<JSON::XS> or L<Cpanel::JSON::XS> module.
a31df49
-
a31df49
-=back
a31df49
-
a31df49
-=head2 import_key_raw
a31df49
-
a31df49
-Import raw public/private key - can load data exported by L</export_key_raw>.
a31df49
-
a31df49
- $pk->import_key_raw($key, $curve);
a31df49
- # $key .... data exported by export_key_raw()
a31df49
- # $curve .. curve name or hashref with curve parameters - same as by generate_key()
a31df49
-
a31df49
-=head2 export_key_der
a31df49
-
a31df49
- my $private_der = $pk->export_key_der('private');
a31df49
- #or
a31df49
- my $public_der = $pk->export_key_der('public');
a31df49
-
a31df49
-Since CryptX-0.36 C<export_key_der> can also export keys in a format
a31df49
-that does not explicitely contain curve parameters but only curve OID.
a31df49
-
a31df49
- my $private_der = $pk->export_key_der('private_short');
a31df49
- #or
a31df49
- my $public_der = $pk->export_key_der('public_short');
a31df49
-
a31df49
-=head2 export_key_pem
a31df49
-
a31df49
- my $private_pem = $pk->export_key_pem('private');
a31df49
- #or
a31df49
- my $public_pem = $pk->export_key_pem('public');
a31df49
-
a31df49
-Since CryptX-0.36 C<export_key_pem> can also export keys in a format
a31df49
-that does not explicitely contain curve parameters but only curve OID.
a31df49
-
a31df49
- my $private_pem = $pk->export_key_pem('private_short');
a31df49
- #or
a31df49
- my $public_pem = $pk->export_key_pem('public_short');
a31df49
-
a31df49
-Support for password protected PEM keys
a31df49
-
a31df49
- my $private_pem = $pk->export_key_pem('private', $password);
a31df49
- #or
a31df49
- my $private_pem = $pk->export_key_pem('private', $password, $cipher);
a31df49
-
a31df49
- # supported ciphers: 'DES-CBC'
a31df49
- #                    'DES-EDE3-CBC'
a31df49
- #                    'SEED-CBC'
a31df49
- #                    'CAMELLIA-128-CBC'
a31df49
- #                    'CAMELLIA-192-CBC'
a31df49
- #                    'CAMELLIA-256-CBC'
a31df49
- #                    'AES-128-CBC'
a31df49
- #                    'AES-192-CBC'
a31df49
- #                    'AES-256-CBC' (DEFAULT)
a31df49
-
a31df49
-=head2 export_key_jwk
a31df49
-
a31df49
-I<Since: CryptX-0.022>
a31df49
-
a31df49
-Exports public/private keys as a JSON Web Key (JWK).
a31df49
-
a31df49
- my $private_json_text = $pk->export_key_jwk('private');
a31df49
- #or
a31df49
- my $public_json_text = $pk->export_key_jwk('public');
a31df49
-
a31df49
-Also exports public/private keys as a perl HASH with JWK structure.
a31df49
-
a31df49
- my $jwk_hash = $pk->export_key_jwk('private', 1);
a31df49
- #or
a31df49
- my $jwk_hash = $pk->export_key_jwk('public', 1);
a31df49
-
a31df49
-B<BEWARE:> For JWK support you need to have L<JSON::PP>, L<JSON::XS> or L<Cpanel::JSON::XS> module.
a31df49
-
a31df49
-=head2 export_key_jwk_thumbprint
a31df49
-
a31df49
-I<Since: CryptX-0.031>
a31df49
-
a31df49
-Exports the key's JSON Web Key Thumbprint as a string.
a31df49
-
a31df49
-If you don't know what this is, see RFC 7638 (C<https://tools.ietf.org/html/rfc7638>).
a31df49
-
a31df49
- my $thumbprint = $pk->export_key_jwk_thumbprint('SHA256');
a31df49
-
a31df49
-=head2 export_key_raw
a31df49
-
a31df49
-Export raw public/private key. Public key is exported in ANS X9.63 format (compressed or uncompressed),
a31df49
-private key is exported as raw bytes (padded with leading zeros to have the same size as the ECC curve).
a31df49
-
a31df49
- my $pubkey_octets  = $pk->export_key_raw('public');
a31df49
- #or
a31df49
- my $pubckey_octets = $pk->export_key_raw('public_compressed');
a31df49
- #or
a31df49
- my $privkey_octets = $pk->export_key_raw('private');
a31df49
-
a31df49
-=head2 encrypt
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($pub_key_filename);
a31df49
- my $ct = $pk->encrypt($message);
a31df49
- #or
a31df49
- my $ct = $pk->encrypt($message, $hash_name);
a31df49
-
a31df49
- #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
a31df49
-
a31df49
-=head2 decrypt
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($priv_key_filename);
a31df49
- my $pt = $pk->decrypt($ciphertext);
a31df49
-
a31df49
-=head2 sign_message
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($priv_key_filename);
a31df49
- my $signature = $priv->sign_message($message);
a31df49
- #or
a31df49
- my $signature = $priv->sign_message($message, $hash_name);
a31df49
-
a31df49
- #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
a31df49
-
a31df49
-=head2 sign_message_rfc7518
a31df49
-
a31df49
-I<Since: CryptX-0.024>
a31df49
-
a31df49
-Same as L<sign_message|/sign_message> only the signature format is as defined by L<https://tools.ietf.org/html/rfc7518>
a31df49
-(JWA - JSON Web Algorithms).
a31df49
-
a31df49
-=head2 verify_message
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($pub_key_filename);
a31df49
- my $valid = $pub->verify_message($signature, $message)
a31df49
- #or
a31df49
- my $valid = $pub->verify_message($signature, $message, $hash_name);
a31df49
-
a31df49
- #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
a31df49
-
a31df49
-=head2 verify_message_rfc7518
a31df49
-
a31df49
-I<Since: CryptX-0.024>
a31df49
-
a31df49
-Same as L<verify_message|/verify_message> only the signature format is as defined by L<https://tools.ietf.org/html/rfc7518>
a31df49
-(JWA - JSON Web Algorithms).
a31df49
-
a31df49
-=head2 sign_hash
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($priv_key_filename);
a31df49
- my $signature = $priv->sign_hash($message_hash);
a31df49
-
a31df49
-=head2 verify_hash
a31df49
-
a31df49
- my $pk = Crypt::PK::ECC->new($pub_key_filename);
a31df49
- my $valid = $pub->verify_hash($signature, $message_hash);
a31df49
-
a31df49
-=head2 shared_secret
a31df49
-
a31df49
-  # Alice having her priv key $pk and Bob's public key $pkb
a31df49
-  my $pk  = Crypt::PK::ECC->new($priv_key_filename);
a31df49
-  my $pkb = Crypt::PK::ECC->new($pub_key_filename);
a31df49
-  my $shared_secret = $pk->shared_secret($pkb);
a31df49
-
a31df49
-  # Bob having his priv key $pk and Alice's public key $pka
a31df49
-  my $pk = Crypt::PK::ECC->new($priv_key_filename);
a31df49
-  my $pka = Crypt::PK::ECC->new($pub_key_filename);
a31df49
-  my $shared_secret = $pk->shared_secret($pka);  # same value as computed by Alice
a31df49
-
a31df49
-=head2 is_private
a31df49
-
a31df49
- my $rv = $pk->is_private;
a31df49
- # 1 .. private key loaded
a31df49
- # 0 .. public key loaded
a31df49
- # undef .. no key loaded
a31df49
-
a31df49
-=head2 size
a31df49
-
a31df49
- my $size = $pk->size;
a31df49
- # returns key size in bytes or undef if no key loaded
a31df49
-
a31df49
-=head2 key2hash
a31df49
-
a31df49
- my $hash = $pk->key2hash;
a31df49
-
a31df49
- # returns hash like this (or undef if no key loaded):
a31df49
- {
a31df49
-   size           => 20, # integer: key (curve) size in bytes
a31df49
-   type           => 1,  # integer: 1 .. private, 0 .. public
a31df49
-   #curve parameters
a31df49
-   curve_A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
a31df49
-   curve_B        => "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
a31df49
-   curve_bits     => 160,
a31df49
-   curve_bytes    => 20,
a31df49
-   curve_cofactor => 1,
a31df49
-   curve_Gx       => "4A96B5688EF573284664698968C38BB913CBFC82",
a31df49
-   curve_Gy       => "23A628553168947D59DCC912042351377AC5FB32",
a31df49
-   curve_name     => "secp160r1",
a31df49
-   curve_order    => "0100000000000000000001F4C8F927AED3CA752257",
a31df49
-   curve_prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
a31df49
-   #private key
a31df49
-   k              => "B0EE84A749FE95DF997E33B8F333E12101E824C3",
a31df49
-   #public key point coordinates
a31df49
-   pub_x          => "5AE1ACE3ED0AEA9707CE5C0BCE014F6A2F15023A",
a31df49
-   pub_y          => "895D57E992D0A15F88D6680B27B701F615FCDC0F",
a31df49
- }
a31df49
-
a31df49
-=head2 curve2hash
a31df49
-
a31df49
-I<Since: CryptX-0.024>
a31df49
-
a31df49
- my $crv = $pk->curve2hash;
a31df49
-
a31df49
- # returns a hash that can be passed to: $pk->generate_key($crv)
a31df49
- {
a31df49
-   A        => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
a31df49
-   B        => "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
a31df49
-   cofactor => 1,
a31df49
-   Gx       => "4A96B5688EF573284664698968C38BB913CBFC82",
a31df49
-   Gy       => "23A628553168947D59DCC912042351377AC5FB32",
a31df49
-   order    => "0100000000000000000001F4C8F927AED3CA752257",
a31df49
-   prime    => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
a31df49
- }
a31df49
-
a31df49
-=head1 FUNCTIONS
a31df49
-
a31df49
-=head2 ecc_encrypt
a31df49
-
a31df49
-Elliptic Curve Diffie-Hellman (ECDH) encryption as implemented by libtomcrypt. See method L</encrypt> below.
a31df49
-
a31df49
- my $ct = ecc_encrypt($pub_key_filename, $message);
a31df49
- #or
a31df49
- my $ct = ecc_encrypt(\$buffer_containing_pub_key, $message);
a31df49
- #or
a31df49
- my $ct = ecc_encrypt($pub_key_filename, $message, $hash_name);
a31df49
-
a31df49
- #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
a31df49
-
a31df49
-ECCDH Encryption is performed by producing a random key, hashing it, and XOR'ing the digest against the plaintext.
a31df49
-
a31df49
-=head2 ecc_decrypt
a31df49
-
a31df49
-Elliptic Curve Diffie-Hellman (ECDH) decryption as implemented by libtomcrypt. See method L</decrypt> below.
a31df49
-
a31df49
- my $pt = ecc_decrypt($priv_key_filename, $ciphertext);
a31df49
- #or
a31df49
- my $pt = ecc_decrypt(\$buffer_containing_priv_key, $ciphertext);
a31df49
-
a31df49
-=head2 ecc_sign_message
a31df49
-
a31df49
-Elliptic Curve Digital Signature Algorithm (ECDSA) - signature generation. See method L</sign_message> below.
a31df49
-
a31df49
- my $sig = ecc_sign_message($priv_key_filename, $message);
a31df49
- #or
a31df49
- my $sig = ecc_sign_message(\$buffer_containing_priv_key, $message);
a31df49
- #or
a31df49
- my $sig = ecc_sign_message($priv_key, $message, $hash_name);
a31df49
-
a31df49
-=head2 ecc_verify_message
a31df49
-
a31df49
-Elliptic Curve Digital Signature Algorithm (ECDSA) - signature verification. See method L</verify_message> below.
a31df49
-
a31df49
- ecc_verify_message($pub_key_filename, $signature, $message) or die "ERROR";
a31df49
- #or
a31df49
- ecc_verify_message(\$buffer_containing_pub_key, $signature, $message) or die "ERROR";
a31df49
- #or
a31df49
- ecc_verify_message($pub_key, $signature, $message, $hash_name) or die "ERROR";
a31df49
-
a31df49
-=head2 ecc_sign_hash
a31df49
-
a31df49
-Elliptic Curve Digital Signature Algorithm (ECDSA) - signature generation. See method L</sign_hash> below.
a31df49
-
a31df49
- my $sig = ecc_sign_hash($priv_key_filename, $message_hash);
a31df49
- #or
a31df49
- my $sig = ecc_sign_hash(\$buffer_containing_priv_key, $message_hash);
a31df49
-
a31df49
-=head2 ecc_verify_hash
a31df49
-
a31df49
-Elliptic Curve Digital Signature Algorithm (ECDSA) - signature verification. See method L</verify_hash> below.
a31df49
-
a31df49
- ecc_verify_hash($pub_key_filename, $signature, $message_hash) or die "ERROR";
a31df49
- #or
a31df49
- ecc_verify_hash(\$buffer_containing_pub_key, $signature, $message_hash) or die "ERROR";
a31df49
-
a31df49
-=head2 ecc_shared_secret
a31df49
-
a31df49
-Elliptic curve Diffie-Hellman (ECDH) - construct a Diffie-Hellman shared secret with a private and public ECC key. See method L</shared_secret> below.
a31df49
-
a31df49
- #on Alice side
a31df49
- my $shared_secret = ecc_shared_secret('Alice_priv_ecc1.der', 'Bob_pub_ecc1.der');
a31df49
-
a31df49
- #on Bob side
a31df49
- my $shared_secret = ecc_shared_secret('Bob_priv_ecc1.der', 'Alice_pub_ecc1.der');
a31df49
-
a31df49
-=head1 OpenSSL interoperability
a31df49
-
a31df49
- ### let's have:
a31df49
- # ECC private key in PEM format - eckey.priv.pem
a31df49
- # ECC public key in PEM format  - eckey.pub.pem
a31df49
- # data file to be signed - input.data
a31df49
-
a31df49
-=head2 Sign by OpenSSL, verify by Crypt::PK::ECC
a31df49
-
a31df49
-Create signature (from commandline):
a31df49
-
a31df49
- openssl dgst -sha1 -sign eckey.priv.pem -out input.sha1-ec.sig input.data
a31df49
-
a31df49
-Verify signature (Perl code):
a31df49
-
a31df49
- use Crypt::PK::ECC;
a31df49
- use Crypt::Digest 'digest_file';
a31df49
- use File::Slurp 'read_file';
a31df49
-
a31df49
- my $pkec = Crypt::PK::ECC->new("eckey.pub.pem");
a31df49
- my $signature = read_file("input.sha1-ec.sig", binmode=>':raw');
a31df49
- my $valid = $pkec->verify_hash($signature, digest_file("SHA1", "input.data"), "SHA1", "v1.5");
a31df49
- print $valid ? "SUCCESS" : "FAILURE";
a31df49
-
a31df49
-=head2 Sign by Crypt::PK::ECC, verify by OpenSSL
a31df49
-
a31df49
-Create signature (Perl code):
a31df49
-
a31df49
- use Crypt::PK::ECC;
a31df49
- use Crypt::Digest 'digest_file';
a31df49
- use File::Slurp 'write_file';
a31df49
-
a31df49
- my $pkec = Crypt::PK::ECC->new("eckey.priv.pem");
a31df49
- my $signature = $pkec->sign_hash(digest_file("SHA1", "input.data"), "SHA1", "v1.5");
a31df49
- write_file("input.sha1-ec.sig", {binmode=>':raw'}, $signature);
a31df49
-
a31df49
-Verify signature (from commandline):
a31df49
-
a31df49
- openssl dgst -sha1 -verify eckey.pub.pem -signature input.sha1-ec.sig input.data
a31df49
-
a31df49
-=head2 Keys generated by Crypt::PK::ECC
a31df49
-
a31df49
-Generate keys (Perl code):
a31df49
-
a31df49
- use Crypt::PK::ECC;
a31df49
- use File::Slurp 'write_file';
a31df49
-
a31df49
- my $pkec = Crypt::PK::ECC->new;
a31df49
- $pkec->generate_key('secp160k1');
a31df49
- write_file("eckey.pub.der",  {binmode=>':raw'}, $pkec->export_key_der('public'));
a31df49
- write_file("eckey.priv.der", {binmode=>':raw'}, $pkec->export_key_der('private'));
a31df49
- write_file("eckey.pub.pem",  $pkec->export_key_pem('public'));
a31df49
- write_file("eckey.priv.pem", $pkec->export_key_pem('private'));
a31df49
- write_file("eckey-passwd.priv.pem", $pkec->export_key_pem('private', 'secret'));
a31df49
-
a31df49
-Use keys by OpenSSL:
a31df49
-
a31df49
- openssl ec -in eckey.priv.der -text -inform der
a31df49
- openssl ec -in eckey.priv.pem -text
a31df49
- openssl ec -in eckey-passwd.priv.pem -text -inform pem -passin pass:secret
a31df49
- openssl ec -in eckey.pub.der -pubin -text -inform der
a31df49
- openssl ec -in eckey.pub.pem -pubin -text
a31df49
-
a31df49
-=head2 Keys generated by OpenSSL
a31df49
-
a31df49
-Generate keys:
a31df49
-
a31df49
- openssl ecparam -param_enc explicit -name prime192v3 -genkey -out eckey.priv.pem
a31df49
- openssl ec -param_enc explicit -in eckey.priv.pem -out eckey.pub.pem -pubout
a31df49
- openssl ec -param_enc explicit -in eckey.priv.pem -out eckey.priv.der -outform der
a31df49
- openssl ec -param_enc explicit -in eckey.priv.pem -out eckey.pub.der -outform der -pubout
a31df49
- openssl ec -param_enc explicit -in eckey.priv.pem -out eckey.privc.der -outform der -conv_form compressed
a31df49
- openssl ec -param_enc explicit -in eckey.priv.pem -out eckey.pubc.der -outform der -pubout -conv_form compressed
a31df49
- openssl ec -param_enc explicit -in eckey.priv.pem -passout pass:secret -des3 -out eckey-passwd.priv.pem
a31df49
-
a31df49
-Load keys (Perl code):
a31df49
-
a31df49
- use Crypt::PK::ECC;
a31df49
- use File::Slurp 'write_file';
a31df49
-
a31df49
- my $pkec = Crypt::PK::ECC->new;
a31df49
- $pkec->import_key("eckey.pub.der");
a31df49
- $pkec->import_key("eckey.pubc.der");
a31df49
- $pkec->import_key("eckey.priv.der");
a31df49
- $pkec->import_key("eckey.privc.der");
a31df49
- $pkec->import_key("eckey.pub.pem");
a31df49
- $pkec->import_key("eckey.priv.pem");
a31df49
- $pkec->import_key("eckey-passwd.priv.pem", "secret");
a31df49
-
a31df49
-=head1 SEE ALSO
a31df49
-
a31df49
-=over
a31df49
-
a31df49
-=item * L<https://en.wikipedia.org/wiki/Elliptic_curve_cryptography|https://en.wikipedia.org/wiki/Elliptic_curve_cryptography>
a31df49
-
a31df49
-=item * L<https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman|https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman>
a31df49
-
a31df49
-=item * L<https://en.wikipedia.org/wiki/ECDSA|https://en.wikipedia.org/wiki/ECDSA>
a31df49
-
a31df49
-=back
a31df49
diff --git a/t/001_compile.t b/t/001_compile.t
a31df49
index 0795acf..7f5c223 100644
a31df49
--- a/t/001_compile.t
a31df49
+++ b/t/001_compile.t
a31df49
@@ -62,7 +62,7 @@ use Crypt::Mode::CFB;
a31df49
 use Crypt::Mode::CTR;
a31df49
 use Crypt::PK::RSA;
a31df49
 use Crypt::PK::DSA;
a31df49
-use Crypt::PK::ECC;
a31df49
+#use Crypt::PK::ECC;
a31df49
 use Crypt::PK::DH;
a31df49
 use Crypt::Checksum;
a31df49
 use Crypt::Checksum::Adler32;
a31df49
diff --git a/t/003_all_pm_pod.t b/t/003_all_pm_pod.t
a31df49
index 4911c4f..ff75ff0 100644
a31df49
--- a/t/003_all_pm_pod.t
a31df49
+++ b/t/003_all_pm_pod.t
a31df49
@@ -5,11 +5,11 @@ use Test::More;
a31df49
 
a31df49
 plan skip_all => "File::Find not installed" unless eval { require File::Find };
a31df49
 plan skip_all => "Test::Pod not installed" unless eval { require Test::Pod };
a31df49
-plan tests => 98;
a31df49
+plan tests => 97 + (eval {require CryptX::PK::ECC; 1} // 0);
a31df49
 
a31df49
 my @files;
a31df49
 File::Find::find({ wanted=>sub { push @files, $_ if /\.pm$/ }, no_chdir=>1 }, 'lib');
a31df49
 
a31df49
 for my $m (sort @files) {
a31df49
   Test::Pod::pod_file_ok( $m, "Valid POD in '$m'" );
a31df49
-}
a31df49
\ No newline at end of file
a31df49
+}
a31df49
diff --git a/t/jwk.t b/t/jwk.t
a31df49
index 11e4c36..85b0c0a 100644
a31df49
--- a/t/jwk.t
a31df49
+++ b/t/jwk.t
a31df49
@@ -2,8 +2,11 @@ use strict;
a31df49
 use warnings;
a31df49
 use Test::More;
a31df49
 
a31df49
+BEGIN {
a31df49
 plan skip_all => "No JSON::* module installed" unless eval { require JSON::PP } || eval { require JSON::XS } || eval { require Cpanel::JSON::XS };
a31df49
+plan skip_all => "ECC disabled" unless eval {require Crypt::PK::ECC; 1};
a31df49
 plan tests => 97;
a31df49
+}
a31df49
 
a31df49
 use Crypt::PK::RSA;
a31df49
 use Crypt::PK::ECC;
a31df49
diff --git a/t/pk_ecc.t b/t/pk_ecc.t
a31df49
index 27fd0b8..93e2ab3 100644
a31df49
--- a/t/pk_ecc.t
a31df49
+++ b/t/pk_ecc.t
a31df49
@@ -1,6 +1,11 @@
a31df49
 use strict;
a31df49
 use warnings;
a31df49
-use Test::More tests => 121;
a31df49
+use Test::More;
a31df49
+
a31df49
+BEGIN {
a31df49
+    plan skip_all => "ECC disabled" unless eval {require Crypt::PK::ECC; 1};
a31df49
+    plan tests => 121;
a31df49
+}
a31df49
 
a31df49
 use Crypt::PK::ECC qw(ecc_encrypt ecc_decrypt ecc_sign_message ecc_verify_message ecc_sign_hash ecc_verify_hash ecc_shared_secret);
a31df49
 
a31df49
diff --git a/t/pk_ecc_test_vectors_openssl.t b/t/pk_ecc_test_vectors_openssl.t
a31df49
index 9569c52..08de1bb 100644
a31df49
--- a/t/pk_ecc_test_vectors_openssl.t
a31df49
+++ b/t/pk_ecc_test_vectors_openssl.t
a31df49
@@ -1,7 +1,11 @@
a31df49
 use strict;
a31df49
 use warnings;
a31df49
 
a31df49
-use Test::More tests => 660;
a31df49
+use Test::More;
a31df49
+BEGIN {
a31df49
+    plan skip_all => "ECC disabled" unless eval {require Crypt::PK::ECC; 1};
a31df49
+    plan tests => 660;
a31df49
+}
a31df49
 use Crypt::PK::ECC;
a31df49
 
a31df49
 my $data = [
a31df49
diff --git a/t/pk_enc_pem.t b/t/pk_enc_pem.t
a31df49
index 1ba9c17..3e8fc82 100644
a31df49
--- a/t/pk_enc_pem.t
a31df49
+++ b/t/pk_enc_pem.t
a31df49
@@ -4,7 +4,6 @@ use Test::More tests => 27;
a31df49
 
a31df49
 use Crypt::PK::RSA;
a31df49
 use Crypt::PK::DSA;
a31df49
-use Crypt::PK::ECC;
a31df49
 
a31df49
 for my $f (qw/rsa-aes128.pem rsa-aes192.pem rsa-aes256.pem rsa-des.pem rsa-des3.pem rsa-seed.pem rsa-camellia128.pem rsa-camellia192.pem rsa-camellia256.pem/) {
a31df49
   my $pk = Crypt::PK::RSA->new("t/data/$f", 'secret');
a31df49
@@ -16,7 +15,10 @@ for my $f (qw/dsa-aes128.pem dsa-aes192.pem dsa-aes256.pem dsa-des.pem dsa-des3.
a31df49
   is($pk->is_private, 1, $f);
a31df49
 }
a31df49
 
a31df49
-for my $f (qw/ec-aes128.pem ec-aes192.pem ec-aes256.pem ec-camellia128.pem ec-camellia192.pem ec-camellia256.pem ec-des.pem ec-des3.pem ec-seed.pem/) {
a31df49
-  my $pk = Crypt::PK::ECC->new("t/data/$f", 'secret');
a31df49
-  is($pk->is_private, 1, $f);
a31df49
+SKIP: {
a31df49
+    skip "ECC disabled", 9 unless eval { require Crypt::PK::ECC; 1};
a31df49
+    for my $f (qw/ec-aes128.pem ec-aes192.pem ec-aes256.pem ec-camellia128.pem ec-camellia192.pem ec-camellia256.pem ec-des.pem ec-des3.pem ec-seed.pem/) {
a31df49
+      my $pk = Crypt::PK::ECC->new("t/data/$f", 'secret');
a31df49
+      is($pk->is_private, 1, $f);
a31df49
+    }
a31df49
 }
a31df49
diff --git a/t/pkcs8.t b/t/pkcs8.t
a31df49
index 96eaef3..103a17e 100644
a31df49
--- a/t/pkcs8.t
a31df49
+++ b/t/pkcs8.t
a31df49
@@ -3,7 +3,7 @@ use warnings;
a31df49
 use Test::More tests => 8;
a31df49
 
a31df49
 use Crypt::PK::RSA;
a31df49
-use Crypt::PK::ECC;
a31df49
+my $HAVE_ECC = eval { require Crypt::PK::ECC; 1 };
a31df49
 
a31df49
 ### generating test keys:
a31df49
 #
a31df49
@@ -27,9 +27,7 @@ use Crypt::PK::ECC;
a31df49
 #
a31df49
 
a31df49
 my $rsa = Crypt::PK::RSA->new;
a31df49
-my $ec  = Crypt::PK::ECC->new;
a31df49
 ok($rsa, "RSA new");
a31df49
-ok($ec,  "ECC new");
a31df49
 
a31df49
 for my $f (qw/pkcs8.rsa-priv-nopass.pem pkcs8.rsa-priv-nopass.der/) {
a31df49
   $rsa->import_key("t/data/$f");
a31df49
@@ -42,9 +40,15 @@ for my $f (qw/pkcs8.rsa-priv-nopass.pem pkcs8.rsa-priv-nopass.der/) {
a31df49
 ###   ok($rsa->is_private, "RSA is_private $f");
a31df49
 ### }
a31df49
 
a31df49
-for my $f (qw/pkcs8.ec-short-priv-nopass.der pkcs8.ec-short-priv-nopass.pem pkcs8.ec-priv-nopass.der pkcs8.ec-priv-nopass.pem/) {
a31df49
-  $ec->import_key("t/data/$f");
a31df49
-  ok($ec->is_private, "ECC is_private $f");
a31df49
+SKIP: {
a31df49
+    skip "ECC disabled", 5 unless $HAVE_ECC;
a31df49
+    my $ec  = Crypt::PK::ECC->new;
a31df49
+    ok($ec,  "ECC new");
a31df49
+
a31df49
+    for my $f (qw/pkcs8.ec-short-priv-nopass.der pkcs8.ec-short-priv-nopass.pem pkcs8.ec-priv-nopass.der pkcs8.ec-priv-nopass.pem/) {
a31df49
+      $ec->import_key("t/data/$f");
a31df49
+      ok($ec->is_private, "ECC is_private $f");
a31df49
+    }
a31df49
 }
a31df49
 
a31df49
 ### XXX-FIXME password protected pkcs8 private keys are not supported
a31df49
diff --git a/t/sshkey.t b/t/sshkey.t
a31df49
index ba374e1..c98d4ed 100644
a31df49
--- a/t/sshkey.t
a31df49
+++ b/t/sshkey.t
a31df49
@@ -3,15 +3,13 @@ use warnings;
a31df49
 use Test::More tests => 341;
a31df49
 
a31df49
 use Crypt::PK::RSA;
a31df49
-use Crypt::PK::ECC;
a31df49
+my $HAVE_ECC = eval { require Crypt::PK::ECC; 1 };
a31df49
 use Crypt::PK::DSA;
a31df49
 use Data::Dumper;
a31df49
 
a31df49
 my $rsa = Crypt::PK::RSA->new;
a31df49
-my $ec  = Crypt::PK::ECC->new;
a31df49
 my $dsa = Crypt::PK::DSA->new;
a31df49
 ok($rsa, "RSA new");
a31df49
-ok($ec,  "ECC new");
a31df49
 ok($dsa, "DSA new");
a31df49
 
a31df49
 my $dir = "t/data/ssh";
a31df49
@@ -174,15 +172,21 @@ sub _check_ecc {
a31df49
   }
a31df49
 }
a31df49
 
a31df49
-for my $f (qw/ssh_ecdsa_256 ssh_ecdsa_384 ssh_ecdsa_521/) {
a31df49
-  $ec->import_key("$dir/$f");
a31df49
-  _check_ecc($ec, $f, "private", 1);
a31df49
-  $ec->import_key("$dir/$f.pub.pkcs8");
a31df49
-  _check_ecc($ec, $f, "pub.pkcs8", 0);
a31df49
-  $ec->import_key("$dir/$f.pub");
a31df49
-  _check_ecc($ec, $f, "pub", 0);
a31df49
-  $ec->import_key("$dir/$f.pub.rfc4716");
a31df49
-  _check_ecc($ec, $f, "pub.rfc4716", 0);
a31df49
+SKIP: {
a31df49
+    skip "ECC disabled", 1+3*4*10+3 unless $HAVE_ECC;
a31df49
+
a31df49
+    my $ec  = Crypt::PK::ECC->new;
a31df49
+    ok($ec,  "ECC new");
a31df49
+    for my $f (qw/ssh_ecdsa_256 ssh_ecdsa_384 ssh_ecdsa_521/) {
a31df49
+      $ec->import_key("$dir/$f");
a31df49
+      _check_ecc($ec, $f, "private", 1);
a31df49
+      $ec->import_key("$dir/$f.pub.pkcs8");
a31df49
+      _check_ecc($ec, $f, "pub.pkcs8", 0);
a31df49
+      $ec->import_key("$dir/$f.pub");
a31df49
+      _check_ecc($ec, $f, "pub", 0);
a31df49
+      $ec->import_key("$dir/$f.pub.rfc4716");
a31df49
+      _check_ecc($ec, $f, "pub.rfc4716", 0);
a31df49
+    }
a31df49
 }
a31df49
 
a31df49
 sub _check_dsa {
a31df49
diff --git a/t/wycheproof.t b/t/wycheproof.t
a31df49
index 0782d03..e73221d 100644
a31df49
--- a/t/wycheproof.t
a31df49
+++ b/t/wycheproof.t
a31df49
@@ -137,7 +137,7 @@ if (0) {
a31df49
   # not ok 820 - type=ECDSAVer/SHA256 tcId=121 comment='Modified r or s, e.g. by adding or subtracting the order of the group' expected-result=invalid verify_message=1
a31df49
   # not ok 821 - type=ECDSAVer/SHA256 tcId=122 comment='Modified r or s, e.g. by adding or subtracting the order of the group' expected-result=invalid verify_message=1
a31df49
 
a31df49
-  use Crypt::PK::ECC;
a31df49
+  require Crypt::PK::ECC;
a31df49
 
a31df49
   my $tests = CryptX::_decode_json read_rawfile 't/wycheproof/ecdsa_test.json';
a31df49
   for my $g (@{$tests->{testGroups}}) {
a31df49
@@ -176,7 +176,7 @@ if (0) {
a31df49
 }
a31df49
 
a31df49
 if (0) {
a31df49
-  use Crypt::PK::ECC;
a31df49
+  require Crypt::PK::ECC;
a31df49
 
a31df49
   my $tests = CryptX::_decode_json read_rawfile 't/wycheproof/ecdsa_webcrypto_test.json';
a31df49
   for my $g (@{$tests->{testGroups}}) {
a31df49
@@ -217,31 +217,33 @@ if (0) {
a31df49
 }
a31df49
 
a31df49
 if (1) {
a31df49
-  use Crypt::PK::ECC;
a31df49
-
a31df49
-  my $tests = CryptX::_decode_json read_rawfile 't/wycheproof/ecdh_webcrypto_test.json';
a31df49
-  for my $g (@{$tests->{testGroups}}) {
a31df49
-    my $type   = $g->{type};
a31df49
-    for my $t (@{$g->{tests}}) {
a31df49
-      my $tcId    = $t->{tcId};
a31df49
-      my $comment = $t->{comment};
a31df49
-      my $name    = $t->{name};
a31df49
-      my $result  = $t->{result};
a31df49
-      my $shared  = pack "H*", $t->{shared};
a31df49
-      # do the test
a31df49
-      my $testname = "type=$type/$name tcId=$tcId comment='$comment' expected-result=$result";
a31df49
-      my $pub = Crypt::PK::ECC->new( $t->{public} );
a31df49
-      my $pri = Crypt::PK::ECC->new( $t->{private} );
a31df49
-      my $shared_hex = unpack "H*", $pri->shared_secret($pub);
a31df49
-      if ($result eq 'valid' || $result eq 'acceptable') {
a31df49
-        is($shared_hex, $t->{shared}, $testname);
a31df49
-      }
a31df49
-      elsif ($result eq 'invalid') {
a31df49
-        isnt($shared_hex, $t->{shared}, $testname);
a31df49
+    SKIP: {
a31df49
+      skip "ECC disable", 56 unless eval {require Crypt::PK::ECC; 1};
a31df49
+
a31df49
+      my $tests = CryptX::_decode_json read_rawfile 't/wycheproof/ecdh_webcrypto_test.json';
a31df49
+      for my $g (@{$tests->{testGroups}}) {
a31df49
+        my $type   = $g->{type};
a31df49
+        for my $t (@{$g->{tests}}) {
a31df49
+          my $tcId    = $t->{tcId};
a31df49
+          my $comment = $t->{comment};
a31df49
+          my $name    = $t->{name};
a31df49
+          my $result  = $t->{result};
a31df49
+          my $shared  = pack "H*", $t->{shared};
a31df49
+          # do the test
a31df49
+          my $testname = "type=$type/$name tcId=$tcId comment='$comment' expected-result=$result";
a31df49
+          my $pub = Crypt::PK::ECC->new( $t->{public} );
a31df49
+          my $pri = Crypt::PK::ECC->new( $t->{private} );
a31df49
+          my $shared_hex = unpack "H*", $pri->shared_secret($pub);
a31df49
+          if ($result eq 'valid' || $result eq 'acceptable') {
a31df49
+            is($shared_hex, $t->{shared}, $testname);
a31df49
+          }
a31df49
+          elsif ($result eq 'invalid') {
a31df49
+            isnt($shared_hex, $t->{shared}, $testname);
a31df49
+          }
a31df49
+          else {
a31df49
+            ok(0, "UNEXPECTED result=$result");
a31df49
+          }
a31df49
+        }
a31df49
       }
a31df49
-      else {
a31df49
-        ok(0, "UNEXPECTED result=$result");
a31df49
-      }
a31df49
-    }
a31df49
   }
a31df49
 }
a31df49
-- 
a31df49
2.16.1
a31df49