rsa-key.t
1 #! /usr/bin/env perl 2 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # See the NOTICE file distributed with this work for additional 6 # information regarding copyright ownership. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 use strict; 18 use warnings; 19 20 use feature qw(fc); 21 use FindBin; 22 use lib "$FindBin::Bin"; 23 use driver; 24 use parsers qw(parse_pkcs1_vectors); 25 use cmd_helpers; 26 27 my $sign_data = parse_pkcs1_vectors("$FindBin::Bin/pkcs1v15sign-vectors.txt"); 28 my $enc_data = parse_pkcs1_vectors("$FindBin::Bin/pkcs1v15crypt-vectors.txt"); 29 30 use Digest::SHA qw(sha1); 31 32 my $valid = unpack('H*', "VALID\n"); 33 34 my %dertags = ( 35 octet_string => "\x04", 36 null => "\x05", 37 oid => "\x06", 38 sequence => "\x30", # 0x20 for CONSTRUCTED, 0x10 for SEQUENCE 39 ); 40 41 sub der { 42 my $tag = shift; 43 my $value = join('', @_); 44 my $len = length($value); 45 my $derlen; 46 47 $derlen = pack('CN', 0x84, $len) if $len <= 0xFFFFFFFF; 48 $derlen = pack('CCn',0x83, ($len>>16), ($len&0xFFFF)) if $len < 1<<16; 49 $derlen = pack('Cn', 0x82, $len) if $len < 1<<12; 50 $derlen = pack('CC', 0x81, $len) if $len < 1<<8; # x.690 8.1.3.5 51 $derlen = pack('C', $len) if $len < 128; # x.690 8.1.3.4 52 53 my $res = $dertags{$tag} . $derlen . $value; 54 return $res; 55 } 56 57 sub EMSA_PKCS1_v1_5 { 58 my $hash = shift; 59 my $encodedoid = shift; 60 61 return sub { 62 my %opts = @_; 63 my $emLen = length($opts{key}->{N}) / 2; 64 my $M = pack('H*', $opts{message}); 65 my $H = $hash->($M); 66 my $T = der('sequence', 67 der('sequence', $encodedoid, der('null')), 68 der('octet_string', $H)); 69 my $tLen = length $T; 70 71 if ($emLen < $tLen + 11) { 72 print STDERR "# ERROR: intended encoded message length too short\n"; 73 return 0; 74 } 75 my $PS = pack('H*', 'ff') x ($emLen - $tLen - 3); 76 my $EM = pack('H*', '0001') . $PS . pack('H*', '00') . $T; 77 78 return $EM; 79 } 80 } 81 82 sub EME_PKCS1_v1_5_encoding { 83 return sub { 84 my %opts = @_; 85 my $k = length($opts{key}->{N}) / 2; 86 my $M = pack('H*', $opts{message}); 87 my $mLen = length($M); 88 my $PS = pack('H*', $opts{seed}); 89 90 if (length($PS) != $k - $mLen - 3) { 91 print STDERR "# ERROR: message or seed too short or too long\n"; 92 return 0; 93 } 94 my $EM = pack('H*', '0002') . $PS . pack('H*', '00') . $M; 95 96 return $EM; 97 } 98 } 99 100 sub EME_PKCS1_v1_5_decoding { 101 return sub { 102 my $output = shift; 103 my %opts = @_; 104 # These lengths are for unpacking hex digits, so should not be divided 105 # by two, as they are in EME_PKCS1_v1_5_encoding(). 106 my $messagelen = length($opts{message}); 107 my $seedlen = length($opts{seed}); 108 my ($prefix, $PS, $midfix, $M, $trailer) 109 = unpack("H4H${seedlen}H2H${messagelen}H*", $output); 110 die "RSA decryption output badly formed [ '$prefix', '$PS', '$midfix', '$M', '$trailer' ]" 111 unless (fc($prefix) eq '0002' 112 && fc($PS) eq fc($opts{seed}) 113 && fc($midfix) eq '00' 114 && fc($M) eq fc($opts{message}) 115 && $trailer eq ''); 116 117 return $M; 118 } 119 } 120 121 my $emsa_sha1_hook = EMSA_PKCS1_v1_5(\&sha1, pack('H*', "06052b0e03021a")); 122 123 runtests( 124 { 125 title => 'PKCS#1 v1.5 Signature using key associated operations', 126 cases => [ 127 sign => { 128 input => 'message', 129 output => 'signature', 130 cmd => mk_cmd('lesec-tool', 'sign', 131 '-plugin ltc', 132 '-assoc', 133 'rsa', 134 mk_key_from('key')), 135 'input-hook' => $emsa_sha1_hook, 136 }, 137 verify => { 138 input => 'message', 139 auxilliary => 'signature', 140 expected => $valid, 141 cmd => mk_cmd('lesec-tool', 'verify', 142 '-plugin ltc', 143 '-assoc', 144 'rsa', 145 mk_sig_from('signature'), 146 mk_key_from('key')), 147 'input-hook' => $emsa_sha1_hook, 148 } 149 ], 150 vectors => $sign_data, 151 }, 152 { 153 title => 'PKCS#1 v1.5 Encryption using key associated operations', 154 cases => [ 155 encrypt => { 156 input => 'message', 157 auxilliary => 'seed', 158 output => 'encryption', 159 cmd => mk_cmd('lesec-tool', 'enc', 160 '-plugin ltc', 161 '-assoc', 162 'rsa', 163 mk_key_from('key')), 164 'input-hook' => EME_PKCS1_v1_5_encoding(), 165 }, 166 decrypt => { 167 input => 'encryption', 168 auxilliary => 'seed', 169 output => 'message', 170 cmd => mk_cmd('lesec-tool', 'dec', 171 '-plugin ltc', 172 '-assoc', 173 'rsa', 174 mk_key_from('key')), 175 'output-hook' => EME_PKCS1_v1_5_decoding(), 176 } 177 ], 178 vectors => $enc_data, 179 } 180 );