/ tests / rsa-key.t
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  );