AES encryption in php and then decryption with Javascript (cryptojs) - php

I'm searching for a way to make a 2 way encryption of a simple text (5 to 6 numbers and/or characters). The catch is that i want to make the encryption in php and then decrypt it via Javascript. For php i've tested using mcrypt_encode and have gotten it to work, hence when i try to decrypt it with javascript (i'm using the Crypto-js library - http://code.google.com/p/crypto-js/ ) i get no results. Here is the php code i'm using:
$key = "oijhd981727783hy18274";
$text = "1233";
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC,$iv);
echo base64_encode($crypttext);
and then here is the Javascript code i'm using:
var encrypted = CryptoJS.enc.Base64.parse("LiJU5oYHXRSNsrjMtCr5o2ev7yDFGZId85gh9MEXPeg=");
var key = 'oijhd981727783hy18274';
var decrypted = CryptoJS.AES.decrypt(encrypted, key);
document.write( decrypted.toString(CryptoJS.enc.Utf8) );
As i'm just testing, i copy/paste the output from the php straight into the JS and see if it would return any results, however that doesnt happen. As i'm new to the encryption/decryption part i might be missing something. Any suggestions will be greatly appreciated.
On a side note, as i read a lot of suggestions here about using other types of communication to transfer the data, that would not be possible in this case, as i need to pass this string to a third party software, which will bring it over on a secure area, where i have access to edit only the javascript, this is why i'm trying to encrypt the text in php and place it inside the website's source, from where the third party software will read it as it is encrypted and will transfer it to the secure section, where i will need to decrypt it back via Javascript (i dont have access to php there).

So, after some more digging i came to the following online encryptor/decryptor which led me to the gibberish-aes at GitHub repository.
Inside one of the comments on the first link i found that this JS library has a php equivalent, which seems to be working reasonably well and is fairly easy to deploy:
https://github.com/ivantcholakov/gibberish-aes-php
So thanks to Lars for the answer he provided, i would encourage him to open the repository, i'm sure he'll make someone's life a little bit easier :)

From the CryptoJS documentation:
For the key, when you pass a string, it's treated as a passphrase and used to derive an actual key and IV. Or you can pass a WordArray that represents the actual key. If you pass the actual key, you must also pass the actual IV.
So in your line
var decrypted = CryptoJS.AES.decrypt(encrypted, key);
"oijhd981727783hy18274" is treated as a passphrase to create a key and not as the actual key.
Passing an IV works like this:
var key = CryptoJS.enc.Hex.parse('000102030405060708090a0b0c0d0e0f');
var iv = CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');
var encrypted = CryptoJS.AES.encrypt("Message", key, { iv: iv });

Some time ago I had the same problem. I finally got to use SlowAES from http://code.google.com/p/slowaes/ with some fixes and ported it to PHP.
Note: The official sources are broken, just as the official PHP port.
Let me know if you're interested. Then I'd open a new repository at GitHub where you can grab everything you need...

Related

aspnet_membership password decryption via PHP

I've spent better half of the day trying to figure out the problem I have, and I'm at a dead end it seems.
I have a ASP application(no access to actual code, just database), in which the user passwords are stored in aspnet_membership > Password column, it also has a salt.
I've also got a copy of the machine key file, which from what I understand contains the keys neede to decryot the password?
<machineKey validationKey="**validation key**" decryptionKey="**decryption key**" validation="SHA1" decryption="AES"/>
i've tried a bunch of different ways of doing this, with open ssl, with different libraries, etc. However I seem to lack knowledge when it comes to this. I'm currently trying to use https://github.com/phpseclib/phpseclib library to decrypt the password:
$cipher = new AES(); // could use AES::MODE_CBC
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
//$cipher->setKeyLength(128);
$cipher->setKey(**decrypt key**);
// the IV defaults to all-NULLs if not explicitly defined
$cipher->setIV($salt);
echo $cipher->decrypt($password);
However any way i'm trying todo this, I get either random return or false. I've got a very limited amount of info about the version of AES running on the ASP application or any other encryption info. Any help would be appreciated!
Hi This MachineKey has nothing to do with Salt, the salt is generating by the code at run-time using the Password provided.
.NET framework using Rfc2898DeriveBytes for encryption
Something like this
using (Rfc2898DeriveBytes rfc2898DeriveByte = new Rfc2898DeriveBytes(password, 16, 1000))
{
salt = rfc2898DeriveByte.Salt;
bytes = rfc2898DeriveByte.GetBytes(32);
}

