Skip to content

Commit

Permalink
Remove mcrypt dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
skymeyer committed Mar 30, 2017
1 parent 5cdb86f commit 77d0283
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 109 deletions.
3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ language: php
matrix:
fast_finish: true
include:
- php: 5.3
- php: 5.4
- php: 5.5
- php: 5.6
env:
- EXECUTE_COVERAGE=true
Expand Down
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
}
},
"require": {
"php": ">= 5.3"
"php": ">= 5.6"
},
"suggest": {
"ext-openssl": "OpenSSL extension",
"ext-mcrypt": "MCrypt extension"
"ext-openssl": "OpenSSL extension"
}
}
243 changes: 141 additions & 102 deletions src/XMLSecurityKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 the openssl-extension.
* In case of using DES3-CBC the key is checked for a proper parity bits set.
* @return string
* @throws Exception
*/
Expand All @@ -248,13 +251,7 @@ public function generateSessionKey()
}
$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 = openssl_random_pseudo_bytes($keysize);

if ($this->type === self::TRIPLEDES_CBC) {
/* Make sure that the generated key has the proper parity bits set.
Expand Down Expand Up @@ -332,122 +329,156 @@ public function loadKey($key, $isFile=false, $isCert = false)
$this->x509Certificate = null;
}
if ($this->cryptParams['library'] == 'openssl') {
if ($this->cryptParams['type'] == 'public') {
if ($isCert) {
/* Load the thumbprint if this is an X509 certificate. */
$this->X509Thumbprint = self::getRawThumbprint($this->key);
}
$this->key = openssl_get_publickey($this->key);
if (! $this->key) {
throw new Exception('Unable to extract public key');
}
} else {
$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) {
throw new Exception('Key must contain at least 25 characters for this cipher');
}
switch ($this->cryptParams['type']) {
case 'public':
if ($isCert) {
/* Load the thumbprint if this is an X509 certificate. */
$this->X509Thumbprint = self::getRawThumbprint($this->key);
}
$this->key = openssl_get_publickey($this->key);
if (! $this->key) {
throw new Exception('Unable to extract public key');
}
break;

case 'private':
$this->key = openssl_get_privatekey($this->key, $this->passphrase);
break;
case (self::AES192_CBC):
if (strlen($this->key) < 17) {
throw new Exception('Key must contain at least 17 characters for this cipher');

case'symmetric':
if (strlen($this->key) < $this->cryptParams['keysize']) {
throw new Exception('Key must contain at least 25 characters for this cipher');
}
break;

default:
throw new Exception('Unknown type');
}
}
}

/**
* Encrypts the given data (string) using the mcrypt-extension
* ISO 10126 Padding
*
* @param string $data
* @param integer $blockSize
* @throws Exception
* @return string
*/
private function encryptMcrypt($data)
private function padISO10126($data, $blockSize)
{
$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);
if ($blockSize > 256) {
throw new Exception('Block size higher than 256 not allowed');
}
$encrypted_data = $this->iv.mcrypt_generic($td, $data);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypted_data;
$padChr = $blockSize - (strlen($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 = substr($data, -1);
$padLen = ord($padChr);
return substr($data, 0, -$padLen);
}

/**
* Decrypts the given data (string) using the mcrypt-extension
* Encrypts the given data (string) using the openssl-extension
*
* @param string $data
* @return string
*/
private function decryptMcrypt($data)
private function encryptSymmetric($data)
{
$td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
$iv_length = mcrypt_enc_get_iv_size($td);
$this->iv = openssl_random_pseudo_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());
}
return $this->iv . $encrypted;
}

