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   1896 use strict;
  5         12  
  5         119  
4 5     5   22 use warnings;
  5         9  
  5         118  
5              
6 5     5   1963 use Crypt::Perl::Ed25519::Math;
  5         13  
  5         147  
7 5     5   394 use Crypt::Perl::X;
  5         8  
  5         106  
8              
9 5     5   2222 use Digest::SHA ();
  5         11395  
  5         136  
10              
11 5     5   71 use parent qw( Crypt::Perl::KeyBase );
  5         46  
  5         30  
12              
13             use constant {
14 5         341 SIGN_BYTE_LENGTH => 64,
15             OID_Ed25519 => '1.3.101.112',
16 5     5   267 };
  5         14  
17              
18 5         227 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   28 >;
  5         10  
26              
27 5     5   52 use constant _JWK_THUMBPRINT_JSON_ORDER => qw( crv kty x );
  5         10  
  5         3170  
28              
29             sub to_der {
30 3     3 0 11 my ($self) = @_;
31              
32 3         22 require Crypt::Perl::ASN1;
33 3         18 my $asn1 = Crypt::Perl::ASN1->new()->prepare(
34             _ASN1_BASE() . $self->_ASN1()
35             )->find('FG_Key');
36              
37 3         63 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 74 my ($self) = @_;
56              
57 6         85 return $self->{'_public'};
58             }
59              
60             sub get_struct_for_public_jwk {
61 4     4 0 560 my ($self) = @_;
62              
63 4         721 require MIME::Base64;
64              
65             return {
66             kty => 'OKP',
67             crv => 'Ed25519',
68 4         804 x => MIME::Base64::encode_base64url($self->{'_public'}),
69             }
70             }
71              
72             sub verify {
73 21     21 0 13753 my ($self, $msg, $sig) = @_;
74              
75 21 50       101 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         80 my $public_ar = $self->{'_public_ar'};
80              
81 21         163 my $sig_ar = [ unpack 'C*', $sig ];
82              
83 21         164 my @sm = ( @$sig_ar, unpack( 'C*', $msg ) );
84 21         110 my @m = (0) x @sm;
85              
86 21         102 @m = @sm;
87              
88 21         28 @m[ 32 .. 63 ] = @{$public_ar};
  21         97  
89              
90 21         64 my @p = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         225  
91 21         56 my @q = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         162  
92              
93 21 50       103 if ( Crypt::Perl::Ed25519::Math::unpackneg( \@q, $public_ar ) ) {
94 0         0 return !1;
95             }
96              
97 21         528 my @h = unpack 'C*', Digest::SHA::sha512( pack 'C*', @m );
98 21         137 Crypt::Perl::Ed25519::Math::reduce(\@h);
99              
100 21         109 Crypt::Perl::Ed25519::Math::scalarmult(\@p, \@q, \@h);
101              
102 21         283 my @latter_sm = @sm[32 .. $#sm];
103 21         145 Crypt::Perl::Ed25519::Math::scalarbase( \@q, \@latter_sm );
104 21         262 @sm[32 .. $#sm] = @latter_sm;
105              
106 21         139 Crypt::Perl::Ed25519::Math::add( \@p, \@q );
107 21         77 my $t_ar = Crypt::Perl::Ed25519::Math::pack(\@p);
108              
109 21 100       118 if( Crypt::Perl::Ed25519::Math::crypto_verify_32(\@sm, 0, $t_ar, 0)) {
110 9         311 return !1;
111             }
112              
113 12         34 my $n = @sm - SIGN_BYTE_LENGTH;
114              
115 12         352 return $n >= 0;
116             }
117              
118             sub _verify_binary_key_part {
119 12 50   12   44 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         29 return;
124             }
125              
126             1;