File Coverage

blib/lib/Crypt/Perl/Ed25519/KeyBase.pm
Criterion Covered Total %
statement 64 70 91.4
branch 5 8 62.5
condition n/a
subroutine 14 15 93.3
pod 0 5 0.0
total 83 98 84.6


line stmt bran cond sub pod time code
1             package Crypt::Perl::Ed25519::KeyBase;
2              
3 5     5   1985 use strict;
  5         10  
  5         118  
4 5     5   22 use warnings;
  5         7  
  5         115  
5              
6 5     5   1880 use Crypt::Perl::Ed25519::Math;
  5         13  
  5         178  
7 5     5   346 use Crypt::Perl::X;
  5         10  
  5         103  
8              
9 5     5   2274 use Digest::SHA ();
  5         11467  
  5         142  
10              
11 5     5   31 use parent qw( Crypt::Perl::KeyBase );
  5         24  
  5         31  
12              
13             use constant {
14 5         344 SIGN_BYTE_LENGTH => 64,
15             OID_Ed25519 => '1.3.101.112',
16 5     5   264 };
  5         9  
17              
18 5         240 use constant _ASN1_BASE => q<
19             -- cf. RFC 3280 4.1.1.2
20             -- XXX COPIED FROM RSA TEMPLATE MODULE
21             AlgorithmIdentifier ::= SEQUENCE {
22             algorithm OBJECT IDENTIFIER,
23             parameters ANY DEFINED BY algorithm OPTIONAL
24             }
25 5     5   57 >;
  5         9  
26              
27 5     5   26 use constant _JWK_THUMBPRINT_JSON_ORDER => qw( crv kty x );
  5         9  
  5         2961  
28              
29             sub to_der {
30 3     3 0 10 my ($self) = @_;
31              
32 3         23 require Crypt::Perl::ASN1;
33 3         17 my $asn1 = Crypt::Perl::ASN1->new()->prepare(
34             _ASN1_BASE() . $self->_ASN1()
35             )->find('FG_Key');
36              
37 3         62 return $asn1->encode( {
38             version => 0,
39             algorithmIdentifier => {
40             algorithm => OID_Ed25519(),
41             },
42             $self->_to_der_args(),
43             } );
44             }
45              
46             # TODO: refactor; duplicated w/ RSA
47             sub to_pem {
48 0     0 0 0 my ($self) = @_;
49              
50 0         0 require Crypt::Format;
51 0         0 return Crypt::Format::der2pem( $self->to_der(), $self->_PEM_HEADER() );
52             }
53              
54             sub get_public {
55 6     6 0 60 my ($self) = @_;
56              
57 6         71 return $self->{'_public'};
58             }
59              
60             sub get_struct_for_public_jwk {
61 4     4 0 453 my ($self) = @_;
62              
63 4         602 require MIME::Base64;
64              
65             return {
66             kty => 'OKP',
67             crv => 'Ed25519',
68 4         713 x => MIME::Base64::encode_base64url($self->{'_public'}),
69             }
70             }
71              
72             sub verify {
73 21     21 0 11369 my ($self, $msg, $sig) = @_;
74              
75 21 50       66 if (SIGN_BYTE_LENGTH() != length $sig) {
76 0         0 die Crypt::Perl::X::create('Generic', sprintf('Invalid length (%d) of Ed25519 signature: %v.02x', length($sig), $sig));
77             }
78              
79 21         57 my $public_ar = $self->{'_public_ar'};
80              
81 21         144 my $sig_ar = [ unpack 'C*', $sig ];
82              
83 21         139 my @sm = ( @$sig_ar, unpack( 'C*', $msg ) );
84 21         94 my @m = (0) x @sm;
85              
86 21         94 @m = @sm;
87              
88 21         29 @m[ 32 .. 63 ] = @{$public_ar};
  21         76  
89              
90 21         54 my @p = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         233  
91 21         48 my @q = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         155  
92              
93 21 50       86 if ( Crypt::Perl::Ed25519::Math::unpackneg( \@q, $public_ar ) ) {
94 0         0 return !1;
95             }
96              
97 21         441 my @h = unpack 'C*', Digest::SHA::sha512( pack 'C*', @m );
98 21         118 Crypt::Perl::Ed25519::Math::reduce(\@h);
99              
100 21         108 Crypt::Perl::Ed25519::Math::scalarmult(\@p, \@q, \@h);
101              
102 21         297 my @latter_sm = @sm[32 .. $#sm];
103 21         132 Crypt::Perl::Ed25519::Math::scalarbase( \@q, \@latter_sm );
104 21         209 @sm[32 .. $#sm] = @latter_sm;
105              
106 21         106 Crypt::Perl::Ed25519::Math::add( \@p, \@q );
107 21         76 my $t_ar = Crypt::Perl::Ed25519::Math::pack(\@p);
108              
109 21 100       107 if( Crypt::Perl::Ed25519::Math::crypto_verify_32(\@sm, 0, $t_ar, 0)) {
110 9         226 return !1;
111             }
112              
113 12         36 my $n = @sm - SIGN_BYTE_LENGTH;
114              
115 12         292 return $n >= 0;
116             }
117              
118             sub _verify_binary_key_part {
119 12 50   12   40 if (32 != length $_[1]) {
120 0         0 die Crypt::Perl::X::create('Generic', sprintf('Invalid length (%d) of Ed25519 key piece: %v.02x', length($_[1]), $_[1]));
121             }
122              
123 12         22 return;
124             }
125              
126             1;