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 our $OPENSSL = 'openssl';
25 our $SSH_KEYGEN = 'ssh-keygen';
27 sub _croak
{ require Carp
; Carp
::croak
(@_) }
28 sub _usage
{ _croak
("Usage: @_\n") }
30 =func generate_secure_random_bytes
32 $bytes = generate_secure_random_bytes
($num_bytes);
34 Get a certain number of secure random bytes
.
38 sub generate_secure_random_bytes
{
39 my $size = shift or _usage
(q{generate_secure_random_bytes($num_bytes)});
41 my @cmd = ($OPENSSL, 'rand', $size);
44 my $pid = open2
($out, undef, @cmd);
49 my $exit_code = $status >> 8;
50 _croak
'Failed to generate secure random bytes' if $exit_code != 0;
52 return do { local $/; <$out> };
55 =func read_openssh_public_key
57 $pem_public_key = read_openssh_public_key
($public_key_filepath);
59 Read a RFC4716
(SSH2
) public key from a file
, converting it to PKCS8
(PEM
).
63 sub read_openssh_public_key
{
64 my $filepath = shift or _usage
(q{read_openssh_public_key($filepath)});
66 my @cmd = ($SSH_KEYGEN, qw{-e -m PKCS8 -f}, $filepath);
69 my $pid = open2
($out, undef, @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 = ($SSH_KEYGEN, qw{-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 = ($OPENSSL, qw{rsautl -decrypt -oaep -in}, $filepath, '-inkey', $privkey);
142 push @cmd, ('-out', $outfile) if $outfile;
145 my $pid = open2
($out, undef, @cmd);
150 my $exit_code = $status >> 8;
151 _croak
'Failed to decrypt ciphertext' if $exit_code != 0;
153 return do { local $/; <$out> };
158 $ciphertext = decrypt_rsa
($plaintext_filepath, $public_key_filepath);
159 $ciphertext = decrypt_rsa
(\
$plaintext, $public_key_filepath);
160 decrypt_rsa
($plaintext_filepath, $public_key_filepath, $ciphertext_filepath);
161 decrypt_rsa
(\
$plaintext, $public_key_filepath, $ciphertext_filepath);
163 Do RSA encryption
. Turn plaintext into ciphertext
.
168 my $filepath = shift or _usage
(q{encrypt_rsa($filepath, $keypath)});
169 my $pubkey = shift or _usage
(q{encrypt_rsa($filepath, $keypath)});
173 if (ref $filepath eq 'SCALAR') {
174 $temp1 = File
::Temp-
>new(UNLINK
=> 1);
175 print $temp1 $$filepath;
177 $filepath = $temp1->filename;
180 my $key = read_openssh_public_key
($pubkey);
182 my $temp2 = File
::Temp-
>new(UNLINK
=> 1);
185 my $keypath = $temp2->filename;
187 my @cmd = ($OPENSSL, qw{rsautl -encrypt -oaep -pubin -inkey}, $keypath, '-in', $filepath);
188 push @cmd, ('-out', $outfile) if $outfile;
191 my $pid = open2
($out, undef, @cmd);
196 my $exit_code = $status >> 8;
197 _croak
'Failed to encrypt plaintext' if $exit_code != 0;
199 return do { local $/; <$out> };
202 =func decrypt_aes_256_cbc
204 $plaintext = decrypt_aes_256_cbc
($ciphertext_filepath, $secret);
205 $plaintext = decrypt_aes_256_cbc
(\
$ciphertext, $secret);
206 decrypt_aes_256_cbc
($ciphertext_filepath, $secret, $plaintext_filepath);
207 decrypt_aes_256_cbc
(\
$ciphertext, $secret, $plaintext_filepath);
209 Do symmetric decryption
. Turn ciphertext into plaintext
.
213 sub decrypt_aes_256_cbc
{
214 my $filepath = shift or _usage
(q{decrypt_aes_256_cbc($ciphertext, $secret)});
215 my $secret = shift or _usage
(q{decrypt_aes_256_cbc($ciphertext, $secret)});
219 if (ref $filepath eq 'SCALAR') {
220 $temp = File
::Temp-
>new(UNLINK
=> 1);
221 print $temp $$filepath;
223 $filepath = $temp->filename;
226 my @cmd = ($OPENSSL, qw{aes-256-cbc -d -pass stdin -md sha256 -in}, $filepath);
227 push @cmd, ('-out', $outfile) if $outfile;
230 my $pid = open2
($out, $in, @cmd);
238 my $exit_code = $status >> 8;
239 _croak
'Failed to decrypt ciphertext' if $exit_code != 0;
241 return do { local $/; <$out> };
244 =func encrypt_aes_256_cbc
246 $ciphertext = encrypt_aes_256_cbc
($plaintext_filepath, $secret);
247 $ciphertext = encrypt_aes_256_cbc
(\
$plaintext, $secret);
248 encrypt_aes_256_cbc
($plaintext_filepath, $secret, $ciphertext_filepath);
249 encrypt_aes_256_cbc
(\
$plaintext, $secret, $ciphertext_filepath);
251 Do symmetric encryption
. Turn plaintext into ciphertext
.
255 sub encrypt_aes_256_cbc
{
256 my $filepath = shift or _usage
(q{encrypt_aes_256_cbc($plaintext, $secret)});
257 my $secret = shift or _usage
(q{encrypt_aes_256_cbc($plaintext, $secret)});
261 if (ref $filepath eq 'SCALAR') {
262 $temp = File
::Temp-
>new(UNLINK
=> 1);
263 print $temp $$filepath;
265 $filepath = $temp->filename;
268 my @cmd = ($OPENSSL, qw{aes-256-cbc -pass stdin -md sha256 -in}, $filepath);
269 push @cmd, ('-out', $outfile) if $outfile;
272 my $pid = open2
($out, $in, @cmd);
280 my $exit_code = $status >> 8;
281 _croak
'Failed to encrypt plaintext' if $exit_code != 0;
283 return do { local $/; <$out> };