/**
* Decrypts the given data (string) using the openssl-extension
*
* @param string $data
* @return string
*/
private function decryptSymmetric($data)
{
$iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']);
$this->iv = substr($data, 0, $iv_length);
$data = substr($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);
}

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));
/**
* Encrypts the given public data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function encryptPublic($data)
{
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;
}

/**
* Encrypts the given data (string) using the openssl-extension
* Decrypts the given public data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function encryptOpenSSL($data)
private function decryptPublic($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_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string);
}
return $encrypted_data;
return $decrypted;
}

/**
* Decrypts the given data (string) using the openssl-extension
* Encrypts the given private data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function decryptOpenSSL($data)
private function encryptPrivate($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');
}
if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string());
}
return $encrypted;
}

/**
* Decrypts the given private 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;
}
Expand Down Expand Up @@ -495,11 +526,15 @@ private function verifyOpenSSL($data, $signature)
*/
public function encryptData($data)
{
switch ($this->cryptParams['library']) {
case 'mcrypt':
return $this->encryptMcrypt($data);
case 'openssl':
return $this->encryptOpenSSL($data);
if ($this->cryptParams['library'] === 'openssl') {
switch ($this->cryptParams['type']) {
case 'symmetric':
return $this->encryptSymmetric($data);
case 'public':
return $this->encryptPublic($data);
case 'private':
return $this->encryptPrivate($data);
}
}
}

Expand All @@ -511,11 +546,15 @@ public function encryptData($data)
*/
public function decryptData($data)
{
switch ($this->cryptParams['library']) {
case 'mcrypt':
return $this->decryptMcrypt($data);
case 'openssl':
return $this->decryptOpenSSL($data);
if ($this->cryptParams['library'] === 'openssl') {
switch ($this->cryptParams['type']) {
case 'symmetric':
return $this->decryptSymmetric($data);
case 'public':
return $this->decryptPublic($data);
case 'private':
return $this->decryptPrivate($data);
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions tests/basic-doc-encrypted-aes128-cbc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Basic XML example -->
<Root xmlns="urn:envelope"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/><dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><xenc:EncryptedKey><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/><xenc:CipherData><xenc:CipherValue>pKChAdt8YXFRkOfgARrW2IEwlnK1ZWEqnSvVhKK9VSiC5yICrf/dHL2BmkjJvG1wbOqBfJXCDCn/F+CeVDcZBa4kg/oQeUpIF7FMYaUK7Q9529uni/P5tMegQkOWeD7M76vlt5TXXbhRV/jZqCa5W5WIkhns53/2e97FKWOujPxrnydhvgzP9ztOPjOgbqIeJBkW432XQkgOSq6AANgfsgwrugQSusQcsJzuYRRhfSKTkH79t2sCGDlqV9XlAs1DOv2+elWEyL5G58/nDwaecRoZgo3EV4EdOudeNesvrNnZrsNRaR/qchUH+G+R9RDnXO4l3qookkH+6o222osxcQ==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>r0YRkEixBnAKU032/ux7avHcVTH1CIIyKaPA2qr4KlIs0LVZp5CuwQKRRi6lji4cnaFbH4jETtJhMSEfbpSdvg==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData></Root>
7 changes: 7 additions & 0 deletions tests/basic-doc-encrypted-aes192-cbc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Basic XML example -->
<Root xmlns="urn:envelope"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes192-cbc"/><dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><xenc:EncryptedKey><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/><xenc:CipherData><xenc:CipherValue>GXVyq5+hysMutP0IXxmJ3SZxBoLwWpMkgvqUYdiZGpH18Y8apPSetryE6wy8wgblFF0FnzpZttDdMWV646M+YhJtXXc+PaSpeYUM5qCHX2s0mROvmq1NGybNgy3tC1CuYnETAr+nfBt4vaQkcF+gBG5fd4Z2lkk9ZuQS+Fsyimtt59wVQoNfwkddBgphMp/XtUa120+c5cQpkVvTAUIs1AWnpcxFL6lOdLVND+59n2GGSkWJLcCrv96LO3aTPeSCnAWCx6wBSVVRSkhVpqC1zDTqz6Nq4hlUvcMt7rzTq6NMA6WUZOtG1iHiIrYDtqyHwOKYAVKnIKjPhLLewWMQ9g==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>ptSPO8ShXZrxkIVDvFwAuNAWEZIPKI/VpmsdWsVH/nQfMWpmFr9RKdzh6ezhr73i1sB6VZkafV6hErzEHVv+5w==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData></Root>
7 changes: 7 additions & 0 deletions tests/basic-doc-encrypted-aes256-cbc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Basic XML example -->
<Root xmlns="urn:envelope"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/><dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><xenc:EncryptedKey><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/><xenc:CipherData><xenc:CipherValue>jUzXhKjpKTTOavStGjH7+6lLoShei5Dk9B+Bg0hfUy4MFV3aq8E/HdfBYh36vm6bFroHF+6KP+K7Z2S9odN1zsbjF5oQjXLHDYnDEerMGiVbhlkXXaTWckThchZV8WoowXwSIkg8FjU01P+p8F6+lg9CC1h5B0xOWe9hQ3M0JSMSN1BZ15PVwXARDi/LuxJqf9dDZhqCFoYRUR7Q3612TNSgU/livb2VcRY7EbyRpuuSGfSjXNQPM1d/OlsfmZUYhd7aFO/OkHeUoFEx+BKkkRzrAfkRt7M5ilj7UHilNfzRsxSx0EQG3dfbJ0pbBgGgmiM9iLYnj087rzluN+x8kw==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>iUIRz5HJvgGADfkQAqXBC8WjmhoofuLAJedYn8DfwA614RQX5iB4PYw7GiVng+m/MVGYqvoudsg6lNprV0vN8Q==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData></Root>
7 changes: 7 additions & 0 deletions tests/basic-doc-encrypted-tripledes-cbc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Basic XML example -->
<Root xmlns="urn:envelope"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/><dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><xenc:EncryptedKey><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/><xenc:CipherData><xenc:CipherValue>11Tlnb3B2M+N5Uu7k3iozyVVVy7+Ylrzex79A0CiaBIWzdag36X6uk8ukdYiOxbGrb1iL0M/48h3pf2DA3gUj13d8cma3e2GprIphFWl57FJcBd5n/E/PRuVR6CfBqxzHTYKWuVntOkiA+l4QMWozmTNMmv3zWphwk5eMerob3kRPs5tFA+IFes9B++hKx3USXUVLfLJIhEf0AZB9o3eyZeG3pqzF6mkiy6epZKGM6JPA5oZJDKxCk+jscc4pDXftqIDdTu7Ukjbt2iD+OcMEO3zwpIoz8w0SksLH0WRRgZK/naPRSDCKHlqc/2nJaY8CcoLvC+pN93QaKHWzh+JHA==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>D+3dKq7MFK7U+8bqdlyRcvO12JV5Lahl5ALhF5eJXSfi+cbYKRbkRjvJsMKPp2Mk</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData></Root>
Loading

0 comments on commit 77d0283

Please sign in to comment.