Encryption with Node Crypto - Decryption with PHP openssl_decrypt fails

I'm trying to create a JWT (JSON web token) in a node service which then needs to be checked in a PHP service.
I'm creating the token as per the spec as far as I can tell, and I'm encrypting the signature with the Node crypto library. I've read that the only algorithm that'll work reliably between these technologies is aes-128-cbc so that's the one I'm using.
I had some luck using mcrypt_decrypt, but it was still not 100% correct which is still a fail. Also because that library is deprecated I'd rather use openssl_decrypt, which I cannot get to work at all, it simply returns false.
The secret and init vector are both stored in a database in fields of type varchar(16), so they are the same in both bits of code. I'm using a 16byte blocksize so matching that with 16byte secret and iv.
I've tried different combinations of binary, hex and base64 formats but cannot get the openssl_decrypt function to return anything but false.
This question comes down to how can I encrypt a string in node and decrypt it in PHP? Or what is wrong with my current usage of these methods?
Node v7.4.0
var crypto = require('crypto');
var secret = crypto.randomBytes(16);
var iv = crypto.randomBytes(16);
var header = { type:'JWT', alg: 'aes-128-cbc' };
var payload = { iss: 'auth-token', exp: Date.now() + 86400, token: <some uuid> };
var data = new Buffer(JSON.stringify(header)).toString('base64') + '.' + new Buffer(JSON.stringify(payload)).toString('base64');
var cipher = crypto.createCipheriv('aes-128-cbc', secret, iv);
var encrypted = cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
var JWT = data + '.'+ encrypted;
PHP v7.0.13 (also tried v7.1.1)
list($header64, $payload64, $sigEnc) = explode('.', $_POST['jwt']);
$header = base64_decode ($header64);
$payload = base64_decode ($payload64);
$signature = openssl_decrypt($sigEnc, 'aes-128-cbc', $secret, null, $iv); // secret and iv are both straight out of the database
Update
I've changed my objective here now and used a hash, which is possibly the correct way. So in the Node service I create a SHA256 hash of the base64 header and payload using a random key stored in the database. Then in the PHP service I do the same and compare the hashes. This is a better approach, which I should have taken before.
But there is still the question of how can you reliably encrypt a string in Node and decrypt it in PHP?
There are libraries but they seem a little overkill for what should be fairly straightforward.
It should be fairly straightforward but apparently it isn't.
With cryptography you either understand it well enough to implement the algorithms yourself from scratch, or you don't try because it's too risky to get it wrong. It's bad enough when you make a mistake like you did when nothing works, but it is way worse when it seems to work but is weak and vulnerable to some attack that you didn't think about.
If you're serious about security then use the right tool for the job. In Node you have:
https://www.npmjs.com/package/jwt
https://www.npmjs.com/package/jsonwebtoken
https://www.npmjs.com/package/jwt-simple
https://www.npmjs.com/package/express-jwt
and many more.
For PHP you have:
https://github.com/firebase/php-jwt
https://github.com/namshi/jose
https://github.com/lcobucci/jwt
https://github.com/emarref/jwt
https://github.com/Spomky-Labs/jose
https://github.com/nov/jose-php
See https://jwt.io/ for more info, more tools and more tutorials.
If you want to learn how to do it correctly yourself without using a library, then read the source code of those libraries - they are all open source, free software.

Adding an encryption method?

