File Coverage

lib/Crypt/Perl/RSA/KeyBase.pm
Criterion Covered Total %
statement 77 80 96.2
branch 3 4 75.0
condition n/a
subroutine 24 25 96.0
pod 1 11 9.0
total 105 120 87.5


line stmt bran cond sub pod time code
1             package Crypt::Perl::RSA::KeyBase;
2              
3 7     7   3538 use strict;
  7         37  
  7         191  
4 7     7   36 use warnings;
  7         16  
  7         192  
5              
6 7         72 use parent qw(
7             Class::Accessor::Fast
8             Crypt::Perl::KeyBase
9 7     7   32 );
  7         21  
10              
11 7     7   10590 use Crypt::Format ();
  7         18  
  7         100  
12 7     7   34 use Module::Load ();
  7         13  
  7         96  
13              
14 7     7   32 use Crypt::Perl::BigInt ();
  7         16  
  7         80  
15 7     7   33 use Crypt::Perl::X ();
  7         14  
  7         410  
16              
17             BEGIN {
18 7     7   75 __PACKAGE__->mk_ro_accessors('modulus');
19 7         1631 __PACKAGE__->mk_ro_accessors('publicExponent');
20              
21 7         1305 *N = \&modulus;
22 7         214 *E = \&publicExponent;
23             }
24              
25 7     7   46 use constant _JWK_THUMBPRINT_JSON_ORDER => qw( e kty n );
  7         17  
  7         3934  
26              
27             sub new {
28 290     290 1 25344 my ($class, @args) = @_;
29              
30 290         2184 my $self = $class->SUPER::new(@args);
31              
32 290         5381 $self->{'publicExponent'} = Crypt::Perl::BigInt->new( $self->{'publicExponent'} );
33              
34 290         12376 return $self;
35             }
36              
37             sub to_pem {
38 1     1 0 3 my ($self) = @_;
39              
40 1         2 return Crypt::Format::der2pem( $self->to_der(), $self->_PEM_HEADER() );
41             }
42              
43             #i.e., modulus length, in bits
44             sub size {
45 0     0 0 0 my ($self) = @_;
46              
47 0         0 return length( $self->modulus()->as_bin() ) - 2;
48             }
49              
50             sub modulus_byte_length {
51 1317     1317 0 3234 my ($self) = @_;
52              
53 1317         35047 return length $self->N()->as_bytes();
54              
55             #return( ( length( $self->N()->as_hex() ) - 2 ) / 2 );
56             }
57              
58             sub verify_RS256 {
59 777     777 0 251076 my ($self, $msg, $sig) = @_;
60              
61 777         3852 return $self->_verify($msg, $sig, 'Digest::SHA', 'sha256', 'PKCS1_v1_5');
62             }
63              
64             sub verify_RS384 {
65 2     2 0 31 my ($self, $msg, $sig) = @_;
66              
67 2         12 return $self->_verify($msg, $sig, 'Digest::SHA', 'sha384', 'PKCS1_v1_5');
68             }
69              
70             sub verify_RS512 {
71 2     2 0 29 my ($self, $msg, $sig) = @_;
72              
73 2         14 return $self->_verify($msg, $sig, 'Digest::SHA', 'sha512', 'PKCS1_v1_5');
74             }
75              
76             sub encrypt_raw {
77 1     1 0 14 my ($self, $bytes) = @_;
78              
79 1         7 return Crypt::Perl::BigInt->from_bytes($bytes)->bmodpow($self->{'publicExponent'}, $self->{'modulus'})->as_bytes();
80             }
81              
82             sub to_der {
83 6     6 0 42 my ($self) = @_;
84              
85 6         42 return $self->_to_der($self->_ASN1_MACRO());
86             }
87              
88             sub algorithm_identifier {
89 5     5 0 17 my ($self) = @_;
90              
91             return {
92 5         31 algorithm => OID_rsaEncryption(),
93             parameters => Crypt::Perl::ASN1::NULL(),
94             };
95             }
96              
97 7     7   67 use constant OID_rsaEncryption => '1.2.840.113549.1.1.1';
  7         25  
  7         3507  
98              
99             sub _to_subject_public_der {
100 5     5   19 my ($self) = @_;
101              
102 5         42 my $asn1 = $self->_asn1_find('SubjectPublicKeyInfo');
103              
104 5         123 return $asn1->encode( {
105             algorithm => $self->algorithm_identifier(),
106             subjectPublicKey => $self->_to_der('RSAPublicKey'),
107             } );
108             }
109              
110             sub get_struct_for_public_jwk {
111 4     4 0 14 my ($self) = @_;
112              
113 4         20 require MIME::Base64;
114              
115             return {
116 4         113 kty => 'RSA',
117             n => MIME::Base64::encode_base64url($self->N()->as_bytes()),
118             e => MIME::Base64::encode_base64url($self->E()->as_bytes()),
119             }
120             }
121              
122             #----------------------------------------------------------------------
123              
124             sub _asn1_find {
125 16     16   55 my ($self, $macro) = @_;
126              
127 16         103 require Crypt::Perl::ASN1;
128 16         62 require Crypt::Perl::RSA::Template;
129 16         74 my $asn1 = Crypt::Perl::ASN1->new()->prepare(
130             Crypt::Perl::RSA::Template::get_template('INTEGER'),
131             );
132              
133 16         96 $asn1->find($macro);
134             }
135              
136             sub _to_der {
137 11     11   269 my ($self, $macro) = @_;
138              
139 11         49 return $self->_asn1_find($macro)->encode( { %$self } );
140             }
141              
142             sub _verify {
143 781     781   2803 my ($self, $message, $signature, $hash_module, $hasher, $scheme) = @_;
144              
145 781         3908 Module::Load::load($hash_module);
146              
147 781         90898 my $digest = $hash_module->can($hasher)->($message);
148              
149 781         5329 my $y = Crypt::Perl::BigInt->from_hex( unpack 'H*', $signature );
150              
151             #This modifies $y, but it doesn’t matter here.
152 781         2131111 my $x = $y->bmodpow( $self->E(), $self->N() );
153              
154             #Math::BigInt will strip off the leading zero that PKCS1_v1_5 requires,
155             #so let’s put it back first of all.
156 781         21048734 my $octets = "\0" . $x->as_bytes();
157              
158             #printf "OCTETS - %v02x\n", $octets;
159              
160 781 50       3131 if ($scheme eq 'PKCS1_v1_5') {
161 781         3445 my $key_bytes_length = $self->modulus_byte_length();
162 781 100       3277 if (length($octets) != $key_bytes_length) {
163 203         1569 my $err = sprintf( "Invalid PKCS1_v1_5 length: %d (should be %d)", length($octets), $key_bytes_length );
164 203         1296 die Crypt::Perl::X::create('Generic', $err);
165             }
166              
167 578         4966 require Crypt::Perl::RSA::PKCS1_v1_5;
168 578         3653 return $digest eq Crypt::Perl::RSA::PKCS1_v1_5::decode($octets, $hasher);
169             }
170              
171 0           die Crypt::Perl::X::create('Generic', "Unknown signature scheme: “$scheme”");
172             }
173              
174             1;