File Coverage

blib/lib/Crypt/Perl/Ed25519/KeyBase.pm
Criterion Covered Total %
statement 58 62 93.5
branch 3 4 75.0
condition n/a
subroutine 12 13 92.3
pod 0 5 0.0
total 73 84 86.9


line stmt bran cond sub pod time code
1             package Crypt::Perl::Ed25519::KeyBase;
2              
3 2     2   708 use strict;
  2         3  
  2         42  
4 2     2   7 use warnings;
  2         3  
  2         35  
5              
6 2     2   694 use Crypt::Perl::Ed25519::Math;
  2         5  
  2         49  
7              
8 2     2   849 use Digest::SHA ();
  2         4181  
  2         45  
9              
10 2     2   36 use parent qw( Crypt::Perl::KeyBase );
  2         3  
  2         13  
11              
12             use constant {
13 2         126 SIGN_BYTE_LENGTH => 64,
14             OID_Ed25519 => '1.3.101.112',
15 2     2   77 };
  2         3  
16              
17 2         70 use constant _ASN1_BASE => q<
18             -- cf. RFC 3280 4.1.1.2
19             -- XXX COPIED FROM RSA TEMPLATE MODULE
20             AlgorithmIdentifier ::= SEQUENCE {
21             algorithm OBJECT IDENTIFIER,
22             parameters ANY DEFINED BY algorithm OPTIONAL
23             }
24 2     2   9 >;
  2         3  
25              
26 2     2   15 use constant _JWK_THUMBPRINT_JSON_ORDER => qw( crv kty x );
  2         3  
  2         899  
27              
28             sub to_der {
29 2     2 0 5 my ($self) = @_;
30              
31 2         28 require Crypt::Perl::ASN1;
32 2         13 my $asn1 = Crypt::Perl::ASN1->new()->prepare(
33             _ASN1_BASE() . $self->_ASN1()
34             )->find('FG_Key');
35              
36 2         35 return $asn1->encode( {
37             version => 0,
38             algorithmIdentifier => {
39             algorithm => OID_Ed25519(),
40             },
41             $self->_to_der_args(),
42             } );
43             }
44              
45             # TODO: refactor; duplicated w/ RSA
46             sub to_pem {
47 0     0 0 0 my ($self) = @_;
48              
49 0         0 require Crypt::Format;
50 0         0 return Crypt::Format::der2pem( $self->to_der(), $self->_PEM_HEADER() );
51             }
52              
53             sub get_public {
54 6     6 0 68 my ($self) = @_;
55              
56 6         68 return $self->{'_public'};
57             }
58              
59             sub get_struct_for_public_jwk {
60 4     4 0 467 my ($self) = @_;
61              
62 4         634 require MIME::Base64;
63              
64             return {
65             kty => 'OKP',
66             crv => 'Ed25519',
67 4         714 x => MIME::Base64::encode_base64url($self->{'_public'}),
68             }
69             }
70              
71             sub verify {
72 21     21 0 11107 my ($self, $msg, $sig) = @_;
73              
74 21         80 my $public_ar = $self->{'_public_ar'};
75              
76 21         148 my $sig_ar = [ unpack 'C*', $sig ];
77              
78 21         144 my @sm = ( @$sig_ar, unpack( 'C*', $msg ) );
79 21         132 my @m = (0) x @sm;
80              
81 21         109 @m = @sm;
82              
83 21         42 @m[ 32 .. 63 ] = @{$public_ar};
  21         96  
84              
85 21         74 my @p = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         208  
86 21         52 my @q = map { [ Crypt::Perl::Ed25519::Math::gf0() ] } 1 .. 4;
  84         162  
87              
88 21 50       108 if ( Crypt::Perl::Ed25519::Math::unpackneg( \@q, $public_ar ) ) {
89 0         0 return !1;
90             }
91              
92 21         525 my @h = unpack 'C*', Digest::SHA::sha512( pack 'C*', @m );
93 21         127 Crypt::Perl::Ed25519::Math::reduce(\@h);
94              
95 21         105 Crypt::Perl::Ed25519::Math::scalarmult(\@p, \@q, \@h);
96              
97 21         287 my @latter_sm = @sm[32 .. $#sm];
98 21         160 Crypt::Perl::Ed25519::Math::scalarbase( \@q, \@latter_sm );
99 21         268 @sm[32 .. $#sm] = @latter_sm;
100              
101 21         135 Crypt::Perl::Ed25519::Math::add( \@p, \@q );
102 21         99 my $t_ar = Crypt::Perl::Ed25519::Math::pack(\@p);
103              
104 21 100       154 if( Crypt::Perl::Ed25519::Math::crypto_verify_32(\@sm, 0, $t_ar, 0)) {
105 9         280 return !1;
106             }
107              
108 12         32 my $n = @sm - SIGN_BYTE_LENGTH;
109              
110 12         334 return $n >= 0;
111             }
112              
113             1;