1 package App
::GroupSecret
::Crypt
;
2 # ABSTRACT: Collection of crypto-related subroutines
7 our $VERSION = '9999.999'; # VERSION
9 use Exporter
qw(import);
12 use namespace
::clean
-except
=> [qw(import)];
15 generate_secure_random_bytes
16 read_openssh_public_key
17 read_openssh_key_fingerprint
24 sub _croak
{ require Carp
; Carp
::croak
(@_) }
25 sub _usage
{ _croak
("Usage: @_\n") }
27 =func generate_secure_random_bytes
29 $bytes = generate_secure_random_bytes
($num_bytes);
31 Get a certain number of secure random bytes
.
35 sub generate_secure_random_bytes
{
36 my $size = shift or _usage
(q{generate_secure_random_bytes($num_bytes)});
38 my @cmd = (qw{openssl rand}, $size);
41 my $pid = open2
($out, $in, @cmd);
47 my $exit_code = $status >> 8;
48 _croak
'Failed to generate secure random bytes' if $exit_code != 0;
50 return do { local $/; <$out> };
53 =func read_openssh_public_key
55 $pem_public_key = read_openssh_public_key
($public_key_filepath);
57 Read a RFC4716
(SSH2
) public key from a file
, converting it to PKCS8
(PEM
).
61 sub read_openssh_public_key
{
62 my $filepath = shift or _usage
(q{read_openssh_public_key($filepath)});
64 my @cmd = (qw{ssh-keygen -e -m PKCS8 -f}, $filepath);
67 my $pid = open2
($out, $in, @cmd);
74 my $exit_code = $status >> 8;
75 _croak
'Failed to read OpenSSH public key' if $exit_code != 0;
77 return do { local $/; <$out> };
80 =func read_openssh_key_fingerprint
82 $fingerprint = read_openssh_key_fingerprint
($filepath);
84 Get the fingerprint of an OpenSSH private
or public key
.
88 sub read_openssh_key_fingerprint
{
89 my $filepath = shift or _usage
(q{read_openssh_key_fingerprint($filepath)});
91 my @cmd = (qw{ssh-keygen -l -E md5 -f}, $filepath);
94 my $pid = open2
($out, undef, @cmd);
99 my $exit_code = $status >> 8;
100 _croak
'Failed to read SSH2 key fingerprint' if $exit_code != 0;
102 my $line = do { local $/; <$out> };
105 my ($bits, $fingerprint, $comment, $type) = $line =~ m!^(\d+) MD5:([^ ]+) (.*) \(([^\)]+)\)$!;
107 $fingerprint =~ s/://g;
111 fingerprint
=> $fingerprint,
119 $plaintext = decrypt_rsa
($ciphertext_filepath, $private_key_filepath);
120 $plaintext = decrypt_rsa
(\
$ciphertext, $private_key_filepath);
121 decrypt_rsa
($ciphertext_filepath, $private_key_filepath, $plaintext_filepath);
122 decrypt_rsa
(\
$ciphertext, $private_key_filepath, $plaintext_filepath);
124 Do RSA decryption
. Turn ciphertext into plaintext
.
129 my $filepath = shift or _usage
(q{decrypt_rsa($filepath, $keypath)});
130 my $privkey = shift or _usage
(q{decrypt_rsa($filepath, $keypath)});
134 if (ref $filepath eq 'SCALAR') {
135 $temp = File
::Temp-
>new(UNLINK
=> 1);
136 print $temp $$filepath;
138 $filepath = $temp->filename;
141 my @cmd = (qw{openssl rsautl -decrypt -oaep -in}, $filepath, '-inkey', $privkey);
142 push @cmd, ('-out', $outfile) if $outfile;
145 my $pid = open2
($out, $in, @cmd);
152 my $exit_code = $status >> 8;
153 _croak
'Failed to decrypt ciphertext' if $exit_code != 0;
155 return do { local $/; <$out> };
160 $ciphertext = decrypt_rsa
($plaintext_filepath, $public_key_filepath);
161 $ciphertext = decrypt_rsa
(\
$plaintext, $public_key_filepath);
162 decrypt_rsa
($plaintext_filepath, $public_key_filepath, $ciphertext_filepath);
163 decrypt_rsa
(\
$plaintext, $public_key_filepath, $ciphertext_filepath);
165 Do RSA encryption
. Turn plaintext into ciphertext
.
170 my $filepath = shift or _usage
(q{encrypt_rsa($filepath, $keypath)});
171 my $pubkey = shift or _usage
(q{encrypt_rsa($filepath, $keypath)});
175 if (ref $filepath eq 'SCALAR') {
176 $temp1 = File
::Temp-
>new(UNLINK
=> 1);
177 print $temp1 $$filepath;
179 $filepath = $temp1->filename;
182 my $key = read_openssh_public_key
($pubkey);
184 my $temp2 = File
::Temp-
>new(UNLINK
=> 1);
187 my $keypath = $temp2->filename;
189 my @cmd = (qw{openssl rsautl -encrypt -oaep -pubin -inkey}, $keypath, '-in', $filepath);
190 push @cmd, ('-out', $outfile) if $outfile;
193 my $pid = open2
($out, $in, @cmd);
200 my $exit_code = $status >> 8;
201 _croak
'Failed to encrypt plaintext' if $exit_code != 0;
203 return do { local $/; <$out> };
206 =func decrypt_aes_256_cbc
208 $plaintext = decrypt_aes_256_cbc
($ciphertext_filepath, $secret);
209 $plaintext = decrypt_aes_256_cbc
(\
$ciphertext, $secret);
210 decrypt_aes_256_cbc
($ciphertext_filepath, $secret, $plaintext_filepath);
211 decrypt_aes_256_cbc
(\
$ciphertext, $secret, $plaintext_filepath);
213 Do symmetric decryption
. Turn ciphertext into plaintext
.
217 sub decrypt_aes_256_cbc
{
218 my $filepath = shift or _usage
(q{decrypt_aes_256_cbc($ciphertext, $secret)});
219 my $secret = shift or _usage
(q{decrypt_aes_256_cbc($ciphertext, $secret)});
223 if (ref $filepath eq 'SCALAR') {
224 $temp = File
::Temp-
>new(UNLINK
=> 1);
225 print $temp $$filepath;
227 $filepath = $temp->filename;
230 my @cmd = (qw{openssl aes-256-cbc -d -pass stdin -in}, $filepath);
231 push @cmd, ('-out', $outfile) if $outfile;
234 my $pid = open2
($out, $in, @cmd);
242 my $exit_code = $status >> 8;
243 _croak
'Failed to decrypt ciphertext' if $exit_code != 0;
245 return do { local $/; <$out> };
248 =func encrypt_aes_256_cbc
250 $ciphertext = encrypt_aes_256_cbc
($plaintext_filepath, $secret);
251 $ciphertext = encrypt_aes_256_cbc
(\
$plaintext, $secret);
252 encrypt_aes_256_cbc
($plaintext_filepath, $secret, $ciphertext_filepath);
253 encrypt_aes_256_cbc
(\
$plaintext, $secret, $ciphertext_filepath);
255 Do symmetric encryption
. Turn plaintext into ciphertext
.
259 sub encrypt_aes_256_cbc
{
260 my $filepath = shift or _usage
(q{encrypt_aes_256_cbc($plaintext, $secret)});
261 my $secret = shift or _usage
(q{encrypt_aes_256_cbc($plaintext, $secret)});
265 if (ref $filepath eq 'SCALAR') {
266 $temp = File
::Temp-
>new(UNLINK
=> 1);
267 print $temp $$filepath;
269 $filepath = $temp->filename;
272 my @cmd = (qw{openssl aes-256-cbc -pass stdin -in}, $filepath);
273 push @cmd, ('-out', $outfile) if $outfile;
276 my $pid = open2
($out, $in, @cmd);
284 my $exit_code = $status >> 8;
285 _croak
'Failed to encrypt plaintext' if $exit_code != 0;
287 return do { local $/; <$out> };