File Coverage

blib/lib/Crypt/OpenPGP/Util.pm
Criterion Covered Total %
statement 59 65 90.7
branch 19 24 79.1
condition 5 6 83.3
subroutine 15 15 100.0
pod 7 10 70.0
total 105 120 87.5


line stmt bran cond sub pod time code
1             package Crypt::OpenPGP::Util;
2 16     16   216427 use strict;
  16         31  
  16         740  
3 16     16   84 use warnings;
  16         31  
  16         1387  
4              
5             our $VERSION = '1.19'; # VERSION
6              
7             # For some reason, FastCalc causes problems. Restrict to one of these 3 backends
8 16     16   24149 use Math::BigInt only => 'Pari,GMP,Calc';
  16         782531  
  16         89  
9              
10 16     16   481942 use Exporter;
  16         35  
  16         20536  
11             our @EXPORT_OK = qw( bitsize bin2bigint bin2mp bigint2bin mp2bin mod_exp mod_inverse
12             dash_escape dash_unescape canonical_text );
13             our @ISA = qw( Exporter );
14              
15             sub bitsize {
16 109     109 1 36694 my $bigint = Math::BigInt->new($_[0]);
17 109         11750 return $bigint->bfloor($bigint->blog(2)) + 1;
18             }
19              
20 489 100   489 1 280866 sub bin2bigint { $_[0] ? Math::BigInt->new('0x' . unpack 'H*', $_[0]) : 0 }
21              
22             *bin2mp = \&bin2bigint;
23              
24             sub bigint2bin {
25 112     112 1 40380 my($p) = @_;
26            
27 112         511 $p = _ensure_bigint($p);
28            
29 112         449 my $base = _ensure_bigint(1) << _ensure_bigint(4*8);
30 112         49477 my $res = '';
31 112         485 while ($p != 0) {
32 2354         476798 my $r = $p % $base;
33 2354         1871191 $p = ($p-$r) / $base;
34 2354         2491012 my $buf = pack 'N', $r;
35 2354 100       126240 if ($p == 0) {
36 110 100       22974 $buf = $r >= 16777216 ? $buf :
    100          
    100          
37             $r >= 65536 ? substr($buf, -3, 3) :
38             $r >= 256 ? substr($buf, -2, 2) :
39             substr($buf, -1, 1);
40             }
41 2354         537876 $res = $buf . $res;
42             }
43 112         21953 $res;
44             }
45              
46             *mp2bin = \&bigint2bin;
47              
48             sub mod_exp {
49 38     38 1 1579 my($a, $exp, $n) = @_;
50            
51 38         163 $a = _ensure_bigint($a);
52            
53 38         235 $a->copy->bmodpow($exp, $n);
54             }
55              
56             sub mod_inverse {
57 14     14 1 3873 my($a, $n) = @_;
58            
59 14         98 $a = _ensure_bigint($a);
60              
61 14         112 $a->copy->bmodinv($n);
62             }
63              
64             sub dash_escape {
65 1     1 1 6 my($data) = @_;
66 1         4 $data =~ s/^-/- -/mg;
67 1         3 $data;
68             }
69              
70             sub dash_unescape {
71 2     2 0 8 my($data) = @_;
72 2         11 $data =~ s/^-\s//mg;
73 2         25 $data;
74             }
75              
76             sub canonical_text {
77 4     4 1 14 my($text) = @_;
78 4         25 my @lines = split /\n/, $text, -1;
79 4         13 for my $l (@lines) {
80             ## pgp2 and pgp5 do not trim trailing whitespace from "canonical text"
81             ## signatures, only from cleartext signatures.
82             ## See:
83             ## http://cert.uni-stuttgart.de/archive/ietf-openpgp/2000/01/msg00033.html
84 21 50       38 if ($Crypt::OpenPGP::Globals::Trim_trailing_ws) {
85 21         268 $l =~ s/[ \t\r\n]*$//;
86             } else {
87 0         0 $l =~ s/[\r\n]*$//;
88             }
89             }
90 4         41 join "\r\n", @lines;
91             }
92              
93              
94             sub _ensure_bigint {
95 388     388   734 my $num = shift;
96              
97 388 100 66     2247 if ($num && (! ref $num || ! $num->isa('Math::BigInt'))) {
      100        
98 287         2277 $num = Math::BigInt->new($num);
99             }
100            
101 388         35688 return $num;
102             }
103              
104             sub get_random_bytes {
105 89     89 0 192 my $length = shift;
106 89 50       6940 if (eval 'require Crypt::Random; 1;') {
    50          
107 0         0 return Crypt::Random::makerandom_octet( Length => $length);
108             }
109             elsif (eval 'require Bytes::Random::Secure; 1;') {
110 89         605 return Bytes::Random::Secure::random_bytes($length);
111             }
112             else {
113 0         0 die "No random source available!";
114             }
115             }
116              
117             sub get_random_bigint {
118 23     23 0 43575 my $bits = shift;
119 23 50       1857 if (eval 'require Crypt::Random; 1;') {
    50          
120 0         0 my $pari = Crypt::Random::makerandom( Size => $bits, Strength => 0 );
121 0         0 return Math::BigInt->new($pari);
122             }
123             elsif (eval 'require Bytes::Random::Secure; 1;') {
124 23         142 my $hex = Bytes::Random::Secure::random_bytes_hex(int(($bits + 7) / 8));
125 23         2749 my $val = Math::BigInt->new("0x$hex");
126             # Get exactly the correct number of bits.
127 23 100       22608 $val->brsft(8 - ($bits & 7)) if ($bits & 7);
128             # Make sure the top bit is set.
129 23         24526 $val->bior(Math::BigInt->bone->blsft($bits-1));
130 23         60158 return $val;
131             }
132             else {
133 0           die "No random source available!";
134             }
135             }
136              
137             1;
138             __END__