Encryption is a topic that I have literally no experience with whatsoever until I actually learn about it at University next year (excluding basic knowledge of simple cyphers). I'll hopefully understand them better in the future, but for now I'd just llike to implement them into my apps without knowing the inner details.
Scenario
I'm trying to secure one of my PHP/NodeJS apps by adding encryption to it. I'm doing this so I can share data between NodeJS and PHP in a secure manner.
PHP server -> Needs to be able to encrypt and decrypt data
NodeJS server -> Only needs to be able to decrypt data
Possible solutions
I've spent hours searching for a decent solution to my problem. I've tried many code samples, but this seems to be the best code sample that I've come across and tested so far.
As you can see from the code, decryption methods have been built for both NodeJs and PHP. Both appear to work very well so far from what I've tested. That's half of my problem solved already. :-)
What I'm trying to do now, is figure our how to implement an encryption function with PHP code. I've tried this:
print "Encrypted: " . base64_encode(openssl_encrypt("Hello world", 'aes-256-cbc', $password));
but I get the output of: aUZaNnFlWWV5M0dObTE1U3pxMENwdz09 when I should in fact be getting the value of edata as output: U2FsdGVkX18M7K+pELP06c4d5gz7kLM1CcqJBbubW/Q=
Does anyone know why this output is different? I'm obviously doing something wrong, but I just can't figure out what I should be doing as there is so much going on in that PHP code... If someone could give me a little guidance that would be great. Thanks!
but I get the output of: aUZaNnFlWWV5M0dObTE1U3pxMENwdz09 when I should in fact be getting the value of edata as output: U2FsdGVkX18M7K+pELP06c4d5gz7kLM1CcqJBbubW/Q=
There are two things to keep in mind:
Unless you specify OPENSSL_RAW_DATA, openssl_encrypt() will automatically base64 encode the output for you, so the second output is double-encoded.
The Node.js snippet you linked above does some funky stuff to generate a key and IV, and your PHP snippet doesn't do this at all.
var rounds = 3;
var data00 = password + salt;
console.log("Data00 (Base64): " + new Buffer(data00, "binary").toString("base64"));
md5_hash = new Array();
md5_hash[0] = crypto.createHash("md5").update(data00).digest("binary");
var result = md5_hash[0];
console.log("MD5-Hash[0] (Base64): " + new Buffer(result, "binary").toString("base64"));
for (i = 1; i < rounds; i++) {
md5_hash[i] = crypto.createHash("md5").update(md5_hash[i - 1] + data00).digest("binary");
result += md5_hash[i];
console.log("Result (Base64): " + new Buffer(result, "binary").toString("base64"));
}
Conversely, your PHP snippet uses a naked $password variable and doesn't pass an IV at all, which generates an error:
php > $password = 'password';
php > echo base64_encode(openssl_encrypt("Hello world", 'aes-256-cbc', $password));
PHP Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in php shell code on line 1
NlpwenNFNCtJYjhjOWNIYkNHazZCZz09
So those are your immediate sources of failure:
Your key is different.
The Node.js snippet uses an IV, you do not. You need an IV for AES-CBC.
But also: AES-CBC is not secure by itself. See this answer for what to do instead.

Decrypting the .ASPXAUTH Cookie WITH protection=validation

