Skip to content
This repository has been archived by the owner on Jan 24, 2023. It is now read-only.

Commit

Permalink
[#4] Support encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
ioanrogers committed Jul 28, 2016
1 parent 616d539 commit 7260c44
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 5 deletions.
66 changes: 63 additions & 3 deletions lib/Crypt/PKCS11/Easy.pm
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ has _default_mech => (
is => 'ro',
default => sub {
{
sign => CKM_SHA1_RSA_PKCS,
verify => CKM_SHA1_RSA_PKCS,
digest => CKM_SHA_1,
digest => CKM_SHA_1,
encrypt => CKM_RSA_PKCS,
sign => CKM_SHA1_RSA_PKCS,
verify => CKM_SHA1_RSA_PKCS,

};
},
);
Expand Down Expand Up @@ -281,6 +283,7 @@ sub _build__key {
given ($self->function) {
return $self->get_signing_key($self->key) when 'sign';
return $self->get_verification_key($self->key) when 'verify';
return $self->get_encryption_key($self->key) when 'encrypt';
default {
die "Unknown key type: " . $self->function;
}
Expand Down Expand Up @@ -605,6 +608,28 @@ sub get_verification_key {
return $self->_get_key($label, $tmpl);
}

=method C<get_encryption_key(Str $label)>
Will look for a key matching with a label matching C<$label> which can be used
for encryption.
The returned key is a L<Crypt::PKCS11::Object>.
=cut

sub get_encryption_key {
my ($self, $label) = @_;

$log->debug('Looking for an encryption key');

my $tmpl =
Crypt::PKCS11::Attributes->new->push(
Crypt::PKCS11::Attribute::Encrypt->new->set(1),
);

return $self->_get_key($label, $tmpl);
}

sub _get_pss_params {
my ($self, $hash, $hash_number) = @_;

Expand Down Expand Up @@ -901,6 +926,41 @@ sub get_mechanisms {
return \%mech;
}

=method C<encrypt((data => 'some data' | file => '/path'), mech => 'RSA_PKCS'?)>
Returns encrypted data. The data to be encrypted is either passed as a scalar
in C<data>, or in C<file> which can be a string path or a L<Path::Tiny> object.
A PKCS#11 mechanism can optionally be specified as a string and without the
leading 'CKM_'.
my $encrypted_data = $hsm->sign(file => $file, mech => 'RSA_PKCS');
my $encrypted_data = $hsm->sign(data => 'SIGN ME');
=cut

sub encrypt {
my ($self, %args) = @_;

$self->_handle_common_args(\%args);

if (!$args{mech}) {
$args{mech} = Crypt::PKCS11::CK_MECHANISM->new;
$args{mech}->set_mechanism($self->_default_mech->{encrypt});
}

# TODO check key size and size of data to be encrypted and look up max sizes for mechanism
# XXX trying to encrypt data that is too big returns a CKR_GENERAL_ERROR, which is super-unhelpful

$self->_session->EncryptInit($args{mech}, $self->_key)
or die "Failed to init encryption: " . $self->_session->errstr;

my $encrypted_data = $self->_session->Encrypt($args{data})
or die "Failed to encrypt: " . $self->_session->errstr;

return $encrypted_data;
}

1;

__END__
Expand Down
17 changes: 17 additions & 0 deletions t/02-basic.t
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,24 @@ mUwq3aC/GjFW+pOLRYevQ2UwJiZmcVtP4nDD9Vt/exZS/ggM4HnaoGm8QyGnhlk3

$key_file = path 't/keys/1024_sign_pub.pem';
ok $self->openssl_verify($key_file, $sig_file, $data_file);
};

test encryption => sub {
my $self = shift;

my $data_file = path 't/data/64B.file';

my $pkcs11 = $self->_new_pkcs11('encryption_key', 0, 'encrypt');

ok my $encrypted_data = $pkcs11->encrypt(file => $data_file),
'Encrypted with defaults (RSA_PKCS)';

my $private_key_file = path 't/keys/1024_enc.pem';
ok my $decrypted_data =
$self->openssl_decrypt($private_key_file, $encrypted_data),
'Decrypted using openssl';

is $decrypted_data, $data_file->slurp_raw, 'Successful round-trip';
};

run_me;
Expand Down
1 change: 1 addition & 0 deletions t/data/64B.file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
P�AbxX�ޢ�}�Df�P�v���+r��l���$���d�«0"�80�\�'���v���O��a3�
24 changes: 22 additions & 2 deletions t/lib/CommonTest.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ use Test::TempDir::Tiny;
use Path::Tiny;
use IPC::Cmd 0.92 qw/can_run run run_forked/;

has _openssl => (
is => 'ro',
lazy => 1,
default => sub {
my $p = can_run 'openssl';
BAIL_OUT "openssl not found, cannot continue" unless $p;
return path $p;
},
);

has workdir => (
is => 'ro',
clearer => 1,
Expand Down Expand Up @@ -141,10 +151,20 @@ sub openssl_verify {
$self->_openssl, 'dgst', '-sha1', '-verify',
$key_file, '-signature', $sig_file, $data_file
];
my $output = run_forked $openssl_cmd,
{verbose => $ENV{TEST_DEBUG}, child_stdin => $data_file->slurp_raw};

return run command => $openssl_cmd, verbose => $ENV{TEST_DEBUG};
}

sub openssl_decrypt {
my ($self, $private_key_file, $encrypted_data) = @_;

my $openssl_cmd =
[$self->_openssl, 'rsautl', '-decrypt', '-inkey', $private_key_file];

my $output = run_forked $openssl_cmd,
{verbose => $ENV{TEST_DEBUG}, child_stdin => $encrypted_data};
chomp $output->{stdout};

return $output->{stdout};
}

Expand Down

0 comments on commit 7260c44

Please sign in to comment.