diff --git a/.travis.yml b/.travis.yml
index 4a1c5331..4c975328 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,21 +2,41 @@ sudo: false
language: php
+sudo: required
+dist: trusty
+group: edge
+
+env:
+ global:
+ COMPOSER_DISABLE_XDEBUG_WARN=true
+
+cache:
+ directories:
+ - $HOME/.composer/cache
+
matrix:
fast_finish: true
include:
- - php: 5.3
- - php: 5.4
- - php: 5.5
- - php: 5.6
- env:
- - EXECUTE_COVERAGE=true
- - php: 7
- - php: hhvm
+ - php: 7.0
+ - php: 7.1
+ env: EXECUTE_COVERAGE=true
+ - php: nightly
+ - php: hhvm-3.12
+ env: COMPOSER_INSTALL_FLAGS=--ignore-platform-reqs
+ - php: hhvm-3.15
+ env: COMPOSER_INSTALL_FLAGS=--ignore-platform-reqs
+ - php: hhvm-nightly
+ env: COMPOSER_INSTALL_FLAGS=--ignore-platform-reqs
+ allow-failures:
+ - php: nightly
+ - php: hhvm-nightly
+
+install:
+ - travis_retry composer install --prefer-dist $COMPOSER_INSTALL_FLAGS
script:
- - if [[ $EXECUTE_COVERAGE == 'true' ]]; then phpunit --coverage-clover clover.xml tests; fi
- - if [[ $EXECUTE_COVERAGE != 'true' ]]; then phpunit tests; fi
+ - if [[ $EXECUTE_COVERAGE == 'true' ]]; then vendor/bin/phpunit --coverage-clover clover.xml; fi
+ - if [[ $EXECUTE_COVERAGE != 'true' ]]; then vendor/bin/phpunit; fi
after_success:
- if [[ $EXECUTE_COVERAGE == 'true' ]]; then bash <(curl -s https://codecov.io/bash); fi
diff --git a/composer.json b/composer.json
index 1fa8dd19..e4e6371c 100644
--- a/composer.json
+++ b/composer.json
@@ -14,11 +14,16 @@
"RobRichards\\XMLSecLibs\\": "src"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "RobRichards\\XMLSecLibs\\Tests\\": "tests/src"
+ }
+ },
"require": {
- "php": ">= 5.3"
- },
- "suggest": {
- "ext-openssl": "OpenSSL extension",
- "ext-mcrypt": "MCrypt extension"
+ "ext-openssl": "*",
+ "php": ">= 7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7.4"
}
}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 00000000..cf81d6e4
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,19 @@
+
+
+
+
+ tests/
+
+
+ tests/src/
+
+
+
+
+ src/
+
+
+
+
+
+
diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php
index 380ffcbe..12e90b46 100644
--- a/src/XMLSecEnc.php
+++ b/src/XMLSecEnc.php
@@ -315,7 +315,7 @@ public function encryptKey($srcKey, $rawKey, $append=true)
$this->encKey = $encKey;
}
$encMethod = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod'));
- $encMethod->setAttribute('Algorithm', $srcKey->getAlgorith());
+ $encMethod->setAttribute('Algorithm', $srcKey->getAlgorithm());
if (! empty($srcKey->name)) {
$keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'));
$keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name));
diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php
index 5767cfc8..476eca5b 100644
--- a/src/XMLSecurityDSig.php
+++ b/src/XMLSecurityDSig.php
@@ -152,7 +152,7 @@ private function getXPathObj()
*/
public static function generateGUID($prefix='pfx')
{
- $uuid = md5(uniqid(mt_rand(), true));
+ $uuid = bin2hex(random_bytes(16));
$guid = $prefix.substr($uuid, 0, 8)."-".
substr($uuid, 8, 4)."-".
substr($uuid, 12, 4)."-".
diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php
index 9bb914a0..1509611c 100644
--- a/src/XMLSecurityKey.php
+++ b/src/XMLSecurityKey.php
@@ -111,32 +111,36 @@ public function __construct($type, $params=null)
{
switch ($type) {
case (self::TRIPLEDES_CBC):
- $this->cryptParams['library'] = 'mcrypt';
- $this->cryptParams['cipher'] = MCRYPT_TRIPLEDES;
- $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['cipher'] = 'des-ede3-cbc';
+ $this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
$this->cryptParams['keysize'] = 24;
+ $this->cryptParams['blocksize'] = 8;
break;
case (self::AES128_CBC):
- $this->cryptParams['library'] = 'mcrypt';
- $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
- $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['cipher'] = 'aes-128-cbc';
+ $this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
$this->cryptParams['keysize'] = 16;
+ $this->cryptParams['blocksize'] = 16;
break;
case (self::AES192_CBC):
- $this->cryptParams['library'] = 'mcrypt';
- $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
- $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['cipher'] = 'aes-192-cbc';
+ $this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
$this->cryptParams['keysize'] = 24;
+ $this->cryptParams['blocksize'] = 16;
break;
case (self::AES256_CBC):
- $this->cryptParams['library'] = 'mcrypt';
- $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
- $this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+ $this->cryptParams['library'] = 'openssl';
+ $this->cryptParams['cipher'] = 'aes-256-cbc';
+ $this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
$this->cryptParams['keysize'] = 32;
+ $this->cryptParams['blocksize'] = 16;
break;
case (self::RSA_1_5):
$this->cryptParams['library'] = 'openssl';
@@ -235,9 +239,8 @@ public function getSymmetricKeySize()
}
/**
- * Generates a session key using the openssl-extension or using the mcrypt-extension as a fallback.
- * In case of using DES3-CBC the key is checked for a proper parity bits set - Mcrypt doesn't care about the parity bits,
- * but others may care.
+ * Generates a session key using `random_bytes`.
+ * In case of using DES3-CBC the key is checked for a proper parity bits set
* @return string
* @throws Exception
*/
@@ -247,20 +250,11 @@ public function generateSessionKey()
throw new Exception('Unknown key size for type "' . $this->type . '".');
}
$keysize = $this->cryptParams['keysize'];
-
- if (function_exists('openssl_random_pseudo_bytes')) {
- /* We have PHP >= 5.3 - use openssl to generate session key. */
- $key = openssl_random_pseudo_bytes($keysize);
- } else {
- /* Generating random key using iv generation routines */
- $key = mcrypt_create_iv($keysize, MCRYPT_RAND);
- }
-
+ $key = random_bytes($keysize);
+
+ // Make sure that the generated key has the proper parity bits set.
if ($this->type === self::TRIPLEDES_CBC) {
- /* Make sure that the generated key has the proper parity bits set.
- * Mcrypt doesn't care about the parity bits, but others may care.
- */
- for ($i = 0; $i < strlen($key); $i++) {
+ for ($i = 0; $i < $this->byteStrLen($key); $i++) {
$byte = ord($key[$i]) & 0xfe;
$parity = 1;
for ($j = 1; $j < 8; $j++) {
@@ -270,7 +264,7 @@ public function generateSessionKey()
$key[$i] = chr($byte);
}
}
-
+
$this->key = $key;
return $key;
}
@@ -331,8 +325,9 @@ public function loadKey($key, $isFile=false, $isCert = false)
} else {
$this->x509Certificate = null;
}
- if ($this->cryptParams['library'] == 'openssl') {
- if ($this->cryptParams['type'] == 'public') {
+
+ switch ($this->cryptParams['type']) {
+ case 'public':
if ($isCert) {
/* Load the thumbprint if this is an X509 certificate. */
$this->X509Thumbprint = self::getRawThumbprint($this->key);
@@ -341,73 +336,53 @@ public function loadKey($key, $isFile=false, $isCert = false)
if (! $this->key) {
throw new Exception('Unable to extract public key');
}
- } else {
+ break;
+
+ case 'private':
$this->key = openssl_get_privatekey($this->key, $this->passphrase);
- }
- } else if ($this->cryptParams['cipher'] == MCRYPT_RIJNDAEL_128) {
- /* Check key length */
- switch ($this->type) {
- case (self::AES256_CBC):
- if (strlen($this->key) < 25) {
+ break;
+
+ case'symmetric':
+ if ($this->byteStrLen($this->key) < $this->cryptParams['keysize']) {
throw new Exception('Key must contain at least 25 characters for this cipher');
}
break;
- case (self::AES192_CBC):
- if (strlen($this->key) < 17) {
- throw new Exception('Key must contain at least 17 characters for this cipher');
- }
- break;
- }
+ default:
+ throw new Exception('Unknown type');
}
}
/**
- * Encrypts the given data (string) using the mcrypt-extension
+ * Encrypts the given data (string) using the openssl-extension
*
* @param string $data
* @return string
+ * @throws Exception
*/
- private function encryptMcrypt($data)
+ private function encryptSymmetric($data)
{
- $td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
- $this->iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
- mcrypt_generic_init($td, $this->key, $this->iv);
- if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) {
- $bs = mcrypt_enc_get_block_size($td);
- for ($datalen0 = $datalen = strlen($data); (($datalen % $bs) != ($bs - 1)); $datalen++)
- $data .= chr(mt_rand(1, 127));
- $data .= chr($datalen - $datalen0 + 1);
+ $this->iv = random_bytes(openssl_cipher_iv_length($this->cryptParams['cipher']));
+ $data = $this->padISO10126($data, $this->cryptParams['blocksize']);
+ $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
+ if (false === $encrypted) {
+ throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string());
}
- $encrypted_data = $this->iv.mcrypt_generic($td, $data);
- mcrypt_generic_deinit($td);
- mcrypt_module_close($td);
- return $encrypted_data;
+ return $this->iv . $encrypted;
}
/**
- * Decrypts the given data (string) using the mcrypt-extension
+ * Encrypts the given data (string) using the openssl-extension
*
* @param string $data
* @return string
+ * @throws Exception
*/
- private function decryptMcrypt($data)
+ private function encryptPublic($data)
{
- $td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
- $iv_length = mcrypt_enc_get_iv_size($td);
-
- $this->iv = substr($data, 0, $iv_length);
- $data = substr($data, $iv_length);
-
- mcrypt_generic_init($td, $this->key, $this->iv);
- $decrypted_data = mdecrypt_generic($td, $data);
- mcrypt_generic_deinit($td);
- mcrypt_module_close($td);
- if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) {
- $dataLen = strlen($decrypted_data);
- $paddingLength = substr($decrypted_data, $dataLen - 1, 1);
- $decrypted_data = substr($decrypted_data, 0, $dataLen - ord($paddingLength));
+ if (! openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string());
}
- return $decrypted_data;
+ return $encrypted;
}
/**
@@ -417,18 +392,12 @@ private function decryptMcrypt($data)
* @return string
* @throws Exception
*/
- private function encryptOpenSSL($data)
+ private function encryptPrivate($data)
{
- if ($this->cryptParams['type'] == 'public') {
- if (! openssl_public_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) {
- throw new Exception('Failure encrypting Data');
- }
- } else {
- if (! openssl_private_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) {
- throw new Exception('Failure encrypting Data');
- }
+ if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string());
}
- return $encrypted_data;
+ return $encrypted;
}
/**
@@ -438,20 +407,109 @@ private function encryptOpenSSL($data)
* @return string
* @throws Exception
*/
- private function decryptOpenSSL($data)
+ private function decryptSymmetric($data)
{
- if ($this->cryptParams['type'] == 'public') {
- if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
- throw new Exception('Failure decrypting Data');
- }
- } else {
- if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
- throw new Exception('Failure decrypting Data');
- }
+ $iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']);
+ $this->iv = $this->byteSubStr($data, 0, $iv_length);
+ $data = $this->byteSubStr($data, $iv_length);
+ $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
+ if (false === $decrypted) {
+ throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string());
+ }
+ return $this->unpadISO10126($decrypted);
+ }
+
+ /**
+ * Decrypts the given data (string) using the openssl-extension
+ *
+ * @param string $data
+ * @return string
+ * @throws Exception
+ */
+ private function decryptPublic($data)
+ {
+ if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string);
}
return $decrypted;
}
+ /**
+ * Decrypts the given data (string) using the openssl-extension
+ *
+ * @param string $data
+ * @return string
+ * @throws Exception
+ */
+ private function decryptPrivate($data)
+ {
+ if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
+ throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string);
+ }
+ return $decrypted;
+ }
+
+ /**
+ * ISO 10126 Padding
+ *
+ * @param string $data
+ * @param integer $blockSize
+ * @throws Exception
+ * @return string
+ */
+ private function padISO10126($data, $blockSize)
+ {
+ if ($blockSize > 256) {
+ throw new Exception('Block size higher than 256 not allowed');
+ }
+ $padChr = $blockSize - ($this->byteStrLen($data) % $blockSize);
+ $pattern = chr($padChr);
+ return $data . str_repeat($pattern, $padChr);
+ }
+
+ /**
+ * Remove ISO 10126 Padding
+ *
+ * @param string $data
+ * @return string
+ */
+ private function unpadISO10126($data)
+ {
+ $padChr = $this->byteSubStr($data, -1);
+ $padLen = ord($padChr);
+ return $this->byteSubStr($data, 0, -$padLen);
+ }
+
+ /**
+ * Byte strlen wrapper to compensate for mbstring.func_overload
+ *
+ * @param string $string
+ * @return integer
+ */
+ private function byteStrLen($string)
+ {
+ return function_exists('mb_byteStrLen') ?
+ mb_strlen($string, '8bit') : strlen($string);
+ }
+
+ /**
+ * Byte substr wrapper to compensate for mbstring.func_overload
+ *
+ * @param string $string
+ * @param integer $start
+ * @param integer $length
+ * @return string
+ */
+ private function byteSubStr($string, $start, $length = null)
+ {
+ if (null === $length) {
+ $length = $this->byteStrLen($string);
+ }
+
+ return function_exists('mb_byteSubStr') ?
+ mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length);
+ }
+
/**
* Signs the given data (string) using the openssl-extension
*
@@ -488,34 +546,44 @@ private function verifyOpenSSL($data, $signature)
}
/**
- * Encrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
+ * Encrypts the given data (string) using openssl, depending on the library assigned to algorithm in the contructor.
*
* @param string $data
* @return mixed|string
+ * @throws Exception
*/
public function encryptData($data)
{
- switch ($this->cryptParams['library']) {
- case 'mcrypt':
- return $this->encryptMcrypt($data);
- case 'openssl':
- return $this->encryptOpenSSL($data);
+ switch ($this->cryptParams['type']) {
+ case 'symmetric':
+ return $this->encryptSymmetric($data);
+ case 'public':
+ return $this->encryptPublic($data);
+ case 'private':
+ return $this->encryptPrivate($data);
+ default:
+ throw new Exception('Invalid encryption type');
}
}
/**
- * Decrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
+ * Decrypts the given data (string) using openssl, depending on the library assigned to algorithm in the contructor.
*
* @param string $data
* @return mixed|string
+ * @throws Exception
*/
public function decryptData($data)
{
- switch ($this->cryptParams['library']) {
- case 'mcrypt':
- return $this->decryptMcrypt($data);
- case 'openssl':
- return $this->decryptOpenSSL($data);
+ switch ($this->cryptParams['type']) {
+ case 'symmetric':
+ return $this->decryptSymmetric($data);
+ case 'public':
+ return $this->decryptPublic($data);
+ case 'private':
+ return $this->decryptPrivate($data);
+ default:
+ throw new Exception('Invalid openssl decryption type');
}
}
@@ -588,7 +656,7 @@ public static function makeAsnSegment($type, $string)
break;
}
- $length = strlen($string);
+ $length = $this->byteStrLen($string);
if ($length < 128) {
$output = sprintf("%c%c%s", $type, $length, $string);
@@ -623,7 +691,7 @@ public static function convertRSA($modulus, $exponent)
$publicKeyInfoBase64 = base64_encode($publicKeyInfo);
$encoding = "-----BEGIN PUBLIC KEY-----\n";
$offset = 0;
- while ($segment = substr($publicKeyInfoBase64, $offset, 64)) {
+ while ($segment = $this->byteSubStr($publicKeyInfoBase64, $offset, 64)) {
$encoding = $encoding.$segment."\n";
$offset += 64;
}
diff --git a/tests/encrypteddata-node-order.phpt b/tests/encrypteddata-node-order.phpt
index dce2ee14..4d681002 100644
--- a/tests/encrypteddata-node-order.phpt
+++ b/tests/encrypteddata-node-order.phpt
@@ -5,7 +5,7 @@ Makes sure that the child elements of EncryptedData appear in
the correct order.
--FILE--
+
+jUzXhKjpKTTOavStGjH7+6lLoShei5Dk9B+Bg0hfUy4MFV3aq8E/HdfBYh36vm6bFroHF+6KP+K7Z2S9odN1zsbjF5oQjXLHDYnDEerMGiVbhlkXXaTWckThchZV8WoowXwSIkg8FjU01P+p8F6+lg9CC1h5B0xOWe9hQ3M0JSMSN1BZ15PVwXARDi/LuxJqf9dDZhqCFoYRUR7Q3612TNSgU/livb2VcRY7EbyRpuuSGfSjXNQPM1d/OlsfmZUYhd7aFO/OkHeUoFEx+BKkkRzrAfkRt7M5ilj7UHilNfzRsxSx0EQG3dfbJ0pbBgGgmiM9iLYnj087rzluN+x8kw==
+
+ iUIRz5HJvgGADfkQAqXBC8WjmhoofuLAJedYn8DfwA614RQX5iB4PYw7GiVng+m/MVGYqvoudsg6lNprV0vN8Q==
+
+
diff --git a/tests/src/Fixture/basic-doc-encrypted-aes128-cbc.xml b/tests/src/Fixture/basic-doc-encrypted-aes128-cbc.xml
new file mode 100644
index 00000000..d07ebaa8
--- /dev/null
+++ b/tests/src/Fixture/basic-doc-encrypted-aes128-cbc.xml
@@ -0,0 +1,7 @@
+
+
+pKChAdt8YXFRkOfgARrW2IEwlnK1ZWEqnSvVhKK9VSiC5yICrf/dHL2BmkjJvG1wbOqBfJXCDCn/F+CeVDcZBa4kg/oQeUpIF7FMYaUK7Q9529uni/P5tMegQkOWeD7M76vlt5TXXbhRV/jZqCa5W5WIkhns53/2e97FKWOujPxrnydhvgzP9ztOPjOgbqIeJBkW432XQkgOSq6AANgfsgwrugQSusQcsJzuYRRhfSKTkH79t2sCGDlqV9XlAs1DOv2+elWEyL5G58/nDwaecRoZgo3EV4EdOudeNesvrNnZrsNRaR/qchUH+G+R9RDnXO4l3qookkH+6o222osxcQ==
+
+ r0YRkEixBnAKU032/ux7avHcVTH1CIIyKaPA2qr4KlIs0LVZp5CuwQKRRi6lji4cnaFbH4jETtJhMSEfbpSdvg==
+
+
diff --git a/tests/src/Fixture/basic-doc-encrypted-aes192-cbc.xml b/tests/src/Fixture/basic-doc-encrypted-aes192-cbc.xml
new file mode 100644
index 00000000..fb795ada
--- /dev/null
+++ b/tests/src/Fixture/basic-doc-encrypted-aes192-cbc.xml
@@ -0,0 +1,7 @@
+
+
+GXVyq5+hysMutP0IXxmJ3SZxBoLwWpMkgvqUYdiZGpH18Y8apPSetryE6wy8wgblFF0FnzpZttDdMWV646M+YhJtXXc+PaSpeYUM5qCHX2s0mROvmq1NGybNgy3tC1CuYnETAr+nfBt4vaQkcF+gBG5fd4Z2lkk9ZuQS+Fsyimtt59wVQoNfwkddBgphMp/XtUa120+c5cQpkVvTAUIs1AWnpcxFL6lOdLVND+59n2GGSkWJLcCrv96LO3aTPeSCnAWCx6wBSVVRSkhVpqC1zDTqz6Nq4hlUvcMt7rzTq6NMA6WUZOtG1iHiIrYDtqyHwOKYAVKnIKjPhLLewWMQ9g==
+
+ ptSPO8ShXZrxkIVDvFwAuNAWEZIPKI/VpmsdWsVH/nQfMWpmFr9RKdzh6ezhr73i1sB6VZkafV6hErzEHVv+5w==
+
+
diff --git a/tests/src/Fixture/basic-doc-encrypted-tripledes-cbc.xml b/tests/src/Fixture/basic-doc-encrypted-tripledes-cbc.xml
new file mode 100644
index 00000000..8d24927e
--- /dev/null
+++ b/tests/src/Fixture/basic-doc-encrypted-tripledes-cbc.xml
@@ -0,0 +1,7 @@
+
+
+11Tlnb3B2M+N5Uu7k3iozyVVVy7+Ylrzex79A0CiaBIWzdag36X6uk8ukdYiOxbGrb1iL0M/48h3pf2DA3gUj13d8cma3e2GprIphFWl57FJcBd5n/E/PRuVR6CfBqxzHTYKWuVntOkiA+l4QMWozmTNMmv3zWphwk5eMerob3kRPs5tFA+IFes9B++hKx3USXUVLfLJIhEf0AZB9o3eyZeG3pqzF6mkiy6epZKGM6JPA5oZJDKxCk+jscc4pDXftqIDdTu7Ukjbt2iD+OcMEO3zwpIoz8w0SksLH0WRRgZK/naPRSDCKHlqc/2nJaY8CcoLvC+pN93QaKHWzh+JHA==
+
+ D+3dKq7MFK7U+8bqdlyRcvO12JV5Lahl5ALhF5eJXSfi+cbYKRbkRjvJsMKPp2Mk
+
+
diff --git a/tests/src/TestCase.php b/tests/src/TestCase.php
new file mode 100644
index 00000000..4f29e4cb
--- /dev/null
+++ b/tests/src/TestCase.php
@@ -0,0 +1,23 @@
+
+ *
+ */
+class TestCase extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Get fixture filename
+ * @param string $file File name
+ * @param boolean $legacy Use legacy file location
+ * @return string
+ */
+ protected function getFixtureFileName($file, $legacy = false)
+ {
+ return $legacy ? __DIR__ . '/../' . $file : __DIR__ . '/Fixture/' . $file;
+ }
+}
diff --git a/tests/src/XMLSecEncTest.php b/tests/src/XMLSecEncTest.php
new file mode 100644
index 00000000..d3667752
--- /dev/null
+++ b/tests/src/XMLSecEncTest.php
@@ -0,0 +1,241 @@
+
+ *
+ */
+class XMLSecEncTest extends TestCase
+{
+ /**
+ * Basic encryption
+ * (taken from xmlsec-encrypt.phpt)
+ *
+ * @param string $source Source filename
+ * @param string $keyType Security key type
+ *
+ * @dataProvider providerTestBasicEncryptDecrypt
+ * @group functional
+ */
+ public function testBasicEncrypt($source, $keyType)
+ {
+ $dom = new DOMDocument();
+ $dom->load($source);
+
+ $objKey = new XMLSecurityKey($keyType);
+ $objKey->generateSessionKey();
+
+ $enc = new XMLSecEnc();
+ $enc->setNode($dom->documentElement);
+ $enc->encryptKey($this->createSiteKey(), $objKey);
+
+ $enc->type = XMLSecEnc::Element;
+ $encNode = $enc->encryptNode($objKey);
+
+ $this->assertSame('EncryptedData', $dom->documentElement->localName);
+ $this->assertSame('EncryptedData', $encNode->localName);
+ $this->assertSame(XMLSecEnc::XMLENCNS, $encNode->namespaceURI);
+ }
+
+ /**
+ * Basic encryption content
+ * (taken from xmlsec-encrypt-content.phpt)
+ *
+ * @param string $source Source filename
+ * @param string $keyType Security key type
+ *
+ * @dataProvider providerTestBasicEncryptDecrypt
+ * @group functional
+ */
+ public function testBasicEncryptContent($source, $keyType)
+ {
+ $dom = new DOMDocument();
+ $dom->load($source);
+
+ $objKey = new XMLSecurityKey($keyType);
+ $objKey->generateSessionKey();
+
+ $enc = new XMLSecEnc();
+ $enc->setNode($dom->documentElement);
+ $enc->encryptKey($this->createSiteKey(), $objKey);
+
+ $enc->type = XMLSecEnc::Content;
+ $encNode = $enc->encryptNode($objKey);
+
+ $this->assertSame('Root', $dom->documentElement->localName);
+ $this->assertSame('EncryptedData', $encNode->localName);
+ $this->assertSame(XMLSecEnc::XMLENCNS, $encNode->namespaceURI);
+ }
+
+ /**
+ * Basic encryption content without modifying original data
+ * (taken from xmlsec-encrypt-noreplace.phpt)
+ *
+ * @param string $source Source filename
+ * @param string $keyType Security key type
+ *
+ * @dataProvider providerTestBasicEncryptDecrypt
+ * @group functional
+ */
+ public function testBasicEncryptNoModify($source, $keyType)
+ {
+ $dom = new DOMDocument();
+ $dom->load($source);
+ $origData = $dom->saveXML();
+
+ $objKey = new XMLSecurityKey($keyType);
+ $objKey->generateSessionKey();
+
+ $enc = new XMLSecEnc();
+ $enc->setNode($dom->documentElement);
+ $enc->encryptKey($this->createSiteKey(), $objKey);
+
+ $enc->type = XMLSecEnc::Element;
+ $encNode = $enc->encryptNode($objKey, false);
+
+ $this->assertSame($origData, $dom->saveXML());
+ $this->assertSame('EncryptedData', $encNode->localName);
+ $this->assertSame(XMLSecEnc::XMLENCNS, $encNode->namespaceURI);
+ }
+
+ /**
+ * Basic decryption content
+ * (taken from xmlsec-decrypt-content.phpt)
+ *
+ * @param string $source Source filename
+ * @param string $keyType Security key type
+ * @param string $encrypted Encrypted filename
+ *
+ * @dataProvider providerTestBasicEncryptDecrypt
+ * @group functional
+ */
+ public function testBasicDecrypt($source, $keyType, $encrypted)
+ {
+ $doc = new DOMDocument();
+ $doc->load($encrypted);
+
+ $objenc = new XMLSecEnc();
+ $encData = $objenc->locateEncryptedData($doc);
+
+ $objenc->setNode($encData);
+ $objenc->type = $encData->getAttribute("Type");
+
+ $objKey = $objenc->locateKey();
+ $key = null;
+
+ if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) {
+ if ($objKeyInfo->isEncrypted) {
+ $objencKey = $objKeyInfo->encryptedCtx;
+ $objKeyInfo->loadKey($this->getFixtureFileName('privkey.pem', true), true);
+ $key = $objencKey->decryptKey($objKeyInfo);
+ }
+ }
+
+ if (empty($objKey->key)) {
+ $objKey->loadKey($key);
+ }
+
+ if ($decrypt = $objenc->decryptNode($objKey, true)) {
+ $output = null;
+ if ($decrypt instanceof DOMNode) {
+ if ($decrypt instanceof DOMDocument) {
+ $output = $decrypt->saveXML();
+ } else {
+ $output = $decrypt->ownerDocument->saveXML();
+ }
+ } else {
+ $output = $decrypt;
+ }
+ }
+
+ $resDoc = new DOMDocument();
+ $resDoc->load($source);
+ $res = $resDoc->saveXML();
+
+ $this->assertSame($res, $output);
+ }
+
+ /**
+ * Create site key
+ * @return XMLSecurityKey
+ */
+ protected function createSiteKey()
+ {
+ $siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public'));
+ $siteKey->loadKey($this->getFixtureFileName('mycert.pem', true), true, true);
+ return $siteKey;
+ }
+
+ public function providerTestBasicEncryptDecrypt()
+ {
+ return array(
+
+ // legacy fixtures
+ array(
+ $this->getFixtureFileName('basic-doc.xml', true),
+ XMLSecurityKey::AES256_CBC,
+ $this->getFixtureFileName('oaep_sha1-res.xml', true),
+ ),
+ array(
+ $this->getFixtureFileName('basic-doc.xml', true),
+ XMLSecurityKey::AES256_CBC,
+ $this->getFixtureFileName('oaep_sha1-content-res.xml', true),
+ ),
+
+ // new fixtures
+ array(
+ $this->getFixtureFileName('basic-doc.xml', true),
+ XMLSecurityKey::TRIPLEDES_CBC,
+ $this->getFixtureFileName('basic-doc-encrypted-tripledes-cbc.xml'),
+ ),
+ array(
+ $this->getFixtureFileName('basic-doc.xml', true),
+ XMLSecurityKey::AES128_CBC,
+ $this->getFixtureFileName('basic-doc-encrypted-aes128-cbc.xml'),
+ ),
+ array(
+ $this->getFixtureFileName('basic-doc.xml', true),
+ XMLSecurityKey::AES192_CBC,
+ $this->getFixtureFileName('basic-doc-encrypted-aes192-cbc.xml'),
+ ),
+ array(
+ $this->getFixtureFileName('basic-doc.xml', true),
+ XMLSecurityKey::AES256_CBC,
+ $this->getFixtureFileName('basic-doc-encrypt-aes256-cbc.xml'),
+ ),
+ );
+ }
+
+ /**
+ * @covers ::encryptNode
+ * @group unit
+ * @expectedException Exception
+ * @expectedExceptionMessage Node to encrypt has not been set
+ */
+ public function testEncryptNodeRequiresNode()
+ {
+ $sut = new XMLSecEnc();
+ $sut->encryptNode(null);
+ }
+
+ /**
+ * @covers ::encryptNode
+ * @group unit
+ * @expectedException Exception
+ * @expectedExceptionMessage Invalid Key
+ */
+ public function testEncryptNodeInvalidKey()
+ {
+ $sut = new XMLSecEnc();
+ $sut->setNode(new DOMNode());
+ $sut->encryptNode(null);
+ }
+}
diff --git a/tests/thumbprint.phpt b/tests/thumbprint.phpt
index eb5b8160..e9f357ff 100644
--- a/tests/thumbprint.phpt
+++ b/tests/thumbprint.phpt
@@ -2,7 +2,7 @@
Certificate thumbprint check
--FILE--
'public'));
diff --git a/tests/validate_digest_sha512.phpt b/tests/validate_digest_sha512.phpt
index bf438848..f4cf8876 100755
--- a/tests/validate_digest_sha512.phpt
+++ b/tests/validate_digest_sha512.phpt
@@ -2,7 +2,7 @@
Validate Digest SHA 512
--FILE--
--EXPECTF--
-OK
\ No newline at end of file
+OK
diff --git a/tests/withcomment-id-uri.phpt b/tests/withcomment-id-uri.phpt
index a48c9098..0211e51f 100644
--- a/tests/withcomment-id-uri.phpt
+++ b/tests/withcomment-id-uri.phpt
@@ -4,7 +4,7 @@ WithComments with an ID reference.
Checks that comments are removed when using an ID URI in a Reference.
--FILE--
--FILE--
--FILE--
.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * * Neither the name of Robert Richards nor the names of his
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * @author Robert Richards
- * @copyright 2007-2016 Robert Richards
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version 2.0.1
- */
-
-$xmlseclibs_srcdir = dirname(__FILE__) . '/src/';
-require $xmlseclibs_srcdir . '/XMLSecurityKey.php';
-require $xmlseclibs_srcdir . '/XMLSecurityDSig.php';
-require $xmlseclibs_srcdir . '/XMLSecEnc.php';