For quite sometime I've been trying to decipher the ASP .ASPXAUTH cookie and decrypt it using PHP. My reasons are huge and I need to do this, there is no alternative. In PHP so far I have successfully managed to read the data from this cookie, but I cannot seem to do it while it is encrypted. Anyway, here it goes...
First you need to alter your servers Web.config file (protection needs to be set to Validation):
<authentication mode="None">
<forms name=".ASPXAUTH" protection="Validation" cookieless="UseCookies" timeout="10080" enableCrossAppRedirects="true"/>
</authentication>
Then in a PHP script on the same domain, you can do the following to read the data, this is a very basic example, but is proof:
$authCookie = $_COOKIE['_ASPXAUTH'];
echo 'ASPXAUTH: '.$authCookie.'<br />'."\n";//This outputs your plaintext hex cookie
$packed = pack("H*",$authCookie);
$packed_exp = explode("\0",$packed);//This will separate your data using NULL
$random_bytes = array_shift($packed_exp);//This will shift off the random bytes
echo print_r($packed_exp,TRUE); //This will return your cookies data without the random bytes
This breaks down the cookie, or at least the unencrypted data:
Now that I know I can get the data, I removed the 'protection="validation"' string from my Web.config and I tried to decrypt it using PHP mcrypt. I have tried countless methods, but here is a promising example (which fails)...
define('ASP_DECRYPT_KEY','0BC95D748C57F6162519C165E0C5DEB69EA1145676F453AB93DA9645B067DFB8');//This is a decryption key found in my Machine.config file (please note this is forged for example)
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, ASP_DECRYPT_KEY, $authCookie, MCRYPT_MODE_CBC, $iv);//$authCookie is the pack()'d cookie data
This however fails. I've tried variations of IV with all zeros # 16 bytes. I've tried different Rijndael sizes (128 vs 256). I've tried base64_decode()ing, nothing seems to work. I've found this stackoverflow post here and started using variations of the key/iv that are made using sha256, but that isn't really working either.
Anybody have a clue what I should do?
I don't know how encryption is made in .NET AuthCookies, but I can try to answer.
Assuming the encryption occurs in AES CBC-IV mode, with randomly generated IVs, you need to first find out where the IV is.
The code snippet you show cannot work, as you are generating a random IV (which will be incorrect). That being said, even if you get the IV wrong, in CBC mode you will only have the first 16 bytes of your decrypted ciphertext "garbled" and the rest will decrypt properly - you can use this as a test to know if you're doing the rest correctly. In practice when using random IVs, it's very likely that it's prepended to the ciphertext. To check if this correct, you can try to check if len(ciphertext) = len(plaintext) + 16. This would mean that most likely the first 16 bytes are your IV (and therefore it should be removed from the ciphertext before attempting to decrypt it).
Also on your code snippet, it seems you are using the key as an ascii-string, whereas it should be a byte array. Try:
define('ASP_DECRYPT_KEY',hex2bin('0BC95D748C57F6162519C165E0C5DEB69EA1145676F453AB93DA9645B067DFB8'));
Also, this seems to be a 32 byte key, so you need to use AES-256. I don't know how the authcookie looks like, but if it's base64 encoded, you also need to decode it first obviously.
Hope this helps!
Note: I don't recomment doing this for important production code, however - because there are many things that can go wrong if you try to implement even your own decryption routine as you are doing here. In particular, I would guess there should be a MAC tag somewhere that you have to check before attempting decryption, but there are many other things that can go wrong implementing your own crypto.
I understand this may not have been possible for the OP but for other people heading down this route here is a simple alternative.
Create a .net web service with a method like:
public FormsAuthenticationTicket DecryptFormsAuthCookie(string ticket)
{
return FormsAuthentication.Decrypt(ticket);
}
Pass cookie to web service from PHP:
$authCookie = $_COOKIE['.ASPXAUTH'];
$soapClient = new SoapClient("http://localhost/Service1.svc?wsdl");
$params= array(
"ticket" => $authCookie
);
$result = $soapClient->DecryptFormsAuthCookie($params);
I know what a pain is to decrypt in PHP something encrypted in .NET and vice versa.
I had to end up coding myself the Rijndael algorithm ( translated it from another language ).
Here is the link to the source code of the algorithm: http://pastebin.com/EnCJBLSY
At the end of the source code there is some usage example.
But on .NET, you should use zero padding when encrypting. Also test it with ECB mode, I'm not sure if CBC works.
Good luck and hope it helps
edit: the algorithm returns the hexadecimal string when encrypts, and also expects hexadecimal string when decrypting.

PHP mcrypt to ColdFusion decrypt

I am working in a PHP app we have a particular string that we need to encrypt before storing in a database. I can do this in PHP with not problem using mcrypt with a key and a iv. Currently I'm trying to use blowfish because I thought it would be the most flexible as far as decrypting it in ColdFusion. The issue I ran into is it seems ColdFusion doesn't want to use the key or iv I encrypted with. ColdFusion wants you to generateSecretKey() and use some other way to create the iv.
What I can't seem to do is get the two to communicate. I tried first encrypting in coldFusion and using the key it generated and iv it used in PHP but the result was not what it should be. I know I must be missing something but I can't quite pinpoint what it might be.
<?php
$securedString = mcrypt_encrypt ('MCRYPT_BLOWFISH' , 'THISISMYKEYTHATISVERYLONG32CHARS' , "This is the string I need encrypted' , MCRYPT_MODE_CBC , '12345678');
echo base64_encode($securedString);
?>
So what would an equivalent ColdFusion Decryption call look like?
BTW: if Blowfish is not the ideal algorithm to use please feel free to suggest another as long as both ColdFusion and PHP can use it and it is secure.
Thanks,
Bruce
Something like this should work. You just need to share a common key between each.
In PHP:
base64_encode(mcrypt_encrypt(MCRYPT_3DES, $key, $plain_string, MCRYPT_MODE_ECB));
In Coldfusion:
<cfscript>
decrypted_string = decrypt(enc_string, key, "DESEDE", "Base64");
</cfscript>

Categories