use Exporter qw(import);
use File::Temp;
use IPC::Open2;
+use IPC::Open3;
+use Symbol qw(gensym);
use namespace::clean -except => [qw(import)];
our @EXPORT_OK = qw(
encrypt_aes_256_cbc
);
+our $OPENSSL = 'openssl';
+our $SSH_KEYGEN = 'ssh-keygen';
+
sub _croak { require Carp; Carp::croak(@_) }
sub _usage { _croak("Usage: @_\n") }
sub generate_secure_random_bytes {
my $size = shift or _usage(q{generate_secure_random_bytes($num_bytes)});
- my @cmd = (qw{openssl rand}, $size);
+ my @cmd = ($OPENSSL, 'rand', $size);
- my ($in, $out);
- my $pid = open2($out, $in, @cmd);
+ my $out;
+ my $pid = open2($out, undef, @cmd);
- close($in);
waitpid($pid, 0);
my $status = $?;
sub read_openssh_public_key {
my $filepath = shift or _usage(q{read_openssh_public_key($filepath)});
- my @cmd = (qw{ssh-keygen -e -m PKCS8 -f}, $filepath);
+ my @cmd = ($SSH_KEYGEN, qw{-e -m PKCS8 -f}, $filepath);
- my ($in, $out);
- my $pid = open2($out, $in, @cmd);
-
- close($in);
+ my $out;
+ my $pid = open2($out, undef, @cmd);
waitpid($pid, 0);
my $status = $?;
sub read_openssh_key_fingerprint {
my $filepath = shift or _usage(q{read_openssh_key_fingerprint($filepath)});
- my @cmd = (qw{ssh-keygen -l -E md5 -f}, $filepath);
+ # try with the -E flag first
+ my @cmd = ($SSH_KEYGEN, qw{-l -E md5 -f}, $filepath);
my $out;
- my $pid = open2($out, undef, @cmd);
+ my $err = gensym;
+ my $pid = open3(undef, $out, $err, @cmd);
waitpid($pid, 0);
my $status = $?;
my $exit_code = $status >> 8;
- _croak 'Failed to read SSH2 key fingerprint' if $exit_code != 0;
+ if ($exit_code != 0) {
+ my $error_str = do { local $/; <$err> };
+ _croak 'Failed to read SSH2 key fingerprint' if $error_str !~ /unknown option -- E/s;
+
+ @cmd = ($SSH_KEYGEN, qw{-l -f}, $filepath);
+
+ undef $out;
+ $pid = open2($out, undef, @cmd);
+
+ waitpid($pid, 0);
+ $status = $?;
+
+ $exit_code = $status >> 8;
+ _croak 'Failed to read SSH2 key fingerprint' if $exit_code != 0;
+ }
my $line = do { local $/; <$out> };
chomp $line;
- my ($bits, $fingerprint, $comment, $type) = $line =~ m!^(\d+) MD5:([^ ]+) (.*) \(([^\)]+)\)$!;
+ my ($bits, $fingerprint, $comment, $type) = $line =~ m!^(\d+) (?:MD5:)?([^ ]+) (.*) \(([^\)]+)\)$!;
$fingerprint =~ s/://g;
$filepath = $temp->filename;
}
- my @cmd = (qw{openssl rsautl -decrypt -oaep -in}, $filepath, '-inkey', $privkey);
+ my @cmd = ($OPENSSL, qw{rsautl -decrypt -oaep -in}, $filepath, '-inkey', $privkey);
push @cmd, ('-out', $outfile) if $outfile;
- my ($in, $out);
- my $pid = open2($out, $in, @cmd);
-
- close($in);
+ my $out;
+ my $pid = open2($out, undef, @cmd);
waitpid($pid, 0);
my $status = $?;
close $temp2;
my $keypath = $temp2->filename;
- my @cmd = (qw{openssl rsautl -encrypt -oaep -pubin -inkey}, $keypath, '-in', $filepath);
+ my @cmd = ($OPENSSL, qw{rsautl -encrypt -oaep -pubin -inkey}, $keypath, '-in', $filepath);
push @cmd, ('-out', $outfile) if $outfile;
- my ($in, $out);
- my $pid = open2($out, $in, @cmd);
-
- close($in);
+ my $out;
+ my $pid = open2($out, undef, @cmd);
waitpid($pid, 0);
my $status = $?;
$filepath = $temp->filename;
}
- my @cmd = (qw{openssl aes-256-cbc -d -pass stdin -in}, $filepath);
+ my @cmd = ($OPENSSL, qw{aes-256-cbc -d -pass stdin -md sha256 -in}, $filepath);
push @cmd, ('-out', $outfile) if $outfile;
my ($in, $out);
$filepath = $temp->filename;
}
- my @cmd = (qw{openssl aes-256-cbc -pass stdin -in}, $filepath);
+ my @cmd = ($OPENSSL, qw{aes-256-cbc -pass stdin -md sha256 -in}, $filepath);
push @cmd, ('-out', $outfile) if $outfile;
my ($in, $out);