The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#!/usr/bin/perl
use strict;
use utf8;
use Getopt::Long qw( :config gnu_compat );
use Cwd;
use Carp;
use English qw( -no_match_vars );
our $VERSION = '0.101';
sub cli_error {
my ($error) = @_;
$error =~ s/ at .* line \d+.*//;
print "ERROR: $error\n";
exit(255);
}
sub show_version {
require Crypt::PBE;
require Crypt::CBC;
require Crypt::DES;
print "
pkcs5-tool v$VERSION
CORE
Perl ($PERL_VERSION, $OSNAME)
CRYPT
Crypt::PBE ($Crypt::PBE::VERSION)
Crypt::CBC ($Crypt::CBC::VERSION)
Crypt::DES ($Crypt::DES::VERSION)
Crypt::OpenSSL::AES ($Crypt::OpenSSL::AES::VERSION)
DIGEST
Digest::SHA ($Digest::SHA::VERSION)
Digest::MD5 ($Digest::MD5::VERSION)
Digest::MD2 ($Digest::MD2::VERSION)
";
exit(0);
}
my @options = qw(
help|h
man
version
verbose|v
null|0
input=s
password=s
count=i
hash=s
hmac=s
encryption=s
digest=s
scheme=s
algorithm=s
encrypt
decrypt
list-algorithms
);
my $pbe_mapping = {
'PBEWithMD2AndDES' => { scheme => 'pbes1', hash => 'md2', encryption => 'des' },
'PBEWithMD5AndDES' => { scheme => 'pbes1', hash => 'md5', encryption => 'des' },
'PBEWithSHA1AndDES' => { scheme => 'pbes1', hash => 'sha1', encryption => 'des' },
'PBEWithHmacSHA1AndAES_128' => { scheme => 'pbes2', hmac => 'hmac-sha1', encryption => 'aes-128' },
'PBEWithHmacSHA1AndAES_192' => { scheme => 'pbes2', hmac => 'hmac-sha1', encryption => 'aes-192' },
'PBEWithHmacSHA1AndAES_256' => { scheme => 'pbes2', hmac => 'hmac-sha1', encryption => 'aes-256' },
'PBEWithHmacSHA224AndAES_128' => { scheme => 'pbes2', hmac => 'hmac-sha224', encryption => 'aes-128' },
'PBEWithHmacSHA224AndAES_192' => { scheme => 'pbes2', hmac => 'hmac-sha224', encryption => 'aes-192' },
'PBEWithHmacSHA224AndAES_256' => { scheme => 'pbes2', hmac => 'hmac-sha224', encryption => 'aes-256' },
'PBEWithHmacSHA256AndAES_128' => { scheme => 'pbes2', hmac => 'hmac-sha256', encryption => 'aes-128' },
'PBEWithHmacSHA256AndAES_192' => { scheme => 'pbes2', hmac => 'hmac-sha256', encryption => 'aes-192' },
'PBEWithHmacSHA256AndAES_256' => { scheme => 'pbes2', hmac => 'hmac-sha256', encryption => 'aes-256' },
'PBEWithHmacSHA384AndAES_128' => { scheme => 'pbes2', hmac => 'hmac-sha384', encryption => 'aes-128' },
'PBEWithHmacSHA384AndAES_192' => { scheme => 'pbes2', hmac => 'hmac-sha384', encryption => 'aes-192' },
'PBEWithHmacSHA384AndAES_256' => { scheme => 'pbes2', hmac => 'hmac-sha384', encryption => 'aes-256' },
'PBEWithHmacSHA512AndAES_128' => { scheme => 'pbes2', hmac => 'hmac-sha512', encryption => 'aes-128' },
'PBEWithHmacSHA512AndAES_192' => { scheme => 'pbes2', hmac => 'hmac-sha512', encryption => 'aes-192' },
'PBEWithHmacSHA512AndAES_256' => { scheme => 'pbes2', hmac => 'hmac-sha512', encryption => 'aes-256' },
};
my $options = {};
GetOptions( $options, @options ) or pod2usage( -verbose => 0 );
pod2usage( -exitstatus => 0, -verbose => 2 ) if ( $options->{man} );
pod2usage( -exitstatus => 0, -verbose => 0 ) if ( $options->{help} );
show_version if ( $options->{version} );
if ( $options->{'list-algorithms'} ) {
print join( "\n", sort keys %{$pbe_mapping} );
print "\n";
exit(0);
}
pod2usage( -exitstatus => 1, -verbose => 0 ) if ( !$options->{algorithm} );
my $pbe_params = $pbe_mapping->{ $options->{algorithm} };
if ( !$pbe_params ) {
print "ERROR: Invalid algorithm\n\n";
pod2usage( -exitstatus => 1, -verbose => 0 );
}
my $pbes = undef;
if ( $pbe_params->{scheme} eq 'pbes1' ) {
$pbes = Crypt::PBE::PBES1->new(
password => $options->{password},
count => $options->{count} || 1_000,
hash => $pbe_params->{hash},
encryption => $pbe_params->{encryption},
);
}
if ( $pbe_params->{scheme} eq 'pbes2' ) {
$pbes = Crypt::PBE::PBES2->new(
password => $options->{password},
count => $options->{count} || 1_000,
hmac => $pbe_params->{hmac},
encryption => $pbe_params->{encryption},
);
}
if ( $options->{encrypt} ) {
print encode_base64 $pbes->encrypt( $options->{input} ), '';
print "\0" if ( $options->{null} );
print "\n" if ( !$options->{null} );
}
if ( $options->{decrypt} ) {
print $pbes->decrypt( decode_base64 $options->{input} );
print "\0" if ( $options->{null} );
print "\n" if ( !$options->{null} );
}
exit(0);
__END__
=encoding utf-8
=head1 NAME
pkcs5-tool - PKCS#5 Password-Based Encryption Tools
=head1 SYNOPSIS
pkcs5-tool [OPTIONS]
Options:
--help Brief help message
--man Full documentation
--verbose Print more info during run
--version Print version
--algorithm PBE algorithm
--list-algorithms List PBE algorithm
-0, --null Return NULL char instead of new line
--password Password
--input Input data
--encrypt
--decrypt
Examples:
Encrypt:
pkcs5-tool --algorithm PBEWithHmacSHA1AndAES_128 --password mypassword --input secret --encrypt
Decrypt:
pkcs5-tool --algorithm PBEWithHmacSHA1AndAES_128 --password mypassword --input <Base64 encrypted data> --decrypt
=head1 DESCRIPTION
C<pkcs5-tool> PKCS#% Password-Based Encryption Tools
=head1 AUTHOR
L<Giuseppe Di Terlizzi|https://metacpan.org/author/gdt>
=head1 COPYRIGHT AND LICENSE
Copyright © 2018-2020 L<Giuseppe Di Terlizzi|https://metacpan.org/author/gdt>
You may use and distribute this module according to the same terms
that Perl is distributed under.