Package list libcryptx-perl / 4830e8e
Work on PK::Ed25519 manuel 1 year, 9 months ago
5 changed file(s) with 170 addition(s) and 12 deletion(s). Raw diff Collapse all Expand all
124124 key2hash(Crypt::PK::Ed25519 self)
125125 PREINIT:
126126 HV *rv_hash;
127 char buf[256];
127 char buf[32 * 2 + 1];
128128 unsigned long blen;
129129 SV **not_used;
130130 int rv;
163163
164164 RETVAL = newSVpvn(NULL, 0); /* undef */
165165 if (strnEQ(type, "private", 7)) {
166 rv = ed25519_export(out, &out_len, PK_PRIVATE|PK_STD, &self->key);
167 if (rv != CRYPT_OK) croak("FATAL: ed25519_export(PK_PRIVATE|PK_STD) failed: %s", error_to_string(rv));
168 RETVAL = newSVpvn((char*)out, out_len);
169 }
170 else if (strnEQ(type, "public", 6)) {
171 rv = ed25519_export(out, &out_len, PK_PUBLIC|PK_STD, &self->key);
172 if (rv != CRYPT_OK) croak("FATAL: ed25519_export(PK_PUBLIC|PK_STD) failed: %s", error_to_string(rv));
173 RETVAL = newSVpvn((char*)out, out_len);
174 }
175 else {
176 croak("FATAL: export_key_der invalid type '%s'", type);
177 }
178 }
179 OUTPUT:
180 RETVAL
181
182 SV*
183 export_key_raw(Crypt::PK::Ed25519 self, char * type)
184 CODE:
185 {
186 int rv;
187 unsigned char out[4096];
188 unsigned long int out_len = sizeof(out);
189
190 RETVAL = newSVpvn(NULL, 0); /* undef */
191 if (strnEQ(type, "private", 7)) {
166192 rv = ed25519_export(out, &out_len, PK_PRIVATE, &self->key);
167193 if (rv != CRYPT_OK) croak("FATAL: ed25519_export(PK_PRIVATE) failed: %s", error_to_string(rv));
168194 RETVAL = newSVpvn((char*)out, out_len);
173199 RETVAL = newSVpvn((char*)out, out_len);
174200 }
175201 else {
176 croak("FATAL: export_key_der invalid type '%s'", type);
202 croak("FATAL: export_key_raw invalid type '%s'", type);
177203 }
178204 }
179205 OUTPUT:
124124 key2hash(Crypt::PK::X25519 self)
125125 PREINIT:
126126 HV *rv_hash;
127 char buf[256];
127 char buf[32 * 2 + 1];
128128 unsigned long blen;
129129 SV **not_used;
130130 int rv;
168168 RETVAL = newSVpvn((char*)out, out_len);
169169 }
170170 else if (strnEQ(type, "public", 6)) {
171 rv = x25519_export(out, &out_len, PK_PUBLIC, &self->key);
172 if (rv != CRYPT_OK) croak("FATAL: x25519_export(PK_PUBLIC) failed: %s", error_to_string(rv));
171 rv = x25519_export(out, &out_len, PK_PUBLIC|PK_STD, &self->key);
172 if (rv != CRYPT_OK) croak("FATAL: x25519_export(PK_PUBLIC|PK_STD) failed: %s", error_to_string(rv));
173173 RETVAL = newSVpvn((char*)out, out_len);
174174 }
175175 else {
2222 sub import_key_raw {
2323 my ($self, $key, $type) = @_;
2424 croak "FATAL: undefined key" unless $key;
25 croak "FATAL: invalid key" unless length($key) == 32;
2526 croak "FATAL: undefined type" unless $type;
2627 return $self->_import_raw($key, 1) if $type eq 'private';
2728 return $self->_import_raw($key, 0) if $type eq 'public';
9495 # https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD
9596 croak "FATAL: OPENSSH PRIVATE KEY not supported";
9697 }
98 elsif ($data =~ /---- BEGIN SSH2 PUBLIC KEY ----(.*?)---- END SSH2 PUBLIC KEY ----/sg) {
99 $data = pem_to_der($data);
100 my ($typ, $pubkey) = Crypt::PK::_ssh_parse($data);
101 return $self->_import_raw($pubkey, 0) if $typ eq 'ssh-ed25519' && length($pubkey) == 32;
102 }
97103 elsif ($data =~ /(ssh-ed25519)\s+(\S+)/) {
98104 $data = decode_b64("$2");
99105 my ($typ, $pubkey) = Crypt::PK::_ssh_parse($data);
149155
150156 =head2 generate_key
151157
158 Uses Yarrow-based cryptographically strong random number generator seeded with
159 random data taken from C</dev/random> (UNIX) or C<CryptGenRandom> (Win32).
160
161 $pk->generate_key;
162
152163 =head2 import_key
153164
165 TODO
166
154167 =head2 import_key_raw
155168
169 Import raw public/private key - can load raw key data exported by L</export_key_raw>.
170
171 $pk->import_key_raw($key, 'public');
172 $pk->import_key_raw($key, 'private');
173
156174 =head2 export_key_der
157175
176 my $private_der = $pk->export_key_der('private');
177 #or
178 my $public_der = $pk->export_key_der('public');
179
158180 =head2 export_key_pem
159181
182 my $private_pem = $pk->export_key_pem('private');
183 #or
184 my $public_pem = $pk->export_key_pem('public');
185
160186 =head2 export_key_jwk
161187
188 Exports public/private keys as a JSON Web Key (JWK).
189
190 my $private_json_text = $pk->export_key_jwk('private');
191 #or
192 my $public_json_text = $pk->export_key_jwk('public');
193
194 Also exports public/private keys as a perl HASH with JWK structure.
195
196 my $jwk_hash = $pk->export_key_jwk('private', 1);
197 #or
198 my $jwk_hash = $pk->export_key_jwk('public', 1);
199
200 B<BEWARE:> For JWK support you need to have L<JSON::PP>, L<JSON::XS> or L<Cpanel::JSON::XS> module.
201
162202 =head2 export_key_raw
163203
204 Export raw public/private key
205
206 my $private_pem = $pk->export_key_raw('private');
207 #or
208 my $public_pem = $pk->export_key_raw('public');
209
164210 =head2 sign_message
165211
212 my $signature = $priv->sign_message($message);
213 #or
214 my $signature = $priv->sign_message($message, $hash_name);
215
216 #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
217
166218 =head2 verify_message
167219
220 my $valid = $pub->verify_message($signature, $message)
221 #or
222 my $valid = $pub->verify_message($signature, $message, $hash_name);
223
224 #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
225
168226 =head2 is_private
169227
228 my $rv = $pk->is_private;
229 # 1 .. private key loaded
230 # 0 .. public key loaded
231 # undef .. no key loaded
232
170233 =head2 key2hash
171234
235 my $hash = $pk->key2hash;
236
237 # returns hash like this (or undef if no key loaded):
238 {
239 curve => "ed25519",
240 # raw public key as a hexadecimal string
241 pub => "A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D",
242 # raw private key as a hexadecimal string. undef if key is public only
243 priv => "45C109BA6FD24E8B67D23EFB6B92D99CD457E2137172C0D749FE2B5A0C142DAD",
244 }
245
172246 =head1 SEE ALSO
173247
174248 =over
0 ---- BEGIN SSH2 PUBLIC KEY ----
1 Comment: "256-bit ED25519, converted by foo@bar from OpenSSH"
2 AAAAC3NzaC1lZDI1NTE5AAAAIL0XsiFcRDp6Hpsoak8OdiiBMJhM2UKszNTxoGS7dJ++
3 ---- END SSH2 PUBLIC KEY ----
00 use strict;
11 use warnings;
2 use Test::More tests => 55;
2 use Test::More tests => 74;
33
44 use Crypt::PK::Ed25519;
5 use Crypt::Misc qw(read_rawfile);
56
67 {
78 my $k;
1112 # priv = 45C109BA6FD24E8B67D23EFB6B92D99CD457E2137172C0D749FE2B5A0C142DAD == RcEJum_STotn0j77a5LZnNRX4hNxcsDXSf4rWgwULa0
1213 # pub = A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D == oF0a6lgwrJplzfs4RmDUl-NpfEa0Gc8s7IXei9JFRZ0
1314
14 $k = Crypt::PK::Ed25519->new->import_key_raw(pack("H*", "45C109BA6FD24E8B67D23EFB6B92D99CD457E2137172C0D749FE2B5A0C142DAD"), 'private');
15 my $sk_data = pack("H*", "45C109BA6FD24E8B67D23EFB6B92D99CD457E2137172C0D749FE2B5A0C142DAD");
16 $k = Crypt::PK::Ed25519->new->import_key_raw($sk_data, 'private');
1517 ok($k, 'new+import_key_raw raw-priv');
1618 ok($k->is_private, 'is_private raw-priv');
1719 is(uc($k->key2hash->{priv}), '45C109BA6FD24E8B67D23EFB6B92D99CD457E2137172C0D749FE2B5A0C142DAD', 'key2hash->{priv} raw-priv');
1820 is(uc($k->key2hash->{pub}), 'A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D', 'key2hash->{pub} raw-priv');
21 is($k->export_key_raw('private'), $sk_data, 'export_key_raw private');
1922
20 $k = Crypt::PK::Ed25519->new->import_key_raw(pack("H*", "A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D"), 'public');
23 my $pk_data = pack("H*", "A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D");
24 $k = Crypt::PK::Ed25519->new->import_key_raw($pk_data, 'public');
2125 ok($k, 'new+import_key_raw raw-pub');
2226 ok(!$k->is_private, '!is_private raw-pub');
2327 is(uc($k->key2hash->{pub}), 'A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D', 'key2hash->{pub} raw-pub');
28 is($k->export_key_raw('public'), $pk_data, 'export_key_raw public');
2429
25 $k = Crypt::PK::Ed25519->new({ kty=>"OKP",crv=>"Ed25519",d=>"RcEJum_STotn0j77a5LZnNRX4hNxcsDXSf4rWgwULa0",x=>"oF0a6lgwrJplzfs4RmDUl-NpfEa0Gc8s7IXei9JFRZ0"});
30 my $sk_jwk = { kty=>"OKP",crv=>"Ed25519",d=>"RcEJum_STotn0j77a5LZnNRX4hNxcsDXSf4rWgwULa0",x=>"oF0a6lgwrJplzfs4RmDUl-NpfEa0Gc8s7IXei9JFRZ0" };
31 $k = Crypt::PK::Ed25519->new($sk_jwk);
2632 ok($k, 'new JWKHASH/priv');
2733 ok($k->is_private, 'is_private JWKHASH/priv');
2834 is(uc($k->key2hash->{priv}), '45C109BA6FD24E8B67D23EFB6B92D99CD457E2137172C0D749FE2B5A0C142DAD', 'key2hash->{priv} JWKHASH/priv');
35 ok(eq_hash($sk_jwk, $k->export_key_jwk('private', 1)), 'JWKHASH export private');
2936
30 $k = Crypt::PK::Ed25519->new({ kty=>"OKP",crv=>"Ed25519",x=>"oF0a6lgwrJplzfs4RmDUl-NpfEa0Gc8s7IXei9JFRZ0"});
37 my $pk_jwk = { kty=>"OKP",crv=>"Ed25519",x=>"oF0a6lgwrJplzfs4RmDUl-NpfEa0Gc8s7IXei9JFRZ0" };
38 $k = Crypt::PK::Ed25519->new($pk_jwk);
3139 ok($k, 'new JWKHASH/pub');
3240 ok(!$k->is_private, '!is_private JWKHASH/pub');
3341 is(uc($k->key2hash->{pub}), 'A05D1AEA5830AC9A65CDFB384660D497E3697C46B419CF2CEC85DE8BD245459D', 'key2hash->{pub} JWKHASH/pub');
42 ok(eq_hash($pk_jwk, $k->export_key_jwk('public', 1)), 'JWKHASH export public');
3443
3544 $k = Crypt::PK::Ed25519->new('t/data/jwk_ed25519-priv1.json');
3645 ok($k, 'new JWK/priv');
102111 ok(!$k->is_private, '!is_private ssh_ed25519.pub');
103112 is(uc($k->key2hash->{pub}), 'BD17B2215C443A7A1E9B286A4F0E76288130984CD942ACCCD4F1A064BB749FBE', 'key2hash->{pub} ssh_ed25519.pub');
104113
114 $k = Crypt::PK::Ed25519->new('t/data/ssh/ssh_ed25519.pub.rfc4716');
115 ok($k, 'new ssh_ed25519.pub.rfc4716');
116 ok(!$k->is_private, '!is_private ssh_ed25519.pub.rfc4716');
117 is(uc($k->key2hash->{pub}), 'BD17B2215C443A7A1E9B286A4F0E76288130984CD942ACCCD4F1A064BB749FBE', 'key2hash->{pub} ssh_ed25519.pub.rfc4716');
118
105119 ### $k = Crypt::PK::Ed25519->new('t/data/ssh/ssh_ed25519.priv');
106120 ### ok($k, 'new ssh_ed25519.priv');
107 ### ok($k->is_private, 'is_private ssh_ed25519.priv');
108 ###
121 ## ok($k->is_private, 'is_private ssh_ed25519.priv');
122
109123 ### $k = Crypt::PK::Ed25519->new('t/data/ssh/ssh_ed25519_pw.priv', 'secret');
110124 ### ok($k, 'new ssh_ed25519_pw.priv');
111125 ### ok($k->is_private, 'is_private ssh_ed25519_pw.priv');
112126 }
127
128 {
129 my $k = Crypt::PK::Ed25519->new;
130 $k->generate_key;
131 ok($k, 'generate_key');
132 ok($k->is_private, 'is_private');
133 ok($k->export_key_der('private'), 'export_key_der pri');
134 ok($k->export_key_der('public'), 'export_key_der pub');
135 }
136
137 {
138 for (qw( openssl_ed25519_pk.der openssl_ed25519_pk.pem )) {
139 my $k = Crypt::PK::Ed25519->new("t/data/$_");
140 is($k->export_key_der('public'), read_rawfile("t/data/$_"), 'export_key_der public') if (substr($_, -3) eq "der");
141 is($k->export_key_pem('public'), read_rawfile("t/data/$_"), 'export_key_pem public') if (substr($_, -3) eq "pem");
142 }
143
144 for (qw( openssl_ed25519_sk.der openssl_ed25519_sk_t.pem )) {
145 my $k = Crypt::PK::Ed25519->new("t/data/$_");
146 is($k->export_key_der('private'), read_rawfile("t/data/$_"), 'export_key_der private') if (substr($_, -3) eq "der");
147 is($k->export_key_pem('private'), read_rawfile("t/data/$_"), 'export_key_pem private') if (substr($_, -3) eq "pem");
148 }
149 }
150
151 {
152 my $sk = Crypt::PK::Ed25519->new;
153 $sk->import_key('t/data/openssl_ed25519_sk.der');
154 my $pk = Crypt::PK::Ed25519->new;
155 $pk->import_key('t/data/openssl_ed25519_pk.der');
156
157 my $sig = $sk->sign_message("message");
158 ok(length $sig > 60, 'sign_message ' . length($sig));
159 ok($pk->verify_message($sig, "message"), 'verify_message');
160
161 my $hash = pack("H*","04624fae618e9ad0c5e479f62e1420c71fff34dd");
162 $sig = $sk->sign_hash($hash, 'SHA1');
163 ok(length $sig > 60, 'sign_hash ' . length($sig));
164 ok($pk->verify_hash($sig, $hash, 'SHA1'), 'verify_hash');
165 }
166