File Coverage

blib/lib/VOMS/Lite/RSAHelper.pm
Criterion Covered Total %
statement 75 81 92.5
branch 4 8 50.0
condition 2 6 33.3
subroutine 8 9 88.8
pod 0 5 0.0
total 89 109 81.6


line stmt bran cond sub pod time code
1             package VOMS::Lite::RSAHelper;
2              
3 1     1   18 use 5.004;
  1         4  
  1         43  
4 1     1   5 use strict;
  1         2  
  1         35  
5 1     1   5 use Math::BigInt lib => 'GMP';
  1         2  
  1         15  
6              
7             require Exporter;
8 1     1   1231 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         2  
  1         1302  
9             @ISA = qw(Exporter);
10             %EXPORT_TAGS = ( );
11             @EXPORT_OK = qw( rsasign rsaencrypt rsaverify rsadecrypt );
12             @EXPORT = ( );
13             $VERSION = '0.20';
14              
15             ###############################################
16              
17             sub rsasign { # use private key to encrypt
18 5     5 0 24 return &rsaenc( "01", @_);
19             }
20              
21             ###############################################
22              
23             sub rsaencrypt { # use public key to encrypt
24 0     0 0 0 return &rsaenc( "02", @_);
25             }
26              
27             ###############################################
28              
29             sub rsaverify {
30 2     2 0 9 return rsadecrypt( @_ );
31             }
32              
33             ###############################################
34              
35             sub rsadecrypt {
36 2     2 0 5 my ($EDhex,$chex,$nhex)=@_;
37              
38             # Even up hex lengths into whole octets
39 2         16 $chex=~s/^.(..)*$/0$&/;
40 2         19 $nhex=~s/^.(..)*$/0$&/;
41 2         17 $EDhex=~s/^.(..)*$/0$&/;
42 2         6 my $khex=length($nhex);
43              
44             # Length of modulus and Data in octets
45 2         6 my $k=$khex/2;
46 2         6 my $EDlen=length($EDhex)/2;
47              
48             # Create Integer representing Data
49 2         24 my $x=Math::BigInt->bzero();
50 2         130 foreach (split(//,$EDhex)) {
51 256         37210 $x->bmul(16);
52 256         40617 $x->badd(hex($_));
53             }
54              
55             # Create Integer representing Modulus
56 2         262 my $n=Math::BigInt->bzero();
57 2         99 foreach (split(//,$nhex)) {
58 260         28282 $n->bmul(16);
59 260         30649 $n->badd(hex($_));
60             }
61              
62             # Create Integer representing Exponent
63 2         256 my $c=Math::BigInt->bzero();
64 2         137 foreach (split(//,$chex)) {
65 12         1293 $c->bmul(16);
66 12         1179 $c->badd(hex($_));
67             }
68              
69             # Do Big RSA Maths y = x^c mod n
70 2         198 my $y=Math::BigInt->bzero();
71 2         45 $y = $x->bmodpow($c,$n);
72              
73             # Get Encrypted Data Character String
74 2         67990 my $Dhex=$y->as_hex();
75 2         3429 $Dhex=~s/^0x//;
76 2         37 $Dhex=~s/^.(..)*$/0$&/; # Even up the length
77              
78 2 50       25 if ( length($Dhex) < ($khex-4) ) { # short string: BT must be 00 (NB RFC difference should be ($khex-2) )
79 0         0 return $Dhex;
80             }
81             else { # long string: BT is any one of 00, 01 and 02
82 2         7 my $BT=substr($Dhex,0,2);
83 2         6 $Dhex=substr($Dhex,2);
84 2 50       8 if ( $BT eq "00" ) {
85 0   0     0 until ( substr($Dhex,0,2) ne '00' || $Dhex eq "" ) { $Dhex=substr($Dhex,2); }
  0         0  
86             }
87             else { # BT = 01 or 02
88 2   66     25 until ( substr($Dhex,0,2) eq '00' || $Dhex eq "" ) { $Dhex=substr($Dhex,2); }
  52         207  
89 2         6 $Dhex=substr($Dhex,2);
90             }
91             }
92 2         43 return $Dhex;
93             }
94              
95             ###############################################
96              
97             sub rsaenc { #RSA Algorythm as per RFC2313 (with tweak for openssl verification stuff)
98              
99             # Get block type, Data, HexKey, HexModulus
100 5     5 0 14 my ($BT,$Dhex,$chex,$nhex)=@_;
101              
102             # Even up hex lengths into whole octets
103 5         48 $chex=~s/^.(..)*$/0$&/;
104 5         41 $nhex=~s/^.(..)*$/0$&/;
105 5         28 $Dhex=~s/^.(..)*$/0$&/;
106 5         9 my $khex=length($nhex);
107              
108             # Length of modulus and Data in octets
109 5         11 my $k=$khex/2;
110 5         9 my $Dlen=length($Dhex)/2;
111              
112             # Barf if datalen is too long for RSA
113 5 50       18 ( $Dlen > ($k - 11) ) && die "Too much data to encrypt!";
114              
115             # Padding for signing (why - 4 and not - 3 as per RFC I don't know)
116 5         18 my $PS="ff" x ( $k - 4 - $Dlen);
117              
118             # If encrypting alter padding to random
119 5 50       13 if ( $BT eq "02" ) { $PS=~s/../unpack('H2',pack('i',int(rand(255)+1)))/ge; }
  0         0  
  0         0  
120              
121             # Make Encryption Block. EB = 00 || BT || PS || 00 || D
122 5         17 my $EB='00'.$BT.$PS.'00'.$Dhex;
123              
124             # Create Integer representing Data
125 5         30 my $x=Math::BigInt->bzero();
126 5         299 foreach (split(//,$EB)) {
127 640         63965 $x->bmul(16);
128 640         69097 $x->badd(hex($_));
129             }
130              
131             # Create Integer representing Modulus
132 5         594 my $n=Math::BigInt->bzero();
133 5         214 foreach (split(//,$nhex)) {
134 650         66480 $n->bmul(16);
135 650         82419 $n->badd(hex($_));
136             }
137              
138             # Create Integer representing Exponent
139 5         567 my $c=Math::BigInt->bzero();
140 5         231 foreach (split(//,$chex)) {
141 648         63582 $c->bmul(16);
142 648         69792 $c->badd(hex($_));
143             }
144              
145             # Do Big RSA Maths y = x^c mod n
146 5         848 my $y=Math::BigInt->bzero();
147 5         175 $y = $x->bmodpow($c,$n);
148              
149             # Get Encrypted Data Character String
150 5         7089480 my $ED=$y->as_hex();
151 5         7672 $ED=~s/^0x//;
152 5         58 $ED=~s/^.(..)*$/0$&/;
153            
154             # Send Hex Data back
155 5         89 return $ED;
156             }
157              
158             1;
159             __END__