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   2452 use strict;
  5         14  
  5         144  
4 5     5   25 use warnings;
  5         10  
  5         197  
5              
6 5     5   2501 use Crypt::Perl::Ed25519::Math;
  5         60  
  5         177  
7 5     5   425 use Crypt::Perl::X;
  5         11  
  5         124  
8              
9 5     5   2833 use Digest::SHA ();
  5         15839  
  5         179  
10              
11 5     5   60 use parent qw( Crypt::Perl::KeyBase );
  5         16  
  5         51  
12              
13             use constant {
14 5         372 SIGN_BYTE_LENGTH => 64,
15             OID_Ed25519 => '1.3.101.112',
16 5     5   301 };
  5         11  
17              
18 5         295 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   35 >;
  5         11  
26              
27 5     5   29 use constant _JWK_THUMBPRINT_JSON_ORDER => qw( crv kty x );
  5         10  
  5         3888  
28              
29             sub to_der {
30 3     3 0 10 my ($self) = @_;
31              
32 3         23 require Crypt::Perl::ASN1;
33 3         20 my $asn1 = Crypt::Perl::ASN1->new()->prepare(
34             _ASN1_BASE() . $self->_ASN1()
35             )->find('FG_Key');
36              
37 3         83 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 79 my ($self) = @_;
56              
57 6         92 return $self->{'_public'};
58             }
59              
60             sub get_struct_for_public_jwk {
61 4     4 0 575 my ($self) = @_;
62              
63 4         907 require MIME::Base64;
64              
65             return {
66             kty => 'OKP',
67             crv => 'Ed25519',
68 4         889 x => MIME::Base64::encode_base64url($self->{'_public'}),
69             }
70             }
71              
72             sub verify {
73 21     21 0 14876 my ($self, $msg, $sig) = @_;
74              
75 21 50       106 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         79 my $public_ar = $self->{'_public_ar'};
80              
81 21         199 my $sig_ar = [ unpack 'C*', $sig ];
82              
83 21         177 my @sm = ( @$sig_ar, unpack( 'C*', $msg ) );
84 21         124 my @m = (0) x @sm;
85              
86 21         120 @m = @sm;
87              
88 21         35 @m[ 32 .. 63 ] = @{$public_ar};
  21         106  
89              
90 21         76 my @p = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         269  
91 21         70 my @q = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         213  
92              
93 21 50       102 if ( Crypt::Perl::Ed25519::Math::unpackneg( \@q, $public_ar ) ) {
94 0         0 return !1;
95             }
96              
97 21         573 my @h = unpack 'C*', Digest::SHA::sha512( pack 'C*', @m );
98 21         174 Crypt::Perl::Ed25519::Math::reduce(\@h);
99              
100 21         162 Crypt::Perl::Ed25519::Math::scalarmult(\@p, \@q, \@h);
101              
102 21         416 my @latter_sm = @sm[32 .. $#sm];
103 21         195 Crypt::Perl::Ed25519::Math::scalarbase( \@q, \@latter_sm );
104 21         293 @sm[32 .. $#sm] = @latter_sm;
105              
106 21         170 Crypt::Perl::Ed25519::Math::add( \@p, \@q );
107 21         151 my $t_ar = Crypt::Perl::Ed25519::Math::pack(\@p);
108              
109 21 100       147 if( Crypt::Perl::Ed25519::Math::crypto_verify_32(\@sm, 0, $t_ar, 0)) {
110 9         359 return !1;
111             }
112              
113 12         35 my $n = @sm - SIGN_BYTE_LENGTH;
114              
115 12         388 return $n >= 0;
116             }
117              
118             sub _verify_binary_key_part {
119 13 50   13   48 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 13         30 return;
124             }
125              
126             1;