diff --git a/tfa.admin.inc b/tfa.admin.inc index 28319af..c063e08 100644 --- a/tfa.admin.inc +++ b/tfa.admin.inc @@ -25,10 +25,10 @@ function tfa_admin_settings($form, $form_state) { } } - // Check if mcrypt plugin is available. - if (!extension_loaded('mcrypt')) { + // Check if openssl or mcrypt extensions are available. + if (!extension_loaded('openssl') && !extension_loaded('mcrypt')) { // @todo allow alter in case of other encryption libs. - drupal_set_message(t('The TFA module requires the PHP Mcrypt extension be installed on the web server. See the TFA help documentation for setup.', array('!link' => url('admin/help/tfa'))), 'error'); + drupal_set_message(t('The TFA module requires one of the PHP OpenSSL or MCrypt extensions to be installed on the web server. See the TFA help documentation for setup.', array('!link' => url('admin/help/tfa'))), 'error'); return array(); } diff --git a/tfa.inc b/tfa.inc index bb9ab82..035eb0c 100644 --- a/tfa.inc +++ b/tfa.inc @@ -376,6 +376,8 @@ class TfaSetup { */ abstract class TfaBasePlugin { + const CRYPT_VERSION = '1'; + /** * @var string */ @@ -502,18 +504,43 @@ abstract class TfaBasePlugin { * * Should be used when writing codes to storage. * - * @param string. + * @param string $text + * The plaintext to be encrypted. + * * @return string + * The encrypted text. */ protected function encrypt($text) { + // Backwards compatibility with MCrypt. + if (!extension_loaded('openssl') && extension_loaded('mcrypt')) { + return $this->encryptWithMCrypt($text); + } + $iv = drupal_random_bytes(16); + + return sprintf( + '%s|%s|%s', + self::CRYPT_VERSION, + $iv, + openssl_encrypt($text, 'AES-256-CBC', $this->encryptionKey, OPENSSL_RAW_DATA, $iv) + ); + } + + /** + * Encrypt using the deprecated mcrypt extension. + * + * @param string $text + * + * @return string + */ + protected function encryptWithMCrypt($text, $iv = null) { $td = mcrypt_module_open('rijndael-128', '', 'cbc', ''); - $iv = drupal_random_bytes(mcrypt_enc_get_iv_size($td)); + $iv = $iv ?: drupal_random_bytes(mcrypt_enc_get_iv_size($td)); $key = substr($this->encryptionKey, 0, mcrypt_enc_get_key_size($td)); mcrypt_generic_init($td, $key, $iv); - // Encrypt with message length so decryption can return message without - // padding. + // Encrypt with message length so decryption can return message without + // padding. $text = strlen($text) . '|' . $text; $data = mcrypt_generic($td, $text); @@ -528,10 +555,36 @@ abstract class TfaBasePlugin { * * Should be used when reading codes from storage. * - * @param string + * @param string $data + * The encrypted text. + * * @return string + * The plaintext, or FALSE on failure. */ protected function decrypt($data) { + $version_prefix = self::CRYPT_VERSION . '|'; + $version_match = strpos($data, $version_prefix) === 0; + // Backwards compatibility with the old MCrypt scheme. + if (!$version_match) { + if (extension_loaded('mcrypt')) { + return $this->decryptWithMCrypt($data); + } + return FALSE; + } + + list(, $iv, $data) = explode('|', $data, 3); + + return openssl_decrypt($data, 'AES-256-CBC', $this->encryptionKey, TRUE, $iv); + } + + /** + * Decrypt using the deprecated MCrypt extension. + * + * @param string $data + * + * @return string + */ + protected function decryptWithMCrypt($data) { $td = mcrypt_module_open('rijndael-128', '', 'cbc', ''); $iv = substr($data, 0, mcrypt_enc_get_iv_size($td)); diff --git a/tfa.install b/tfa.install index cbf7943..9bd610d 100644 --- a/tfa.install +++ b/tfa.install @@ -26,13 +26,19 @@ function tfa_uninstall() { */ function tfa_requirements($phase) { if ($phase == 'runtime') { - if (!extension_loaded('mcrypt')) { - $requirement_severity = REQUIREMENT_ERROR; - $description = t('The TFA module requires the PHP Mcrypt extension be installed on the web server.'); + if (!extension_loaded('openssl')) { + if (extension_loaded('mcrypt')) { + $requirement_severity = REQUIREMENT_WARNING; + $description = t('The TFA module recommends the PHP OpenSSL extension to be installed on the web server.'); + } + else { + $requirement_severity = REQUIREMENT_ERROR; + $description = t('The TFA module requires either the PHP OpenSSL or MCrypt extensions to be installed on the web server.'); + } } else { $requirement_severity = REQUIREMENT_OK; - $description= ''; + $description = ''; } $enabled = variable_get('tfa_enabled', 0);