I've updated my existing system to PHP 7.4 and mcrypt has been removed and I'm looking for an alternative.
It's recommended to change the code using openssl, but I didn't see any articles posted in my case.
It is recommended to rewrite mcrypt_create_iv for random_bytes and mcrypt_ecb for mcrypt_encrypt, but there is no alternative to E and I can't think of that rewrite.
Do you have an idea?
Service.php
/**
* 3DES encryption
*
* #param string $plain Plaintext
* #return string cipher Ciphertext
*/
public function encrypt3DES($plain) {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ECB), MCRYPT_RAND);
$cipher = bin2hex(mcrypt_ecb (MCRYPT_3DES, self::AUTH_KEY, $plain, MCRYPT_ENCRYPT, $iv));
return $cipher;
}
/**
* 3DES decryption
*
* #param string $cipher Ciphertext
* #return string Plaintext
*/
public function decrypt3DES($cipher) {
if (!ctype_xdigit($cipher)) {
return '';
}
$iv = mcrypt_create_iv (mcrypt_get_iv_size (MCRYPT_3DES, MCRYPT_MODE_ECB), MCRYPT_RAND);
$plain = mcrypt_ecb(MCRYPT_3DES, self::AUTH_KEY, pack("H*", $cipher), MCRYPT_DECRYPT, $iv);
return trim($plain);
}
Related
Good evening everyone!
I am getting a strange warning while trying to buy via credit card. Am using Cardinity payment gateway. OpenCart 3.0.2.0. PHP 7.2.0. Quickcheckout by MarketInSG. What happens is when you click on button Pay Now, it loads for a couple of seconds and then button is returned back to initial Pay Now state. Here is warning message:
PHP Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in .../system/library/encryption.php on line 23.
My encryption.php looks like this:
<?php
/**
* #package OpenCart
* #author Daniel Kerr
* #copyright Copyright (c) 2005 - 2017, OpenCart, Ltd. (https://www.opencart.com/)
* #license https://opensource.org/licenses/GPL-3.0
* #link https://www.opencart.com
*/
/**
* Encryption class
*/
final class Encryption {
/**
*
*
* #param string $key
* #param string $value
*
* #return string
*/
public function encrypt($key, $value) {
return strtr(base64_encode(openssl_encrypt($value, 'aes-256-cbc', hash('sha256', $key, true))), '+/=', '-_,');
}
/**
*
*
* #param string $key
* #param string $value
*
* #return string
*/
public function decrypt($key, $value) {
return trim(openssl_decrypt(base64_decode(strtr($value, '-_,', '+/=')), 'aes-256-cbc', hash('sha256', $key, true)));
}
}
Line 23 is this: return strtr(base64_encode(openssl_encrypt($value, 'aes-256-cbc', hash('sha256', $key, true))), '+/=', '-_,');
Then I browsed around forums and found altered encryption.php that looks like this:
<?php
/**
* #package OpenCart
* #author Daniel Kerr
* #copyright Copyright (c) 2005 - 2017, OpenCart, Ltd. (https://www.opencart.com/)
* #license https://opensource.org/licenses/GPL-3.0
* #link https://www.opencart.com
*/
/**
* Encryption class
*/
final class Encryption {
/**
*
*
* #param string $key
* #param string $value
*
* #return string
*/
public function encrypt($key, $value) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($value);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-gcm'));
// Encrypt the data using AES 256 encryption in GCM mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($key, 'aes-256-gcm', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
/**
*
*
* #param string $key
* #param string $value
*
* #return string
*/
public function decrypt($key, $value) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($value);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($key), 2);
return openssl_decrypt($encrypted_data, 'aes-256-gcm', $encryption_key, 0, $iv);
}
}
When I use modified encryption.php file, I get the following warning:
PHP Warning: openssl_encrypt(): A tag should be provided when using AEAD mode in ...system/library/encryption.php on line 30
Line 30 is this: $encrypted = openssl_encrypt($key, 'aes-256-gcm', $encryption_key, 0, $iv);
Since my coding skills are limited, I don't know what else to do? To contact hosting company or Cardinity? Any help will be hugely appreciated. Thank you!
The cardinity plugin uses opencarts provided encrypt library, which is still using deprecated functions.
When using this there is a PHP warning that mess up ajax json responses. If you want to get around this issue.
set
error_reporting(0);
right before wherever there is a use of encrypt()
error_reporting(0);
$this->encryption->encrypt(...)
The last patch should automatically fix this
https://github.com/cardinity/cardinity-opencart/releases/tag/3.0.x-3dsv2-patch1
I am encrypting a string using following class (using inheritance)
class UnsafeCrypto {
const METHOD = 'aes-256-ctr';
/**
* Encrypts (but does not authenticate) a message
*
* #param string $message - plaintext message
* #param string $key - encryption key (raw binary expected)
* #param boolean $encode - set to TRUE to return a base64-encoded
* #return string (raw binary)
*/
public static function encrypt($message, $key, $encode = false)
{
$nonceSize = openssl_cipher_iv_length(self::METHOD);
$nonce = openssl_random_pseudo_bytes($nonceSize);
$ciphertext = openssl_encrypt(
$message,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$nonce
);
// Now let's pack the IV and the ciphertext together
// Naively, we can just concatenate
if ($encode) {
return base64_encode($nonce.$ciphertext);
}
return $nonce.$ciphertext;
}
/**
* Decrypts (but does not verify) a message
*
* #param string $message - ciphertext message
* #param string $key - encryption key (raw binary expected)
* #param boolean $encoded - are we expecting an encoded string?
* #return string
*/
public static function decrypt($message, $key, $encoded = false)
{
if ($encoded) {
$message = base64_decode($message, true);
if ($message === false) {
throw new Exception('Encryption failure');
}
}
$nonceSize = openssl_cipher_iv_length(self::METHOD);
$nonce = mb_substr($message, 0, $nonceSize, '8bit');
$ciphertext = mb_substr($message, $nonceSize, null, '8bit');
$plaintext = openssl_decrypt(
$ciphertext,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$nonce
);
return $plaintext;
}
}
Inheriting the class as below.
class SaferCrypto extends UnsafeCrypto {
const HASH_ALGO = 'sha256';
/**
* Encrypts then MACs a message
*
* #param string $message - plaintext message
* #param string $key - encryption key (raw binary expected)
* #param boolean $encode - set to TRUE to return a base64-encoded string
* #return string (raw binary)
*/
public static function encrypt($message, $key, $encode = false)
{
list($encKey, $authKey) = self::splitKeys($key);
// Pass to UnsafeCrypto::encrypt
$ciphertext = parent::encrypt($message, $encKey);
// Calculate a MAC of the IV and ciphertext
$mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);
if ($encode) {
return base64_encode($mac.$ciphertext);
}
// Prepend MAC to the ciphertext and return to caller
return $mac.$ciphertext;
}
/**
* Decrypts a message (after verifying integrity)
*
* #param string $message - ciphertext message
* #param string $key - encryption key (raw binary expected)
* #param boolean $encoded - are we expecting an encoded string?
* #return string (raw binary)
*/
public static function decrypt($message, $key, $encoded = false)
{
list($encKey, $authKey) = self::splitKeys($key);
if ($encoded) {
$message = base64_decode($message, true);
if ($message === false) {
throw new Exception('Encryption failure');
}
}
// Hash Size -- in case HASH_ALGO is changed
$hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit');
$mac = mb_substr($message, 0, $hs, '8bit');
$ciphertext = mb_substr($message, $hs, null, '8bit');
$calculated = hash_hmac(
self::HASH_ALGO,
$ciphertext,
$authKey,
true
);
if (!self::hashEquals($mac, $calculated)) {
throw new Exception('Encryption failure');
}
// Pass to UnsafeCrypto::decrypt
$plaintext = parent::decrypt($ciphertext, $encKey);
return $plaintext;
}
/**
* Splits a key into two separate keys; one for encryption
* and the other for authenticaiton
*
* #param string $masterKey (raw binary)
* #return array (two raw binary strings)
*/
protected static function splitKeys($masterKey)
{
// You really want to implement HKDF here instead!
return [
hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
];
}
/**
* Compare two strings without leaking timing information
*
* #param string $a
* #param string $b
* #ref https://paragonie.com/b/WS1DLx6BnpsdaVQW
* #return boolean
*/
protected static function hashEquals($a, $b)
{
if (function_exists('hash_equals')) {
return hash_equals($a, $b);
}
$nonce = openssl_random_pseudo_bytes(32);
return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
}
}
Encrypting string as follow.
$email = 'myemail#domain.com';
$key = 'Some key';
$encrypted_email = $encrypted = SaferCrypto::encrypt($message, $key);
String is getting encrypted like this:
óÜCu!>Ò·<x0½“—J ‡l¿Ø ;ƒ;›OøVP#ï 1 Sjñ,(ñúrÛòv–~ºyÍg ÷–´´iƒû
If I pass this with urlencode($string) data is not getting decrypted because hash is not matching because hashEquals method is throwing exception.
What is the proper way to pass encrypted string in GET request?
It's not clear, what is the problem, but you can use base64_encode($encrypted_email) to pass your string as smth like HDo1FaXabDHjfxBkpx7YBHNGVeZ/G8FvI2BoxES2rUu3lvNWRo5G0PImiv9IhENv.
link
When receiving, decode it
$encrypted_email = base64_decode($_GET['enc']);
This question already has answers here:
Where should I store an encryption key for php?
(5 answers)
Closed 6 years ago.
I'm using this php function to encrypt some strings.
openssl_encrypt();
To generate the encryption key I use
$encryption_key = openssl_random_pseudo_bytes(32);
I also know that this encryption key should be stored somewhere.
The problem is that I don't want to store it in my database, because it could be accessible for hackers.
Where could I also store my keys safely?
P.S. It makes any sense to store encrypted data and used keys in the same database
Here's an example encryption class I created in PHP. The encryption key is stored in this class, which can then be used to decrypt encrypted DB values. Hope this helps.
/**
* Provides basic encryption and decryption of strings and objects.
* Reasonable protection is provided, but you are still responsible
* for sanitizing the source strings or objects prior to use.
*/
class Encrypter {
/**
* This is the global encryption key for the site.
* The longer you make this key, the more secure the encryption
*/
const MASTER_KEY = 'my_amazing_key_of_death';
private $key;
private $cipher;
private $mode;
private $iv;
private $iv_size;
private $key_size;
private $block_size;
public function __construct() {
$this->key = self::MASTER_KEY
$this->cipher = MCRYPT_BLOWFISH;
$this->mode = MCRYPT_MODE_CBC;
$this->block_size = mcrypt_get_block_size($this->cipher);
$this->iv_size = mcrypt_get_iv_size($this->cipher, $this->mode);
$this->key_size = mcrypt_get_key_size($this->cipher, $this->mode);
$this->iv = mcrypt_create_iv($this->iv_size, MCRYPT_RAND);
/**
* if the calculated keysize is shorter than
* they key provided, trim the provided key
* to match its length
*/
if (strlen($this->key) > $this->key_size) {
$this->key = substr($this->key, 0, $this->key_size);
}
}
/**
* Static method alias for string encryption
* #param string $string The string to encrypt
* #return string The encrypted string
*/
public static function enc($string) {
$e = new self;
return $e->encrypt_string($string);
}
/**
* Static method alias for string decryption
* #param string $enc_string The previously encrypted string
* #return string The decrypted/original string
*/
public static function dec($enc_string) {
$e = new self;
return $e->decrypt_string($enc_string);
}
/**
* Encrypt a string
* #param string $string - string to encrypt
* #return string - encrypted string
*/
function encrypt_string($string) {
$enc = mcrypt_encrypt(
$this->cipher,
$this->key,
$string,
$this->mode,
$this->iv
);
$enc = base64_encode($this->iv . $enc);
/**
* replace potentially illegal chars
*/
$enc = strtr($enc, '+/=', '-_,');
/**
* remove unnecessary and ugly trailing commas
*/
$enc = strrev($enc);
if(substr($enc,0,1) == ',') $enc = substr($enc,1);
if(substr($enc,0,1) == ',') $enc = substr($enc,1);
$enc = strrev($enc);
return $enc;
}
/**
* Decrypt an encrypted string and return the original
* #param string $s The string previously encrypted with this class
* #return string The original unencrypted string
*/
function decrypt_string($s) {
$s = strtr($s, '-_,', '+/=');
$s = base64_decode($s);
$this->iv_size = mcrypt_get_iv_size($this->cipher, $this->mode);
$this->iv = substr($s, 0, $this->iv_size);
$data = substr($s, $this->iv_size);
/**
* supress warnings because they happen every time
* IV parameter must be as long as the block size
* yet this still works perfectly
*/
$decrypted = #mcrypt_decrypt($this->cipher, $this->key, $data, $this->mode, $this->iv);
return trim($decrypted);
}
/**
* Serialize an object into an encrypted string
* #throws Exception
* #param object $object
* #return string
*/
function encrypt_object($object) {
if(is_resource($object)) throw new Exception("Cannot encrypt objects of type 'resource'");
$ser = serialize($object);
$enc = base64_encode($ser);
return $this->encrypt_string($enc);
}
/**
* Unserialize an encrypted string back into an object
* #param string $enc
* #return object
*/
function decrypt_object($enc) {
$dec = $this->decrypt_string($enc);
$unenc = base64_decode($dec);
return unserialize($unenc);
}
}
I'm trying to encrypt some data using the MCRYPT_RIJNDAEL_128 algoritm. But somehow when I encrypt and afterwards decrypt, the decrypted data has randomly added bytes.
The input: string(13) "test#test.com"
The output: string(16) "test#test.com"
As you can see the output has 16 characters while the input has 13.
The following is the code used for encryption.
class Cipher
{
/**
* The key/salt(bin2hex format) used to encrypt data with in AES(RIJNDAEL) format.
* #var string
*/
private static $encryptionKey = 'baafbd1f8d752d920caae00ae550be8185c1183207a142c97c36fca3edc507da';
/**
* Gets and transforms the encryption key to binary format.
* #return string (in binary format)
*/
public static function getEncryptionKey()
{
return hex2bin(self::$encryptionKey);
}
/**
* Generates a new random main encryption key used to encrypt data.
* Store the generated key in the private property of this class.
* #param bool $strong Whether the encryption will be strong.
* #return string The generated key in hexadecimal format.
*/
public static function generateEncryptionKey($strong = true)
{
$keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
return bin2hex(openssl_random_pseudo_bytes($keySize, $strong));
}
/**
* Creates an encryption key IV used to store near the database record for the encrypted data.
* Use bin2hex function for a representational string.
* #return string (in binary format)
*/
public static function createIv()
{
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
return mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
}
/**
* Encrypts a given string by the generated encryption key and generated IV.
* #param string $string The string which will be encrypted.
* #param string $iv The dynamic key used to encrypt.
* #return string (in binary format)
*/
public static function encrypt($string, $iv)
{
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, self::getEncryptionKey(), $string, MCRYPT_MODE_CBC, $iv);
}
/**
* Decrypts a given string by the generated encryption key and generated IV.
* #param string $string The binary string which will be decrypted.
* #param string $iv The dynamic key which belongs to the encrypted string.
* #return string The decrypted string.
*/
public static function decrypt($string, $iv)
{
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, self::getEncryptionKey(), $string, MCRYPT_MODE_CBC, $iv);
}
}
The encryption key showed here isn't used in production or testing environments and is only used for display purposes.
The following is used to display the decryption
$iv = Cipher::createIv();
$emailAddress = Cipher::encrypt('test#test.com', $iv);
var_dump(Cipher::decrypt($emailAddress, $iv));exit;
I'm using the following environments:
Ubuntu: 14.10
PHP: PHP 5.5.9-1ubuntu4.3 (cli) (built: Jul 7 2014 16:36:58)
Those are just padding 0x00 characters added at the end, because the string's length for that cryptographic algorithms has to be a multiple of 16 (with 128 bit).
Indeed, if you add at the end of your code:
var_dump(bin2hex(Cipher::decrypt($emailAddress, $iv)));
You can see that the last 6 characters are all 0's (which means there are 3 0x00 bytes at the end).
To remove them, just run:
$decrypted = rtrim($decrypted, "\0");
I've got the following class.
<?php
/**
* Cypher Class
*/
class Cipher
{
/**
* SHA256 Encrypted Key
* #var string
*/
private $encryptedKey;
/**
* Initial vector
*
* Used to seed the encryption string
*
* #var string
*/
private $initVector;
/**
* Constructor
* #param boolean|string $personalKey Holds the personal key to use in encryption
*/
public function __construct($personalKey = false)
{
// $config = configuration::getInstance();
if (false === $personalKey) {
return false;
} else {
$key = $personalKey;
}
$this->encryptionKey = hash('sha256', $key, TRUE);
$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);
$this->initVector = mcrypt_create_iv($size, MCRYPT_DEV_URANDOM);
}
/**
* Encrypt a string
* #param mixed $input Data to encrypt
* #return string Encrypted data
*/
public function encrypt($input)
{
return array(
'salt' => base64_encode($this->initVector),
'encrypted_value' => base64_encode(mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$this->encryptionKey,
$input,
MCRYPT_MODE_CFB,
$this->initVector
)));
}
/**
* Decrypt string
* #param string $input Encrypted string we are going to decrypt
* #param string $salt Encrypted salt used to decrypt
* #return string Decrypted output
*/
public function decrypt($input, $salt)
{
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->encryptionKey, base64_decode($input), MCRYPT_MODE_CFB, $salt));
}
}
Both my IV and encrypted string are 16 bytes but for some reason PHP gives me the following error:
Warning: mcrypt_encrypt(): The IV parameter must be as long as the blocksize in C:\xampp\htdocs\public\cipher\Cipher.php on line 58
I am not really a star in encryptions and so I was wondering if one of you good people could help me out.
The size of an IV is related to the block size of the cipher. So whatever you choose as the block size must be used as the length of the IV.
Rijndael supports block sizes of 128, 160, 192, 224, and 256 bits. If you use MCRYPT_RIJNDAEL_128 then you are using the 128-bit block size (which matches AES). If you use MCRYPT_RIJNDAEL_256 then your block-size is twice as large.
So, you must decide which block size you want to use and ensure your code consistently refers to the same MCRYPT_RIJNDAEL_* constant.
I assume the website is giving you an error because it's expecting a 16-byte block size (as per AES).