Problem
I need to encrypt data in Javascript and decrypt it in PHP. Mcrypt seems the way to go on the PHP side, and AES seems thoroughly good enough, but I'm having trouble finding a javascript decryption algorithm that matches it. Any suggestions? I'm open to replacing any of the assumptions (mcrypt, aes, ECB, etc) if it'll help get a compatible js encryption/decryption library.
Code
The PHP looks pretty much like this:
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $key, $plaintext,
MCRYPT_MODE_ECB,$iv );
Rationale
Not that it matters, but the point here is to encrypt some credentials to an external system so that we can pass it around our server without our analytics and logging servers picking it up in the clear. It'll eventually be decrypted in the PHP just before it's sent to the external system.
I ended up using the SlowAES library, which has parallel implementations in PHP and JS:
http://kevinkuchta.com/_site/2011/08/matching-php-and-js-encryption/
Related
As php has stopped support for Mcrypt from 7.2 and onwards. I do not know enough to convert Mcrypt to Openssl.
I was wondering if someone could provide the OpenSSL equivalent for this? For the record, I am not looking to support Mcrypt so I have to decrypt my mcrypt encrypted strings(passwords) via openSSL.
To Encode via mcrypt->
static function encode($value= NULL, $key= NULL){
if(!$value){
return false;
}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
return trim(self::safe_b64encode($crypttext));
}
private function safe_b64encode($string= NULL) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
Updated
Unfortunately it looks like there is not a way your going to be able to do what you want. Had you used the MCRYPT_RIJNDAEL_128 mode with a 256 byte key there may have been hope.
AES-256 and MCRYPT_RIJNDAEL_256 encryption are not the same thing, even though AES is basically Rijndael. It all has to do with the block size. What you want to do just is not compatible.
Your options are this:
Use a version of PHP that still has the MCRYPT libraries available and decrypt the passwords to a file and then encrypt them with your new encryption method.
A PECL option looks available that would allow you to install a pseudo version of MCRYPT with your latest version of PHP.
For just encrypting and decrypting your passwords OpenSSL should be fine, but
OpenSSL has limitation especially when you want to encrypt large amounts of data. It requires you to write additional code to break apart your data into smaller chunks before you encrypt and then put it back together after you decrypt.
I highly recommend that you skip OpenSSL and learn the LibSodium library which is now supported on the latest PHP versions.
http://php.net/manual/en/book.sodium.php
Here is a good page to read to get you started.
https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly
Some more Libsodium resources.
https://github.com/paragonie/pecl-libsodium-doc/blob/v1/chapters/01-quick-start.md
Good Luck~
You have so many choices when it comes to encrypting data, so that's why you should implement it yourself. I recommend you the library diffuse/php-encryption, see this link for a detailed tutorial.
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 am trying to pass some encrypted data to a flash , but I got stuck somewhere in the middle.
Im using RIJNDAEL algorithm to encode the data in PHP :
function encrypt($text){
$key = "53cded30ff7ba54d65b939fd594e3d63";
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //get vector size on CBC mode
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); //Creating the vector
$cryptedtext = mcrypt_encrypt (MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv); //Encrypting using MCRYPT_RIJNDAEL_256 algorithm
return $cryptedtext;
}
And im using the AS3CRYPT library to decrypt the value in flash.
The problem is that if I try to decode the value in flash or even in the demo of AS3CRYPT, it doesnt work.
I also tried to return the data from PHP encoded with base64_encode but still not working.
The output from PHP is something like : flashvar=Á žJcV—µg)7¾1´‘5{Ò<¶Ù$þS„§”
Probably I did something wrong in the PHP ...
PHP doesn't add any padding, which is likely needed.
You'll have to pad it manually, take a look at this post on PHP.net which explains one method of achieving PKCS7 padding compatibility.
Beyond that, make sure you're setting the matching confidentiality mode (CBC) and cipher within "AS3CRYPTO".
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
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?