line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Crypt::ECDH_ES; |
2
|
|
|
|
|
|
|
$Crypt::ECDH_ES::VERSION = '0.003'; |
3
|
1
|
|
|
1
|
|
13227
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
22
|
|
4
|
1
|
|
|
1
|
|
3
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
22
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
3
|
use Carp; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
60
|
|
7
|
1
|
|
|
1
|
|
396
|
use Crypt::Curve25519; |
|
1
|
|
|
|
|
615
|
|
|
1
|
|
|
|
|
50
|
|
8
|
1
|
|
|
1
|
|
375
|
use Crypt::Rijndael; |
|
1
|
|
|
|
|
305
|
|
|
1
|
|
|
|
|
26
|
|
9
|
1
|
|
|
1
|
|
415
|
use Digest::SHA qw/sha256 hmac_sha256/; |
|
1
|
|
|
|
|
2335
|
|
|
1
|
|
|
|
|
73
|
|
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
5
|
use Exporter 5.57 'import'; |
|
1
|
|
|
|
|
13
|
|
|
1
|
|
|
|
|
528
|
|
12
|
|
|
|
|
|
|
our @EXPORT_OK = qw/ecdhes_encrypt ecdhes_decrypt ecdhes_generate_key/; |
13
|
|
|
|
|
|
|
our %EXPORT_TAGS = (all => \@EXPORT_OK); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $csprng = ($^O eq 'MSWin32') ? |
16
|
|
|
|
|
|
|
do { |
17
|
|
|
|
|
|
|
require Win32::API; |
18
|
|
|
|
|
|
|
my $genrand = Win32::API->new('advapi32', 'INT SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength)') or croak "Could not import SystemFunction036: $^E"; |
19
|
|
|
|
|
|
|
sub { |
20
|
|
|
|
|
|
|
my $count = shift; |
21
|
|
|
|
|
|
|
$genrand->Call(my $buffer, $count) or croak "Could not read from csprng: $^E"; |
22
|
|
|
|
|
|
|
return $buffer; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
} : |
25
|
|
|
|
|
|
|
do { |
26
|
|
|
|
|
|
|
open my $urandom, '<:raw', '/dev/urandom' or croak 'Couldn\'t open /dev/urandom'; |
27
|
|
|
|
|
|
|
sub { |
28
|
|
|
|
|
|
|
my $count = shift; |
29
|
|
|
|
|
|
|
read $urandom, my $buffer, $count or croak "Couldn't read from csprng: $!"; |
30
|
|
|
|
|
|
|
return $buffer; |
31
|
|
|
|
|
|
|
}; |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $format = 'C/a C/a n/a N/a'; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub ecdhes_encrypt { |
37
|
1
|
|
|
1
|
1
|
6
|
my ($public_key, $data) = @_; |
38
|
|
|
|
|
|
|
|
39
|
1
|
|
|
|
|
3
|
my $private = curve25519_secret_key($csprng->(32)); |
40
|
1
|
|
|
|
|
113
|
my $public = curve25519_public_key($private); |
41
|
1
|
|
|
|
|
89
|
my $shared = curve25519_shared_secret($private, $public_key); |
42
|
|
|
|
|
|
|
|
43
|
1
|
|
|
|
|
20
|
my ($encrypt_key, $sign_key) = unpack 'a16 a16', sha256($shared); |
44
|
1
|
|
|
|
|
5
|
my $iv = substr sha256($public), 0, 16; |
45
|
1
|
|
|
|
|
11
|
my $cipher = Crypt::Rijndael->new($encrypt_key, Crypt::Rijndael::MODE_CBC); |
46
|
1
|
|
|
|
|
4
|
$cipher->set_iv($iv); |
47
|
|
|
|
|
|
|
|
48
|
1
|
|
|
|
|
2
|
my $pad_length = 16 - length($data) % 16; |
49
|
1
|
|
|
|
|
4
|
my $padding = chr($pad_length) x $pad_length; |
50
|
|
|
|
|
|
|
|
51
|
1
|
|
|
|
|
6
|
my $ciphertext = $cipher->encrypt($data . $padding); |
52
|
1
|
|
|
|
|
9
|
my $mac = hmac_sha256($iv . $ciphertext, $sign_key); |
53
|
1
|
|
|
|
|
12
|
return pack $format, '', $public, $mac, $ciphertext; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub ecdhes_decrypt { |
57
|
1
|
|
|
1
|
1
|
385
|
my ($private_key, $packed_data) = @_; |
58
|
|
|
|
|
|
|
|
59
|
1
|
|
|
|
|
9
|
my ($options, $public, $mac, $ciphertext) = unpack $format, $packed_data; |
60
|
1
|
50
|
|
|
|
5
|
croak 'Unknown options' if $options ne ''; |
61
|
|
|
|
|
|
|
|
62
|
1
|
|
|
|
|
90
|
my $shared = curve25519_shared_secret($private_key, $public); |
63
|
1
|
|
|
|
|
7
|
my ($encrypt_key, $sign_key) = unpack 'a16 a16', sha256($shared); |
64
|
1
|
|
|
|
|
7
|
my $iv = substr sha256($public), 0, 16; |
65
|
1
|
50
|
|
|
|
13
|
croak 'MAC is incorrect' if hmac_sha256($iv . $ciphertext, $sign_key) ne $mac; |
66
|
1
|
|
|
|
|
8
|
my $cipher = Crypt::Rijndael->new($encrypt_key, Crypt::Rijndael::MODE_CBC); |
67
|
1
|
|
|
|
|
2
|
$cipher->set_iv($iv); |
68
|
|
|
|
|
|
|
|
69
|
1
|
|
|
|
|
4
|
my $plaintext = $cipher->decrypt($ciphertext); |
70
|
1
|
|
|
|
|
2
|
my $pad_length = ord substr $plaintext, -1; |
71
|
1
|
50
|
|
|
|
6
|
substr($plaintext, -$pad_length, $pad_length, '') eq chr($pad_length) x $pad_length or croak 'Incorrectly padded'; |
72
|
1
|
|
|
|
|
4
|
return $plaintext; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub ecdhes_generate_key { |
76
|
0
|
|
|
0
|
1
|
|
my $buf; |
77
|
0
|
0
|
|
|
|
|
if ($^O eq 'MSWin32') { |
78
|
0
|
|
|
|
|
|
$buf = $csprng->(32); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
else { |
81
|
0
|
0
|
|
|
|
|
open my $fh, '<:raw', '/dev/random' or croak "Couldn't open /dev/random: $!"; |
82
|
0
|
0
|
|
|
|
|
read $fh, $buf, 32 or croak "Can't read from /dev/random: $!"; |
83
|
0
|
|
|
|
|
|
close $fh; |
84
|
|
|
|
|
|
|
} |
85
|
0
|
|
|
|
|
|
my $secret = curve25519_secret_key($buf); |
86
|
0
|
|
|
|
|
|
my $public = curve25519_public_key($secret); |
87
|
0
|
|
|
|
|
|
return ($public, $secret); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
1; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
#ABSTRACT: A fast and small hybrid crypto system |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
__END__ |