Permalink
Browse files

updated encryption method to be more secure

  • Loading branch information...
talhaparacha committed Aug 11, 2016
1 parent af1d826 commit fa33020415ccd077eca55e16b99e85cbf7bffcb0
Showing with 68 additions and 25 deletions.
  1. +3 −1 README.md
  2. +62 −21 src/Plugin/EncryptionMethod/OpenSSLEncryptionMethod.php
  3. +3 −3 src/Tests/OpenSSLEncryptionTest.php
@@ -2,4 +2,6 @@

[![Build Status](https://travis-ci.org/talhaparacha/encrypt_openssl.svg?branch=8.x)](https://travis-ci.org/talhaparacha/encrypt_openssl)

This module provides an Encryption Method plugin to be used with the Drupal 8 Encrypt module. Accordingly, the plugin uses AES-128-CBC cipher via the OpenSSL PHP extension.
This module provides an Encryption Method plugin to be used with the Drupal 8 Encrypt module. Accordingly, the plugin uses AES-256-CBC cipher via the OpenSSL PHP extension along with HMAC-SHA256 for authentication of the encrypted data.

For enhanced security, the encrypt()/decrypt() functions are taken directly from this excellent resource [Encryption, Authentication & Data Integrity in PHP](http://zimuel.it/slides/phpbenelux2016/#/) by [Enrico Zimuel](http://www.zimuel.it/).
@@ -11,8 +11,8 @@
*
* @EncryptionMethod(
* id = "openssl",
* title = @Translation("OpenSSL PHP extension"),
* description = "Uses AES-128-CBC cipher via the OpenSSL PHP extension.",
* title = @Translation("AES (OpenSSL) + HMAC-SHA256"),
* description = "Uses AES-256-CBC via OpenSSL along with HMAC-SHA256.",
* key_type = {"encryption"}
* )
*/
@@ -22,32 +22,54 @@ class OpenSSLEncryptionMethod extends EncryptionMethodBase implements Encryption
* {@inheritdoc}
*/
public function encrypt($text, $key) {
// IV is a crypto-secure random binary string of 16 bytes as required by the
// AES-128-CBC cipher.
$iv = Crypt::randomBytes(16);
$iv_size = openssl_cipher_iv_length('aes-256-cbc');
$iv = Crypt::randomBytes($iv_size);
// Encryption key generated by PBKDF2.
$keys = hash_pbkdf2('sha256', $key, $iv, 10000, 64, TRUE);
// 256 bit encryption key.
$enc_key = substr($keys, 0, 32);
// 256 bit hmac key.
$hmac_key = substr($keys, 32);
// Encrypt the data.
$encrypted_data = openssl_encrypt($text, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
$ciphertext = openssl_encrypt(
$text,
'aes-256-cbc',
$enc_key,
OPENSSL_RAW_DATA,
$iv
);
$hmac = hash_hmac('sha256', $iv . $ciphertext, $hmac_key);
// Concatenate IV with the encrypted data so to make it available during
// decryption.
$processed_text = $iv . $encrypted_data;
return $processed_text;
return $hmac . $iv . $ciphertext;
}
/**
* {@inheritdoc}
*/
public function decrypt($text, $key) {
// Separate encrypted data and IV from the cipher text.
$iv = substr($text, 0, 16);
$encrypted_data = substr($text, 16);
$hmac = substr($text, 0, 64);
$iv_size = openssl_cipher_iv_length('aes-256-cbc');
$iv = substr($text, 64, $iv_size);
$ciphertext = substr($text, $iv_size + 64);
// Generate the encryption and hmac keys.
$keys = hash_pbkdf2('sha256', $key, $iv, 10000, 64, TRUE);
// 256 bit encryption key.
$enc_key = substr($keys, 0, 32);
$hmac_new = hash_hmac('sha256', $iv . $ciphertext, substr($keys, 32));
// Decrypt the data.
$plain_text = openssl_decrypt($encrypted_data, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
// To prevent timing attacks.
if (!$this->compareStrings($hmac, $hmac_new)) {
return FALSE;
}
return $plain_text;
return openssl_decrypt(
$ciphertext,
'aes-256-cbc',
$enc_key,
OPENSSL_RAW_DATA,
$iv
);
}
/**
@@ -60,12 +82,31 @@ public function checkDependencies($text = NULL, $key = NULL) {
$errors[] = 'OpenSSL PHP extension is missing.';
}
// Check if we have a 128 bit key as required by the AES-128-CBC cipher.
if (strlen($key) != 16) {
$errors[] = t('This encryption method requires a 128 bit key.');
// Check if we have a 256 bit key as required by the AES-256-CBC cipher.
if (strlen($key) != 32) {
$errors[] = t('This encryption method requires a 256 bit key.');
}
return $errors;
}
/**
* Compare strings in such a way so to prevent timing attacks.
*/
protected function compareStrings($expected, $actual) {
$expected = (string) $expected;
$actual = (string) $actual;
$len_expected = strlen($expected);
$len_actual = strlen($actual);
$len = min($len_expected, $len_actual);
$result = 0;
for ($i = 0; $i < $len; $i++) {
$result |= ord($expected[$i]) ^ ord($actual[$i]);
}
$result |= $len_expected ^ $len_actual;
return ($result === 0);
}
}
@@ -60,8 +60,8 @@ public function testEncryptAndDecrypt() {
'id' => 'testing_key',
'label' => 'Testing Key',
'key_type' => "encryption",
'key_type_settings[key_size]' => '128',
'key_input_settings[key_value]' => Crypt::randomBytes(16),
'key_type_settings[key_size]' => '256',
'key_input_settings[key_value]' => Crypt::randomBytes(32),
'key_provider' => 'config',
];
$this->drupalPostForm(NULL, $edit, t('Save'));
@@ -74,7 +74,7 @@ public function testEncryptAndDecrypt() {
// Check if our plugin exists.
$this->assertOption('edit-encryption-method', 'openssl', t('OpenSSL encryption method option is present.'));
$this->assertText('OpenSSL PHP extension', t('OpenSSL encryption method text is present'));
$this->assertText('AES (OpenSSL) + HMAC-SHA256', t('OpenSSL encryption method text is present'));
$edit = [
'encryption_method' => 'openssl',

0 comments on commit fa33020

Please sign in to comment.