Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ my %WriteMakefileArgs = (
"NAME" => "XML::Enc",
"PREREQ_PM" => {
"Carp" => 0,
"Crypt::AuthEnc::GCM" => 0,
"Crypt::Mode::CBC" => 0,
"Crypt::OpenSSL::Bignum" => 0,
"Crypt::OpenSSL::RSA" => 0,
Expand All @@ -33,7 +34,7 @@ my %WriteMakefileArgs = (
"File::Which" => 0,
"Test::More" => 0
},
"VERSION" => "0.03",
"VERSION" => "0.04",
"test" => {
"TESTS" => "t/*.t"
}
Expand All @@ -42,6 +43,7 @@ my %WriteMakefileArgs = (

my %FallbackPrereqs = (
"Carp" => 0,
"Crypt::AuthEnc::GCM" => 0,
"Crypt::Mode::CBC" => 0,
"Crypt::OpenSSL::Bignum" => 0,
"Crypt::OpenSSL::RSA" => 0,
Expand Down
2 changes: 1 addition & 1 deletion README
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ NAME
XML::Enc - XML::Enc Encryption Support

VERSION
version 0.03
version 0.04

SYNOPSIS
my $decrypter = XML::Enc->new(
Expand Down
1 change: 1 addition & 0 deletions cpanfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Do not edit this file directly. To change prereqs, edit the `dist.ini` file.

requires "Carp" => "0";
requires "Crypt::AuthEnc::GCM" => "0";
requires "Crypt::Mode::CBC" => "0";
requires "Crypt::OpenSSL::Bignum" => "0";
requires "Crypt::OpenSSL::RSA" => "0";
Expand Down
1 change: 1 addition & 0 deletions dist.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ MIME::Base64 = 0
XML::LibXML = 0
Crypt::Mode::CBC = 0
Crypt::Random = 0
Crypt::AuthEnc::GCM = 0

[Prereqs / TestRequires]
Test::More = 0
Expand Down
111 changes: 81 additions & 30 deletions lib/XML/Enc.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use Carp;
use XML::LibXML;
use Crypt::OpenSSL::RSA;
use Crypt::Mode::CBC;
use Crypt::AuthEnc::GCM;
use MIME::Base64 qw/decode_base64 encode_base64/;
use Crypt::Random qw( makerandom_octet );

use vars qw($VERSION @EXPORT_OK %EXPORT_TAGS $DEBUG);

our $VERSION = '0.03';
our $VERSION = '0.04';

our $DEBUG = 0;

Expand Down Expand Up @@ -52,10 +53,37 @@ XML::Enc - XML Encryption
# 5.2.2 AES - 128 bit initialization vector (IV) (16 bytes)

my %encmethods = (
'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' => { ivsize => 8, keysize => 24, modename => 'DES_EDE' },
'http://www.w3.org/2001/04/xmlenc#aes128-cbc' => { ivsize => '16', keysize => 16, modename => 'AES' },
'http://www.w3.org/2001/04/xmlenc#aes192-cbc' => { ivsize => '16', keysize => 24, modename => 'AES' },
'http://www.w3.org/2001/04/xmlenc#aes256-cbc' => { ivsize => '16', keysize => 32, modename => 'AES' },
'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' => {
ivsize => 8,
keysize => 24,
modename => 'DES_EDE' },
'http://www.w3.org/2001/04/xmlenc#aes128-cbc' => {
ivsize => '16',
keysize => 16,
modename => 'AES' },
'http://www.w3.org/2001/04/xmlenc#aes192-cbc' => {
ivsize => '16',
keysize => 24,
modename => 'AES' },
'http://www.w3.org/2001/04/xmlenc#aes256-cbc' => {
ivsize => '16',
keysize => 32,
modename => 'AES' },
'http://www.w3.org/2009/xmlenc11#aes128-gcm' => {
ivsize => '12',
keysize => 16,
modename => 'AES',
tagsize => 16 },
'http://www.w3.org/2009/xmlenc11#aes192-gcm' => {
ivsize => '12',
keysize => 24,
modename => 'AES',
tagsize => 16 },
'http://www.w3.org/2009/xmlenc11#aes256-gcm' => {
ivsize => '12',
keysize => 32,
modename => 'AES',
tagsize => 16 },
);

=head2 new( ... )
Expand Down Expand Up @@ -293,6 +321,9 @@ sub _setEncryptionMethod {
'aes192-cbc' => 'http://www.w3.org/2001/04/xmlenc#aes192-cbc',
'aes256-cbc' => 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
'tripledes-cbc' => 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc',
'aes128-gcm' => 'http://www.w3.org/2009/xmlenc11#aes128-gcm',
'aes192-gcm' => 'http://www.w3.org/2009/xmlenc11#aes192-gcm',
'aes256-gcm' => 'http://www.w3.org/2009/xmlenc11#aes256-gcm',
);

return exists($methods{$method}) ? $methods{$method} : $methods{'aes256-cbc'};
Expand Down Expand Up @@ -327,7 +358,7 @@ sub _setKeyEncryptionMethod {
'rsa-oaep-mgf1p' => 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p',
);

return exists($methods{$method}) ? $methods{$method} : $methods{'rsa-1_5'};
return exists($methods{$method}) ? $methods{$method} : $methods{'rsa-oaep-mgf1p'};
}

sub _DecryptData {
Expand All @@ -338,23 +369,35 @@ sub _DecryptData {

my $iv;
my $encrypted;
my $cbc;
my $plaintext;

my $ivsize = $encmethods{$method}->{ivsize};
my $tagsize = $encmethods{$method}->{tagsize};

$iv = substr $encrypteddata, 0, $ivsize;
$encrypted = substr $encrypteddata, $ivsize;

# XML Encryption 5.2 Block Encryption Algorithms
# The resulting cipher text is prefixed by the IV.
if (defined $encmethods{$method}){
my $blksize = $encmethods{$method}->{ivsize};
#print "Block Size: ", $blksize;
$iv = substr $encrypteddata, 0, $blksize;
$encrypted = substr $encrypteddata, $blksize;
$cbc = Crypt::Mode::CBC->new($encmethods{$method}->{modename}, 0);
if (defined $encmethods{$method} & $method !~ /gcm/ ){
my $cbc = Crypt::Mode::CBC->new($encmethods{$method}->{modename}, 0);
$plaintext = $self->_remove_padding($cbc->decrypt($encrypted, $key, $iv));
} elsif (defined $encmethods{$method} & $method =~ /gcm/ ){
my $gcm = Crypt::AuthEnc::GCM->new("AES", $key, $iv);

# Note that GCM support for additional authentication
# data is not used in the XML specification.
my $tag = substr $encrypted, - $tagsize;
$encrypted = substr $encrypted, 0, (length $encrypted) - $tagsize;
$plaintext = $gcm->decrypt_add($encrypted);
if ( ! $gcm->decrypt_done($tag) ) {
die "Tag expected did not match returned Tag";
}
} else {
die "Unsupported Encryption Algorithm";
}

my $plaintext = $cbc->decrypt($encrypted, $key, $iv);

return $self->_remove_padding($plaintext);
return $plaintext;
}

sub _EncryptData {
Expand All @@ -363,25 +406,33 @@ sub _EncryptData {
my $data = shift;
my $key = shift;

my $iv;
my $cbc;
my $cipherdata;
my $ivsize = $encmethods{$method}->{ivsize};
my $keysize = $encmethods{$method}->{keysize};

# XML Encryption 5.2 Block Encryption Algorithms
# The resulting cipher text is prefixed by the IV.
if (defined $encmethods{$method}){
my $blksize = $encmethods{$method}->{ivsize};
my $keysize = $encmethods{$method}->{keysize};
$iv = makerandom_octet ( Length => $blksize);
${$key} = makerandom_octet ( Length => $keysize);
$data = $self->_add_padding($data, $blksize);
$cbc = Crypt::Mode::CBC->new($encmethods{$method}->{modename}, 0);
my $iv = makerandom_octet ( Length => $ivsize);
${$key} = makerandom_octet ( Length => $keysize);

if (defined $encmethods{$method} & $method !~ /gcm/ ){
my $cbc = Crypt::Mode::CBC->new($encmethods{$method}->{modename}, 0);
# XML Encryption 5.2 Block Encryption Algorithms
# The resulting cipher text is prefixed by the IV.
$data = $self->_add_padding($data, $ivsize);
$cipherdata = $iv . $cbc->encrypt($data, ${$key}, $iv);
} elsif (defined $encmethods{$method} & $method =~ /gcm/ ){
my $gcm = Crypt::AuthEnc::GCM->new($encmethods{$method}->{modename}, ${$key}, $iv);

# Note that GCM support for additional authentication
# data is not used in the XML specification.
my $encrypted = $gcm->encrypt_add($data);
my $tag = $gcm->encrypt_done();

$cipherdata = $iv . $encrypted . $tag;
} else {
die "Unsupported Encryption Algorithm";
}

my $encrypted = $iv . $cbc->encrypt($data, ${$key}, $iv);

return $encrypted;
return $cipherdata;
}

sub _DecryptKey {
Expand Down
9 changes: 7 additions & 2 deletions t/06-test-encryption-methods.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use strict;
use warnings;
use Test::More tests => 32;
use Test::More tests => 56;
use XML::Enc;
use MIME::Base64 qw/decode_base64 encode_base64/;
use File::Which;
Expand All @@ -13,7 +13,7 @@ my $xml = <<'XML';
XML

my @key_methods = qw/rsa-1_5 rsa-oaep-mgf1p/;
my @data_methods = qw/aes128-cbc aes192-cbc aes256-cbc tripledes-cbc/;
my @data_methods = qw/aes128-cbc aes192-cbc aes256-cbc tripledes-cbc aes128-gcm aes192-gcm aes256-gcm/;

foreach my $km (@key_methods) {
foreach my $dm (@data_methods) {
Expand All @@ -34,6 +34,11 @@ foreach my $km (@key_methods) {

SKIP: {
skip "xmlsec1 not installed", 2 unless which('xmlsec1');
my $version;
if (`xmlsec1 version` =~ m/(\d+\.\d+\.\d+)/) {
$version = $1;
};
skip "xmlsec version 1.2.27 minimum for GCM", 2 if $version lt '1.2.27';
ok( open XML, '>', 'tmp.xml' );
print XML $encrypted;
close XML;
Expand Down
26 changes: 22 additions & 4 deletions t/07-decrypt-xmlsec.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use strict;
use warnings;
use Test::More tests => 40;
use Test::More tests => 70;
use XML::Enc;
use MIME::Base64 qw/decode_base64/;
use File::Which;
Expand All @@ -19,13 +19,26 @@ my $plaintext = <<'UNENCRYPTED';
UNENCRYPTED

my @key_methods = qw/rsa-1_5 rsa-oaep-mgf1p/;
my @data_methods = qw/aes128-cbc aes192-cbc aes256-cbc tripledes-cbc/;
my @data_methods = qw/aes128-cbc aes192-cbc aes256-cbc tripledes-cbc aes128-gcm aes192-gcm aes256-gcm/;

my %uri = (
'aes128-cbc' => 'http://www.w3.org/2001/04/xmlenc#',
'aes192-cbc' => 'http://www.w3.org/2001/04/xmlenc#',
'aes256-cbc' => 'http://www.w3.org/2001/04/xmlenc#',
'tripledes-cbc' => 'http://www.w3.org/2001/04/xmlenc#',
'aes128-gcm' => 'http://www.w3.org/2009/xmlenc11#',
'aes192-gcm' => 'http://www.w3.org/2009/xmlenc11#',
'aes256-gcm' => 'http://www.w3.org/2009/xmlenc11#',
);

my %sesskey = (
'aes128-cbc' => 'aes-128',
'aes192-cbc' => 'aes-192',
'aes256-cbc' => 'aes-256',
'tripledes-cbc' => 'des-192',
'aes128-gcm' => 'aes-128-GCM',
'aes192-gcm' => 'aes-192-GCM',
'aes256-gcm' => 'aes-256-GCM',
);

foreach my $km (@key_methods) {
Expand All @@ -41,7 +54,7 @@ XML Security Library example: Original XML
xmlns="http://www.w3.org/2001/04/xmlenc#"
Type="http://www.w3.org/2001/04/xmlenc#Element">
<EncryptionMethod Algorithm=
"http://www.w3.org/2001/04/xmlenc#$dm"/>
"$uri{$dm}$dm"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm=
Expand Down Expand Up @@ -70,7 +83,7 @@ XML Security Library example: Original XML
xmlns="http://www.w3.org/2001/04/xmlenc#"
Type="http://www.w3.org/2001/04/xmlenc#Content">
<EncryptionMethod Algorithm=
"http://www.w3.org/2001/04/xmlenc#$dm"/>
"$uri{$dm}$dm"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm=
Expand All @@ -91,6 +104,11 @@ CONTENT

SKIP: {
skip "xmlsec1 not installed", 5 unless which('xmlsec1');
my $version;
if (`xmlsec1 version` =~ m/(\d+\.\d+\.\d+)/) {
$version = $1;
};
skip "xmlsec version 1.2.27 minimum for GCM", 5 if $version lt '1.2.27';

ok( open XML, '>', 'plaintext.xml' );
print XML $plaintext;
Expand Down