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, undef, @cmd);
46 my $exit_code = $status >> 8;
47 _croak
'Failed to generate secure random bytes' if $exit_code != 0;
49 return do { local $/; <$out> };
52 =func read_openssh_public_key
54 $pem_public_key = read_openssh_public_key
($public_key_filepath);
56 Read a RFC4716
(SSH2
) public key from a file
, converting it to PKCS8
(PEM
).
60 sub read_openssh_public_key
{
61 my $filepath = shift or _usage
(q{read_openssh_public_key($filepath)});
63 my @cmd = (qw{ssh-keygen -e -m PKCS8 -f}, $filepath);
66 my $pid = open2
($out, undef, @cmd);
71 my $exit_code = $status >> 8;
72 _croak
'Failed to read OpenSSH public key' if $exit_code != 0;
74 return do { local $/; <$out> };
77 =func read_openssh_key_fingerprint
79 $fingerprint = read_openssh_key_fingerprint
($filepath);
81 Get the fingerprint of an OpenSSH private
or public key
.
85 sub read_openssh_key_fingerprint
{
86 my $filepath = shift or _usage
(q{read_openssh_key_fingerprint($filepath)});
88 my @cmd = (qw{ssh-keygen -l -E md5 -f}, $filepath);
91 my $pid = open2
($out, undef, @cmd);
96 my $exit_code = $status >> 8;
97 _croak
'Failed to read SSH2 key fingerprint' if $exit_code != 0;
99 my $line = do { local $/; <$out> };
102 my ($bits, $fingerprint, $comment, $type) = $line =~ m!^(\d+) MD5:([^ ]+) (.*) \(([^\)]+)\)$!;
104 $fingerprint =~ s/://g;
108 fingerprint
=> $fingerprint,
116 $plaintext = decrypt_rsa
($ciphertext_filepath, $private_key_filepath);
117 $plaintext = decrypt_rsa
(\
$ciphertext, $private_key_filepath);
118 decrypt_rsa
($ciphertext_filepath, $private_key_filepath, $plaintext_filepath);
119 decrypt_rsa
(\
$ciphertext, $private_key_filepath, $plaintext_filepath);
121 Do RSA decryption
. Turn ciphertext into plaintext
.
126 my $filepath = shift or _usage
(q{decrypt_rsa($filepath, $keypath)});
127 my $privkey = shift or _usage
(q{decrypt_rsa($filepath, $keypath)});
131 if (ref $filepath eq 'SCALAR') {
132 $temp = File
::Temp-
>new(UNLINK
=> 1);
133 print $temp $$filepath;
135 $filepath = $temp->filename;
138 my @cmd = (qw{openssl rsautl -decrypt -oaep -in}, $filepath, '-inkey', $privkey);
139 push @cmd, ('-out', $outfile) if $outfile;
142 my $pid = open2
($out, undef, @cmd);
147 my $exit_code = $status >> 8;
148 _croak
'Failed to decrypt ciphertext' if $exit_code != 0;
150 return do { local $/; <$out> };
155 $ciphertext = decrypt_rsa
($plaintext_filepath, $public_key_filepath);
156 $ciphertext = decrypt_rsa
(\
$plaintext, $public_key_filepath);
157 decrypt_rsa
($plaintext_filepath, $public_key_filepath, $ciphertext_filepath);
158 decrypt_rsa
(\
$plaintext, $public_key_filepath, $ciphertext_filepath);
160 Do RSA encryption
. Turn plaintext into ciphertext
.
165 my $filepath = shift or _usage
(q{encrypt_rsa($filepath, $keypath)});
166 my $pubkey = shift or _usage
(q{encrypt_rsa($filepath, $keypath)});
170 if (ref $filepath eq 'SCALAR') {
171 $temp1 = File
::Temp-
>new(UNLINK
=> 1);
172 print $temp1 $$filepath;
174 $filepath = $temp1->filename;
177 my $key = read_openssh_public_key
($pubkey);
179 my $temp2 = File
::Temp-
>new(UNLINK
=> 1);
182 my $keypath = $temp2->filename;
184 my @cmd = (qw{openssl rsautl -encrypt -oaep -pubin -inkey}, $keypath, '-in', $filepath);
185 push @cmd, ('-out', $outfile) if $outfile;
188 my $pid = open2
($out, undef, @cmd);
193 my $exit_code = $status >> 8;
194 _croak
'Failed to encrypt plaintext' if $exit_code != 0;
196 return do { local $/; <$out> };
199 =func decrypt_aes_256_cbc
201 $plaintext = decrypt_aes_256_cbc
($ciphertext_filepath, $secret);
202 $plaintext = decrypt_aes_256_cbc
(\
$ciphertext, $secret);
203 decrypt_aes_256_cbc
($ciphertext_filepath, $secret, $plaintext_filepath);
204 decrypt_aes_256_cbc
(\
$ciphertext, $secret, $plaintext_filepath);
206 Do symmetric decryption
. Turn ciphertext into plaintext
.
210 sub decrypt_aes_256_cbc
{
211 my $filepath = shift or _usage
(q{decrypt_aes_256_cbc($ciphertext, $secret)});
212 my $secret = shift or _usage
(q{decrypt_aes_256_cbc($ciphertext, $secret)});
216 if (ref $filepath eq 'SCALAR') {
217 $temp = File
::Temp-
>new(UNLINK
=> 1);
218 print $temp $$filepath;
220 $filepath = $temp->filename;
223 my @cmd = (qw{openssl aes-256-cbc -d -pass stdin -md sha256 -in}, $filepath);
224 push @cmd, ('-out', $outfile) if $outfile;
227 my $pid = open2
($out, $in, @cmd);
235 my $exit_code = $status >> 8;
236 _croak
'Failed to decrypt ciphertext' if $exit_code != 0;
238 return do { local $/; <$out> };
241 =func encrypt_aes_256_cbc
243 $ciphertext = encrypt_aes_256_cbc
($plaintext_filepath, $secret);
244 $ciphertext = encrypt_aes_256_cbc
(\
$plaintext, $secret);
245 encrypt_aes_256_cbc
($plaintext_filepath, $secret, $ciphertext_filepath);
246 encrypt_aes_256_cbc
(\
$plaintext, $secret, $ciphertext_filepath);
248 Do symmetric encryption
. Turn plaintext into ciphertext
.
252 sub encrypt_aes_256_cbc
{
253 my $filepath = shift or _usage
(q{encrypt_aes_256_cbc($plaintext, $secret)});
254 my $secret = shift or _usage
(q{encrypt_aes_256_cbc($plaintext, $secret)});
258 if (ref $filepath eq 'SCALAR') {
259 $temp = File
::Temp-
>new(UNLINK
=> 1);
260 print $temp $$filepath;
262 $filepath = $temp->filename;
265 my @cmd = (qw{openssl aes-256-cbc -pass stdin -md sha256 -in}, $filepath);
266 push @cmd, ('-out', $outfile) if $outfile;
269 my $pid = open2
($out, $in, @cmd);
277 my $exit_code = $status >> 8;
278 _croak
'Failed to encrypt plaintext' if $exit_code != 0;
280 return do { local $/; <$out> };