I'm trying to perform encryption and decryption (Rijndael 256, ecb mode) in two different components:
1. PHP - Server Side (using mcrypt)
2. C + + - Client Side (using gcrypt)
I ran into a problem when the client side could not decrypt correctly the encrypted data (made by the server side)
so... i checked the:
1. initial vector - same same (32 length)
2. the key - again the same key on both sides..
so i wrote some code in C++ that will encrypt the data (with the same parameters like in the php)
and i found out that the encrypted data contains different bytes (maybe encoding issue??)
I'll be more than glad to get some help
PHP - MCrypt
// Encrypt Function
function mc_encrypt($encrypt, $mc_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$iv = "static_init_vector_static_init_v";
echo "IV-Size: " . $iv_size . "\n";
echo "IV: " . $iv . "\n";
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $mc_key, $encrypt, MCRYPT_MODE_ECB, $iv);
print_hex($passcrypt);
return $encode;
}
mc_encrypt("Some text which should be encrypted...","keykeykeykeykeykeykeykeykeykeyke");
I'll post the C++ code in a comment
Thanks,
Johnny Depp
OK. I'll make my comment an answer:
An Initialization Vector (IV) isn't used in ECB mode. If it is provided different implementations might work differently.
If you want to be sure the implementations will work correctly then use an IV of 0 (zero). Even though you provide the IV, both implementations SHOULD ignore it but one can never be sure about that. Not providing an IV in ECB mode should work aswell but again, it all depends on the implementations.
According to the PHP documentation MCrypt will ignore it. GCrypt I'm not sure about.
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB) should actually return 0 since you specify ECB mode.
Edit:
Do not call mcrypt_get_iv_size or mcrypt_create_iv.
Instead call mcrypt_encrypt without an IV. According to the PHP documentation all bytes in the IV will be set to '\0'.
Same goes for the C++ code. No need to set any IV at all. The libgcrypt code is complex but from glancing at the source of version 1.4.5 then in ECB mode it seems the IV isn't used at all.
If the resulting ciphertext still differs then the problem is something else.
A couple of possibilities comes to mind:
Encoding - Is the same encoding used in both the server and the client?
Endianness - What type of systems are the server and the client? Big- vs Little-endian?
Related
I'm looking for anything about RC4 Decryption with decode the input using: Hexa
Lucky for me, I found
PHP's mcrypt_encrypt.
I want to decrypt many cipher files with the same key.
But, I had a problem with:
$iv_size = mcrypt_get_iv_size(MCRYPT_ARCFOUR, MCRYPT_MODE_STREAM);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
print (mcrypt_decrypt(MCRYPT_ARCFOUR, $key, $text, MCRYPT_MODE_STREAM, $iv));
(And UTF-8 Vietnamese)
The result of echo $iv_size is 0.
Please help me, I don't know how I can fix it?
Key : Lyr1cjust4nct (key file .txt)
Mode: STREAM
Decode the input using: Hexa
Ciphertext: cipher.txt (Hexa)
http://pastebin.com/bmYcmU0J
RC4 doesn't support IVs. You instead need to use a unique key for each message.
RC4 has two big weaknesses that apply to your situation:
Using related keys is not secure. So you can't just concatenate a fixed key with a variable/unique IV. You'd need to use some kind of hashing scheme.
The beginning of the output is very biased, which leaks information about the ciphertext. So you need to throw away the beginning of the key-stream. I think throwing away 1024 bytes should take care of the biggest biases.
RC4 doesn't include any integrity protection (MAC). So if an attacker manipulates the ciphertext, you'll run into problems.
=> Don't use RC4. Use AES in an authenticated mode such as GCM or by combining AES with a MAC using the encrypt-then-MAC principle.
I strongly recommend using a high level library written by experts, since people get encryption wrong very often, even when using standard primitives like AES.
I am trying to encrypt sensitive user data like personal messages in my php powered website before entering into the database. I have researched a bit on the internet and I have found the few important things to remember:
Never use mcrypt, it's abandonware.
AES is based on the Rijndael algorithm and has been unbroken till now.
AES has also been recommended by NSA and used in US Government data encryption, but since the NSA is recommending it, there's a chance they might sneak upon my user data easily.
Blowfish has been unbroken as well, but slow and less popular.
So, I decided I will give it a try first with AES-256 cbc. But I am still not sure if I should not consider Blowfish a better option. So any recommendations are welcome.
And my primary concern is, how to encrypt the data in php? I don't find a good manual about this in the php documentation. What is the correct way to implement it?
Any help is heavily appreciated.
AES-256 (OpenSSL Implementation)
You're in Luck.
The openssl extension has some pretty easy to use methods for AES-256. The steps you need to take are basically...
Generate a 256-bit encryption key (This needs storing somewhere)
$encryption_key = openssl_random_pseudo_bytes(32);
Generate an "initialization vector" (This too needs storing for decryption but we can append it to the encrypted data)
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
encrypt data using openssl_encrypt()
openssl_encrypt($data, 'aes-256-cbc', $encryptionKey, $options, $initializationVector)
the $options can be set to 0 for default options or changed to OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
append the initialisation vector to the encrypted data
$encrypted = $encrypted . ':' . $iv;
retrieve the encrypted data and the initialization vector.
explode(':' , $encrypted);
decrypt data using openssl_decrypt()
openssl_decrypt($encryptedData, 'aes-256-cbc', $encryptionKey, $options, $initializationVector)
Enabling openssl
openssl_functions() won't be available by default, you can enable this extension in your php.ini file by uncommenting the line. ;extension=php_openssl.dll by removing the leading ;
PHP - Fiddle.
http://phpfiddle.org/lite/code/9epi-j5v2
I'm trying to store encrypted cookies in a PHP app and have implemented 2 different encryption libraries in attempts to get this to work.
Both implementations, when deployed to the server, are generating fatal exceptions when calling my encryption function. On my local dev env, however, both encryption implementations are working successfully.
My open_ssl implementation code (works on localhost, does not work on remote server):
set_encrypted_cookie("foo","my_cookie_name");
function set_encrypted_cookie($msg,$name){
$key = '0123456qwerty'; // Key is stored externally but defined locally for debugging
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encryptedStr = openssl_encrypt($msg, 'aes-256-cbc', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
setcookie($name,$encryptedStr,0,'/');
}
Any thoughts on why the server might be not allowing the openssl_encrypt() func to execute?
openssl_encrypt() returns raw binary, you should base64_encode() before storing in a cookie.
Before you do that, a couple of things you can do to improve your cryptography protocol:
Use MCRYPT_DEV_URANDOM, not MCRYPT_RAND.
Store your IV with your ciphertext (before base64_encode()ing it), so you can use the same IV when decrypting.
Encrypt then MAC.
The last link has two functions, setLessUnsafeCookie() and getLessUnsafeCookie(), that you can use as a drop-in on PHP 5.6.x.
There are still two more things to do to make it safe to use:
Use HKDF to split the key into an encryption key and a decryption key.
Use PKCS7 padding on the plaintext.
(If you want to go for maximum security, you can use libsodium instead of openssl.) Also, don't use mcrypt.
I have a working code to generate encrypt data using PHP:
$cipher_alg = MCRYPT_TRIPLEDES;
$iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher_alg,MCRYPT_MODE_ECB), MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt($cipher_alg, $pKey, $string, MCRYPT_MODE_ECB, $iv);
Question is, I run this code multiple time, if the same inputs and always give me the same output for $encrypted_string and a different output for $iv.
So why my encrypt data is always the same if the IV changes?
ECB mode does not use an IV, so it doesn't matter what you pass in or that it's different every time. The documentation for mcrypt_encrypt itself indirectly says so:
iv
Used for the initialization in CBC, CFB, OFB modes, and in some algorithms in STREAM mode. If you do not supply an IV, while it is
needed for an algorithm, the function issues a warning and uses an IV
with all its bytes set to "\0".
You would need to use a chainable mode (CBC etc) to see different results on each iteration -- and in general, ECB mode is a very bad choice. Don't use it.
I'm in the process of rebuilding a PHP web app in Ruby on Rails, and would dearly love to avoid forcing all existing users to reset their encrypted passwords. The PHP site uses mcrypt_encrypt with AES-256-ECB, and I can't for the life of me get the same cipher text using ruby's OpenSSL. I can't decrypt them either (which is good in principle) since what's actually stored in the user DB is an MD5 hash of the AES cipher text.
I've read these previous, closely related questions and the very helpful answers:
How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together
Part II: How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together
including the pages referenced there, and if I understand correctly, the PHP and ruby implementations use different padding methods. Since I have to live with how things work on the PHP side, is there any way to force the same padding method on ruby/OpenSSL somehow? I'm using ruby 1.9.2-p180.
Here's the sample code in PHP:
$salt = "12345678901234567890123456789012";
$plain = "password";
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $plain, MCRYPT_MODE_ECB, $iv);
echo md5($cipher);
Output: 6337137fd88148250fd135a43dbeb84a
and in ruby:
require 'openssl'
salt = "12345678901234567890123456789012"
plain = "password";
c = OpenSSL::Cipher.new("AES-256-ECB")
c.encrypt
c.key = salt
cipher = c.update(plain)
cipher << c.final
puts Digest::MD5.hexdigest(cipher)
Output: 18dee36145c07ab83452aefe2590c391
Actually not in general an openssl solution but maybe it is ok for you to have a working example.
require 'mcrypt'
require 'openssl'
plaintext = 'password'
puts plaintext
key = '12345678901234567890123456789012'
enc = Mcrypt.new(:rijndael_256, :ecb, key, nil, :zeros)
encrypted = enc.encrypt(plaintext)
puts Digest::MD5.hexdigest(encrypted)
I used an additional gem(ruby-mcrypt). Seems to be an issue with openssl. Actually the issue seems to be that Openssl does not support zero padding and uses either no-padding or default-openssl-padding. Due to the fact that you use zero padding in php you must use zero padding also in ruby.
Output on my machine for the php script:
[~/test] ➔ php5 t.php
6337137fd88148250fd135a43dbeb84a
and for the ruby script:
[~/test] ➔ ruby t2.rb
password
6337137fd88148250fd135a43dbeb84a
and my ruby version:
[~/test] ➔ ruby -version
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]
Hope this helps.
if key size is not standard on php side, you need to fill the key with zeros to next valid key size, in order to make ruby side works like this:
php_encrypted = string_encoded_with_php_mcrypt
key = "longerthan16butnot24".to_a.pack('a24')
enc = Mcrypt.new(:rijndael_256, :ecb, key, nil, :zeros)
enc.decrypt(php_encrypted)
In this case next valid key length is 24.
For :rijndael_256 valid key lengths are: 16, 24, 32
You can get more info on algorithms:
Mcrypt.algorithm_info(:rijndael_256
if you can use other encrypt methods, you can try TEA Block Encryption. I have adopted the method across Ruby, JS, ActionScript. It should work with PHP as well. github repo is here