I'm connecting by Soap to a webservice and I need to fill the header credentials in order to login.
$user_id = 'MyUserId';
$unique_key = $this->getUniqueKey();
$base_password = $this->getFieldBase('MyPassword', $uniqueKey);
$base_date = $this->getFieldBase(gmdate('Y-m-d\TH:i:s\.00\Z'), $unique_key);
$nonce = $this->getFieldNonce($unique_key, '.myPemFile.pem');
<wss:UsernameToken>
<wss:Username>' . $user_id . '</wss:Username>
<wss:Password>' . $base_password . '</wss:Password>
<wss:Nonce>' . $nonce . '</wss:Nonce>
<wss:Created>' . $base_date . '</wss:Created>
</wss:UsernameToken>
All values (except username) as to follow a structure.
I have this working for a 5.6 PHP project but now I need to adapt it to a PHP 7 project, and that means I can no longer use mcrypt_encrypt() because it's deprecated and therefore I need to use openssl_encrypt()
My current functions are:
private function getFieldBase($data, $key)
{
$ivsize = openssl_cipher_iv_length('AES-128-ECB');
$iv = openssl_random_pseudo_bytes($ivsize);
$ciphertext = openssl_encrypt($data, 'AES-128-ECB', $key, 0, $iv);
return trim(base64_encode($ciphertext));
}
private function getFieldNonce($data, $pbkey)
{
openssl_public_encrypt($data, $crypttext, openssl_pkey_get_public(file_get_contents($pbkey)));
return base64_encode($crypttext);
}
private function getUniqueKey()
{
return substr(md5(uniqid(microtime())), 0, 16);
}
The problem is that when connecting to the Webservice I receive the error:
Rejected: Error: The key session is invalid. It was not
possible to decipher the field Created
Which tells me that my getFieldBase() function is wrong.
Solved.
The parameter RAW_OUTPUT must be true within the function openssl_encrypt.
private function getFieldBase($data, $key)
{
$ivsize = openssl_cipher_iv_length('AES-128-ECB');
$iv = openssl_random_pseudo_bytes($ivsize);
$ciphertext = openssl_encrypt($data, 'AES-128-ECB', $key, TRUE, $iv);
return base64_encode($ciphertext);
}
Related
I am currently upgrading an existing PHP application from PHP 5.4 to PHP 8.1. I have managed to restore all functionality except for encryption and decryption of data. My application communicates with a third party server, so just running an old PHP version to decrypt using mcrypt and reencrypt using openssl is not possible. I have seen a lot of similar threads, was however unable to find a solution to my issue.
This is the old set of functions (using mcrypt):
static function encrypt($key, $plain, $salt = null)
{
if (is_null($salt))
{
$salt = QuickBooks_Encryption::salt();
}
$plain = serialize(array( $plain, $salt ));
$crypt = mcrypt_module_open('rijndael-256', '', 'ofb', '');
if (false !== stripos(PHP_OS, 'win') and
version_compare(PHP_VERSION, '5.3.0') == -1)
{
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($crypt), MCRYPT_RAND);
}
else
{
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($crypt), MCRYPT_DEV_URANDOM);
}
$ks = mcrypt_enc_get_key_size($crypt);
$key = substr(md5($key), 0, $ks);
mcrypt_generic_init($crypt, $key, $iv);
$encrypted = base64_encode($iv . mcrypt_generic($crypt, $plain));
mcrypt_generic_deinit($crypt);
mcrypt_module_close($crypt);
return $encrypted;
}
static function decrypt($key, $encrypted)
{
$crypt = mcrypt_module_open('rijndael-256', '', 'ofb', '');
$iv_size = mcrypt_enc_get_iv_size($crypt);
$ks = mcrypt_enc_get_key_size($crypt);
$key = substr(md5($key), 0, $ks);
//print('before base64 [' . $encrypted . ']' . '<br />');
$encrypted = base64_decode($encrypted);
//print('given key was: ' . $key);
//print('iv size: ' . $iv_size);
//print('decrypting [' . $encrypted . ']' . '<br />');
mcrypt_generic_init($crypt, $key, substr($encrypted, 0, $iv_size));
$decrypted = trim(mdecrypt_generic($crypt, substr($encrypted, $iv_size)));
mcrypt_generic_deinit($crypt);
mcrypt_module_close($crypt);
//print('decrypted: [[**(' . $salt . ')');
//print_r($decrypted);
//print('**]]');
$tmp = unserialize($decrypted);
$decrypted = current($tmp);
return $decrypted;
}
And this is my best approximation using openssl:
static function new_encrypt($key, $plain, $salt = null)
{
if (is_null($salt))
{
$salt = QuickBooks_Encryption::salt();
}
$plain = serialize(array( $plain, $salt ));
$method = "AES-256-OFB";
$iv_len = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_len);
$key = substr(md5($key), 0, 32);
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $encrypted);
}
static function new_decrypt($key, $encrypted)
{
$iv_size = openssl_cipher_iv_length('aes-256-ofb');
$key = substr(md5($key), 0, 32);
$encrypted = base64_decode($encrypted);
$iv = substr($encrypted, 0, $iv_size);
$encrypted = substr($encrypted, $iv_size);
$decrypted = openssl_decrypt($encrypted, 'aes-256-ofb', $key, OPENSSL_RAW_DATA, $iv);
$tmp = unserialize($decrypted);
$decrypted = current($tmp);
return $decrypted;
}
Both function sets can encrypt and decrypt data; however they are not compatible with each other.
What am I missing here?
First and foremost: Rijndael is not AES.
While AES is descended from/closely related to Rjindael, and may even have certain compatible implementations under very strict interpretations, more often than not they are not compatible at all. The implementations of Rijndael in mcrypt and AES OpenSSL are not compatible. [note: not a cryptographer, some amount of this paragraph might be BS aside from the words 'not compatible']
That said, you can use a library like phpseclib/mcrypt_compat to shim Rijndael and other functionality back into PHP8 and above.
However, since this library code will be running in userspace rather than a compiled extension the performance will likely be noticeably worse. My suggestion would be to use mcrypt_compat to migrate older encryption versions to something OpenSSL-compatible, or at least more current and broadly used/implemented, like AES.
I want to encrypt data in livecode using mergAESEncryptWithKey pData,pKey,pIV,[pMode],[pKeySize],[pPadding]. The encrypted data is then posted to php. PhP decrypts the data using the same function, does something with the data and then encrypts the results and posts them to livecode. Livecode then decrypts the data from php
My PHP Code looks like this (This works perfect)
function encrypt($plaintext, $salt) {
$method = "AES-256-CBC";
$key = hash('sha256', $salt, true);
$iv = openssl_random_pseudo_bytes(32);
$ciphertext = openssl_encrypt($plaintext, $method, $key, $iv);
$hash = hash_hmac('sha256', $ciphertext . $iv, $key, true);
return $iv . $hash . $ciphertext;
}
function decrypt($ivHashCiphertext, $salt) {
$method = "AES-256-CBC";
$iv = substr($ivHashCiphertext, 0, 32);
$hash = substr($ivHashCiphertext, 32, 48);
$ciphertext = substr($ivHashCiphertext, 64);
$key = hash('sha256', $salt, true);
//if (!hash_equals(hash_hmac('sha256', $ciphertext . $iv, $key, true), $hash)) return null;
return openssl_decrypt($ciphertext, $method, $key, $iv);
}
echo $encrypted."</br>";
echo "----------------------------The message is:<br/>";
echo decrypt($encrypted, 'hashsalt');
For most of you who just don't know but still want to post good for nothing comments, I figured it out. #Sammitch and #Mark asking a question don't mean someone is stupid.
/*
* Encrypt or decrypt data using
* AES-256-CBC
*/
function encrypt_decrypt($mode,$data,$key,$salt){
//define the cipher method
$ciphering = "AES-256-CBC";
// Use OpenSSl Encryption method. This works on PHP 7.2 and above
$iv_length = openssl_cipher_iv_length($ciphering);
$options = 0;
if($mode=="encrypt"){
// Use openssl_encrypt() function to encrypt the data
$Data = openssl_encrypt($data, $ciphering, $key, $options, $salt);
}else{
// Use openssl_decrypt() function to decrypt the data
$Data = openssl_decrypt($data, $ciphering, $key,$options, $salt);
}
return $Data;
}
Oooh and this is for livecode
//encrypt
encrypt tString using "aes-256-cbc" with key theKey and IV saltHash at 256 bit
//decrypt
decrypt base64Decode(varEnc) using "aes-256-cbc" with key theKey and IV saltHash at 256 bit
I can encrypt strings in php but I cannot decrypt my strings in php when calling the decrypt function, I get a null response. What am I doing wrong? my code is below.
<?php
$txt = "Hello";
$mykey = "mysecretkey12345";
$iv_to_pass_to_decryption = 'mysecretpass23456';
function encrypt($text, $key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv_to_pass_to_decryption = base64_encode($iv);
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv));
}
function decrypt($text, $key, $ivdecrypt)
{
$text = base64_decode($text);
$ivdecrypt = base64_decode($ivdecrypt);
return base64_decode(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $ivdecrypt));
}
$encryptdata = encrypt($txt, $mykey); // encrypt works fine
$decryptdata = decrypt($encryptdata, $mykey, $iv_to_pass_to_decryption); // Im getting null response from decrypt
echo 'Encrypt: ' . $encryptdata . ' Decrypt: ' . $decryptdata;
?>
Example echo output is:
Encrypt: j42DGZVT/cKIWEe5p3289aWGOZCtZ8yN3MuUidi2InM= Decrypt:
There are two issues I see:
a) The encrypt function assigns the iv to a local variable. You can make it global by including global $iv_to_pass_to_decryption;at the beginning of the encrypt function.
b) In the return statement of the decrypt function you base_decode the message. But you don't encode it going in. Just remove the base64_decode after return.
The command "openssl passwd -1" uses MD5 based BSD password algorithm 1 to compute a string hash.
Example:
openssl passwd -1
$1$./j/us.N$P2tq6IkO0Zu2d3uqkEHpv.
How do I implement exactly the same functionality in PHP? I'd like it to be a native PHP function, rather than something return by exec/shell_exec.
Example code
<?php
define('KEY', 'scret key');
function encrypt($value)
{
$iv = openssl_random_pseudo_bytes(16);
$encrypt = openssl_encrypt($value, 'AES-128-CBC', KEY, 0, $iv);
return base64_encode($encrypt . ':::' . $iv);
}
function decrypt($data)
{
$data = base64_decode($data);
list($data, $iv) = explode(':::', $data);
return openssl_decrypt($data, 'AES-128-CBC', KEY, 0, $iv);
}
$enc = encrypt('password');
echo decrypt($enc);
I found out that I should not use global variables like global $auth_key for sensitive data's (Correct me if that's not true.) so I wanted to use defined variables for storing security keys.
Inside config.php salt keys are defined.
define('AUTH_KEY','::~K~UC*[tlu4Eq/]Lm|h');
define('SECURE_AUTH_KEY', 'QsTMvbV+tuU{K26!]J2');
In encryption.php contains the encryption functions where AUTH_KEY and SECURE_AUTH_KEY will be used inside.
function encrypt_text($value) {
if(!$value) return false;
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, **AUTH_KEY_HERE**, $value, MCRYPT_MODE_ECB, **SECURE_AUTH_KEY_HERE**);
return trim(base64_encode($crypttext));
}
function decrypt_text($value) {
if(!$value) return false;
$crypttext = base64_decode($value);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, **AUTH_KEY_HERE**, $crypttext, MCRYPT_MODE_ECB, **SECURE_AUTH_KEY_HERE**);
return trim($decrypttext);
}
Is there a way to do that? or any other solutions you can recommend? Please note that these keys are real important for encryption of sensitive informations.
Also, a another question, what is the maximum length of keys to be used on mcrypt?
Thank you and looking forward for reply of yours.
as a rule: the logner the key, the stonger the encryption. Secondly, don't use ECB unless your data is very short, you ought to use CBC or something stronger. Third: use a salt or initialization vector. Lastly read this: https://www.owasp.org/index.php/Cryptographic_Storage_Cheat_Sheet
Using a constant is just like using a variable except there is no dollar sign.
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, AUTH_KEY, $value, MCRYPT_MODE_ECB, SECURE_AUTH);
There is nothing inherently more secure in this approach over using the global key word. Though this approach is preferred. By using a constant you are saying this is a static value I will use across the application. Having to use global on the other hand is often just a result of bad design or laziness. It leads to code that is hard to follow, abusing what scoping tries to accomplish.
Key length is dependent on the encryption algorithm used. RTM.
Yes you can use the define variable like you are doing, see the example
define('AUTH_KEY','::~K~UC*[tlu4Eq/]Lm|h');
function abc()
{
echo AUTH_KEY;
}
abc(); // ::~K~UC*[tlu4Eq/]Lm|h
http://codepad.viper-7.com/tUAg6D
Although choosing constants would be preferable over plain variables, this kind of information is better stored inside a configuration file rather than your code.
Also, for better reuse and avoid having those global values lying around it would be a better idea to encapsulate the functionality:
class MyCrypto
{
private $key;
private $cipher;
private $mode;
public function __construct($key, $cipher, $mode = "cbc")
{
$this->key = $key;
$this->cipher = $cipher;
$this->mode = $mode;
}
public function generate_salt()
{
return mcrypt_create_iv(
mcrypt_get_iv_size($this->cipher, $this->mode),
MCRYPT_DEV_URANDOM
);
}
public function encrypt($data) { ... }
public function decrypt($data) { ... }
}
I've added a salt generator function to be used for every encryption operation;
Lastly, I would recommend using CBC mode - MCRYPT_MODE_CBC.
Update (27/09/17):
Since mcrypt_encrypt is DEPRECATED as of PHP 7.1.0. Ive added a simple encrypt/decrypt using openssl.
function encrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') {
// hash
$key = hash('sha256', $key);
// create iv - encrypt method AES-256-CBC expects 16 bytes
$iv = substr(hash('sha256', $secret), 0, 16);
// encrypt
$output = openssl_encrypt($string, $method, $key, 0, $iv);
// encode
return base64_encode($output);
}
function decrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') {
// hash
$key = hash('sha256', $key);
// create iv - encrypt method AES-256-CBC expects 16 bytes
$iv = substr(hash('sha256', $secret), 0, 16);
// decode
$string = base64_decode($string);
// decrypt
return openssl_decrypt($string, $method, $key, 0, $iv);
}
$str = 'Encrypt this text';
echo "Plain: " .$str. "\n";
// encrypt
$encrypted_str = encrypt($str);
echo "Encrypted: " .$encrypted_str. "\n";
// decrypt
$decrypted_str = decrypt($encrypted_str);
echo "Decrypted: " .$decrypted_str. "\n";
In your example, you are using the same initialization vector **SECURE_AUTH_KEY_HERE** when you can allow PHP to create the iv for you this way you only need 1 SECURE_KEY defined.
<?php
define('SECURE_KEY',md5('your secret key'));
/**
* Encrypt a value
*/
function encrypt($str){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SECURE_KEY, $str, MCRYPT_MODE_ECB, $iv);
}
/**
* Decrypt a value
*/
function decrypt($str){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, SECURE_KEY, $str, MCRYPT_MODE_ECB, $iv));
}
//32
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
//Create an initialization vector (IV) from a random source
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
echo decrypt(encrypt('Encrypt me'));
?>