Hello i'm using Mcrypt to obfuscate some values i'm sending via mail.
When i encrypt the value on my local site, and decrypt it it works ok in every attempt, i mail the value, but when i link back to my site, and try to decrypt it in another page, it works sometimes only.
I'm kinda stuck and dunno why. I'm not so familiar with crypt functions.
This is the code im using for encrypt
function encrypt($decrypted, $password, $salt='!kQm*fF3pXe1Kbm%9') {
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Build $iv and $iv_base64. We use a block size of 128 bits (AES compliant) and CBC mode. (Note: ECB mode is inadequate as IV is not used.)
srand(); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22) return false;
// Encrypt $decrypted and an MD5 of $decrypted using $key. MD5 is fine to use here because it's just to verify successful decryption.
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $decrypted . md5($decrypted), MCRYPT_MODE_CBC, $iv));
// We're done!
return $iv_base64 . $encrypted;
}
This is the code i'm using for decrypt
function decrypt($encrypted, $password, $salt='!kQm*fF3pXe1Kbm%9') {
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
$iv = base64_decode(substr($encrypted, 0, 22) . '==');
// Remove $iv from $encrypted.
$encrypted = substr($encrypted, 22);
// Decrypt the data. rtrim won't corrupt the data because the last 32 characters are the md5 hash; thus any \0 character has to be padding.
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv), "\0\4");
// Retrieve $hash which is the last 32 characters of $decrypted.
$hash = substr($decrypted, -32);
// Remove the last 32 characters from $decrypted.
$decrypted = substr($decrypted, 0, -32);
// Integrity check. If this fails, either the data is corrupted, or the password/salt was incorrect.
if (md5($decrypted) != $hash) return false;
// Yay!
return $decrypted;
}
The $password and $salt variables are being packed using
pack("H*", $string);
After the first failed attempts, i started using urlencode and urldecode for the values on the URL but still the same issue persists.
What i'm doing wrong? i'm really stuck here
Thanks
Your encoded string is being sent with plus (+) signs, wich are being interpreted on the url as blank spaces, you can encode the URL or use str_replace to change empty spaces on the string for plus's sign
Such.
$encrypted_string= "random1234string with blank space";
$empty = array(" ");
$plus = array("+");
$new_encrypted_string = str_replace($empty, $plus, $encrypted_string);
Outputs: "random1234string+with+blank+space"
Related
I'm trying to convert a PHP encryption function to Python. For the sake of the example and making things easier, the iv and relevant data is preset.
$salt = sha1('12345'.'654321');
encrypt('12345678', 'cutekittens12345', $salt);
function encrypt($decrypted, $password, $salt)
{
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
$hexkey = hash('SHA256', $salt . $password, false);
// Build $iv and $iv_base64. We use a block size of 128 bits (AES compliant) and CBC mode. (Note: ECB mode is inadequate as IV is not used.)
#$iv = mcrypt_create_iv(16, MCRYPT_RAND);
$iv = "0000000000000000";
if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22)
return false;
// Encrypt $decrypted and an MD5 of $decrypted using $key. MD5 is fine to use here because it's just to verify successful decryption.
$concatdecrypted = ($decrypted . md5($decrypted));
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $concatdecrypted, MCRYPT_MODE_CBC, $iv));
// We're done!
return $iv_base64 . $encrypted;
}
Which results in
$salt: 6ed52d21d5cc15e76e9879675f4bd0dd51593652
$hexkey: 879522bb98c1f5fb16acd6bf3454b0d4e313e8b71e0aa3cdf5cbf91158dfde71
$iv_base64: MDAwMDAwMDAwMDAwMDAwMA
$concatdecrypted: 1234567825d55ad283aa400af464c76d713c07ad
$encrypted: C3CWJPt2gtmg+id1ySmSazMvvWC7cgDpovJ/tDN0GeuVv9Pf/9+9ZSG+wjl6qD5h
My cleanest attempt at recreating the function is here and:
from base64 import b64encode, b64decode
from Crypto.Cipher import AES
import hashlib
charid = "654321"
apikey = "12345"
vcode = "12345678"
password = "cutekittens12345"
salt = hashlib.sha1((apikey + charid).encode('utf-8')).hexdigest()
key = hashlib.sha256(salt + password).digest()
iv = "0000000000000000"
concatkey = vcode + hashlib.md5(vcode).hexdigest()
AES.key_size=128
encryptor=AES.new(key=key,mode=AES.MODE_CBC,IV=iv)
encoded = encryptor.encrypt(concatkey_pad)
encoded = b64encode(encoded)
print 'Encrypted string:', encoded
I can recreate everything except the final result. I've tried a combination of unhex to see if it's something to do with passing raw inputs, but none of the $encrypted results have been a match.
Any help would be appreciated thank you.
I tried M2Crypto, Crypto.Cipher and pyDes. After reading 'Lessons learned implementing AES in PHP using Mcrypt' I had success with Crypto.Cipher after padding the string with ascii 0's to bypass the multiples of 16 issue and the first half of the encoded string was a match to my php function.
concatkey_pad = concatkey.ljust(48, '\0')
AES.key_size=128
encryptor=AES.new(key=key,mode=AES.MODE_CBC,IV=iv)
encoded = encryptor.encrypt(concatkey_pad)
encoded = b64encode(encoded)
print 'Encrypted string:', encoded
Padding concatkey with binary 0's using ljust generated the correct encoded value.
I am storing some encrypted information in a MySQL database, but I can't get it back out for some reason. I am storing the encrypted data as BINARY(46). Why is my select statement failing?
Here is my SELECT statement:
SELECT max(created) FROM incentive_sales WHERE incentive_sales.accountID = :aid
So shouldn't I encrypt the accountID (:aid) for my select statement?
Here is my encrypt function:
private function _encrypt($decrypted, $password, $salt = '|SgQLL*ea!UMwf^s%'){
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Build $iv and $iv_base64. We use a block size of 128 bits (AES compliant) and CBC mode. (Note: ECB mode is inadequate as IV is not used.)
srand(); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22){
return false;
}
// Encrypt $decrypted using $key.
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $decrypted, MCRYPT_MODE_CBC, $iv));
return $iv_base64.$encrypted;
}
And my decrypt function:
private function _decrypt($encrypted, $password, $salt = '|SgQLL*ea!UMwf^s%'){
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
$iv = base64_decode(substr($encrypted, 0, 22) . '==');
// Remove $iv from $encrypted.
$encrypted = substr($encrypted, 22);
// Decrypt the data.
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv)
return $decrypted;
}
The correct answer is, "As far as I know, you cannot use encrypted data as a selection in the where clause because it will always be different."
To circumvent this (because I do want to be able to select based on the encrypted data), I also store a hashed/salted value of the encrypted data which I then use in my select statement.
I have 2 encrypt & decrypt functions using PHP mcrypt library.
public function encrypt_string($input, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv . $cipher);
}
public function decrypt_string($input, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$ciphertext = base64_decode($input);
$iv = substr($ciphertext, 0, $iv_size);
$cipher = substr($ciphertext, $iv_size);
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv);
}
Given that the key is generated by:
$key = pack('H*', 'dfgsdighsdfksdhfosdfasdjldsfsdfgdfkgdl'); // a random key
I can successfully obtain back the input after encryption & decryption.
Here is the code:
$pass = '123456';
echo sha1($pass) . PHP_EOL; // prints 7c4a8d09ca3762af61e59520943dc26494f8941b
$pass_cipher = encrypt_string($pass, $key);
$pass_decrypt = decrypt_string($pass_cipher, $key);
echo $pass_decrypt . PHP_EOL; // prints 123456
echo sha1($pass_decrypt) . PHP_EOL; // prints f41b44dbecccaccfbb4ccf6a7fc4921c03878c6d
However, the SHA1 result is different:
7c4a8d09ca3762af61e59520943dc26494f8941b // before encrypt & decrypt
f41b44dbecccaccfbb4ccf6a7fc4921c03878c6d // after encrypt & decrypt
Why is it different ? What did I miss ?
UPDATE:
The accepted answer is useful. For people who wants additional information, here it is:
echo bin2hex($pass) . PHP_EOL; // prints 313233343536
echo bin2hex($pass_decrypt) . PHP_EOL; // prints 31323334353600000000000000000000
and after trim(), the SHA1 result works as expected, as empty hidden 0 are removed.
Problem is that your decrypt_string returns 16 bytes string, that is filled with 0 bytes at the right side. It's a problem known for about 2 years.
Remove null bytes from the right with line similar to this one:
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv), "\0");
Be careful not to encrypt things with null character at the end, as cryptology functions in PHP works as if all strings were null-terminated and are not shy to cut string at first \0 or to return a bit of \0s glued to the end of their output.
in post encrypted data + sign will be replaced with whitespace. thats why decryption was not done .
I'm having totally confounding encryption/decryption results. I have two different strings that I need to encode and later decode, the encrypted string being stored in a MySQL database in between. The first of these strings comes out just fine. However, the second one always returns from decryption with the value FALSE. I've stripped out all of the non-essential factors, and am directly passing a plaintext value of "test" to both encryption routines. Again, the first one returns correctly (as "test") the second one returns as "false").
I'm banging my head against the wall trying to figure out what I am doing wrong. I'm using the same password and the same salt in both files. How is it possible that one will work but the second won't???
One clue: if I put this code into a single php file and bypass the database, it all works just fine. Not sure what to make of this, but it's interesting at least.
Here is the code. The encryption/decryption routine comes from a user post on the php site for mcrypt. Can anyone see it? It's probably something stupid.
setValues.php
$encrypted_email_pw = encrypt("test", $password);
$encrypted_default_pw = encrypt("test", $password);
$sql = "UPDATE Settings
SET email_password='$encrypted_email_pw',
default_pw='$encrypted_default_pw'
WHERE id='$id'";
$result = mysql_query($sql);
getValues.php
$sql = "SELECT * FROM Settings";
$result = mysql_query($sql);
$row = mysql_fetch_array($result); //there is only one row in this table
$decrypted_email_pw = decrypt($row['email_password'], $password);
$decrypted_default_pw = decrypt($row['default_pw'], $password);
echo $decrypted_email_pw . " | " . $decrypted_default_pw;
//output: test | false
die();
crypto.php
<?php
function encrypt($decrypted, $password, $salt='6rVDB?zKe6batB+k') {
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Build $iv and $iv_base64.
// We use a block size of 128 bits (AES compliant) and CBC mode.
// (Note: ECB mode is inadequate as IV is not used.)
srand(); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22) return false;
// Encrypt $decrypted and an MD5 of $decrypted using $key.
// MD5 is fine to use here because it's just to verify successful decryption.
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $decrypted . md5($decrypted), MCRYPT_MODE_CBC, $iv));
// We're done!
return $iv_base64 . $encrypted;
}
function decrypt($encrypted, $password, $salt='6rVDB?zKe6batB+k') {
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
$iv = base64_decode(substr($encrypted, 0, 22) . '==');
// Remove $iv from $encrypted.
$encrypted = substr($encrypted, 22);
// Decrypt the data.
// rtrim won't corrupt the data because the last 32 characters are the md5 hash;
// thus any \0 character has to be padding.
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv), "\0\4");
// Retrieve $hash which is the last 32 characters of $decrypted.
$hash = substr($decrypted, -32);
// Remove the last 32 characters from $decrypted.
$decrypted = substr($decrypted, 0, -32);
// Integrity check. If this fails, either the data is corrupted, or the password/salt was incorrect.
if (md5($decrypted) != $hash) return false;
return $decrypted;
}
?>
Have you checked the two columns in the Settings table? Do they have the same data types?
And are you sure the encrypt() and decrypt() methods work correctly?
After you get this working, you should consider using a random generated salt for each password and store the salt in the table together with the password.
I'm trying to encrypt some information in my code, so I searched for a way to do this.
I found this on php official website:
http://www.php.net/manual/vote-note.php?id=107483&page=book.mcrypt&vote=down
So, I changed it a little bit and I did this:
class EncrypterDecrypter {
private $SECRET = "xxxxxxxxxxxxxxxxxxxx";
function encrypt($decrypted, $salt = 'zzzzzzzzzzzzzzzzzz') {
$password = $this->SECRET;
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Build $iv and $iv_base64. We use a block size of 128 bits (AES compliant) and CBC mode. (Note: ECB mode is inadequate as IV is not used.)
srand();
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22)
return false;
// Encrypt $decrypted and an MD5 of $decrypted using $key. MD5 is fine to use here because it's just to verify successful decryption.
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $decrypted . md5($decrypted), MCRYPT_MODE_CBC, $iv));
// We're done!
return $iv_base64 . $encrypted;
}
public function decrypt($encrypted, $salt = 'zzzzzzzzzzzzzzzzzz') {
$password = $this->SECRET;
// Build a 256-bit $key which is a SHA256 hash of $salt and $password.
$key = hash('SHA256', $salt . $password, true);
// Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
$iv = base64_decode(substr($encrypted, 0, 22) . '==');
// Remove $iv from $encrypted.
$encrypted = substr($encrypted, 22);
// Decrypt the data. rtrim won't corrupt the data because the last 32 characters are the md5 hash; thus any \0 character has to be padding.
$decrypted = rtrim(
mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
$key, base64_decode($encrypted),
MCRYPT_MODE_CBC, $iv),
"\0\4");
// Retrieve $hash which is the last 32 characters of $decrypted.
$hash = substr($decrypted, -32);
// Remove the last 32 characters from $decrypted.
$decrypted = substr($decrypted, 0, -32);
// Integrity check. If this fails, either the data is corrupted, or the password/salt was incorrect.
if (md5($decrypted) != $hash)
return false;
// Yay!
return $decrypted;
}
}
I already tried to change the key and salt size but the warning keeps showing.
I also searched other topics but I could not find any answer, they all look to specific.