1

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!

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
Joel Murphy
  • 2,472
  • 3
  • 29
  • 47
  • Please post the code you use to encrypt in Node.js beside the code you use to encrypt in PHP and show the same input/output being run through both. That will make it easier to diagnose. – Patashu Jun 06 '13 at 00:47
  • The code is referenced to in the post (on GitHub) https://gist.github.com/schakko/2628689 Sorry if this is a little unclear :) – Joel Murphy Jun 06 '13 at 00:51
  • It looks like there's a lot of crypto operations on Node.JS side that isn't on PHP side. – Patashu Jun 06 '13 at 01:04
  • how is the data transferred between servers? –  Jun 06 '13 at 01:22
  • Using http with the socket.io module, and just plain ajax XMLHttpRequests. – Joel Murphy Jun 06 '13 at 01:25
  • 2
    then i would suggest using a ssl instead of your current apporach –  Jun 06 '13 at 02:26
  • 1
    Yes! I agree to use SSL. SSL encrypts all the incoming and outgoing transactions using 256 Bits encryption algorithms. – Ashwin Hegde Jun 06 '13 at 03:58
  • But doesn't SSL only encrypt data over actual sockets? So for example between the client and the server? I sorta understand where you guys are coming from, but what if I want to encrypt data on the client side too? I would want to do this to hide the real values that I'm sending over to my server via ajax. This would 1. Stop the user from learning my application's internal structure. 2. Prevent any false ajax requests being sent out (because of the fact that encryption is in place with they key being changed often). Its just another layer of security that I think could be useful. – Joel Murphy Jun 06 '13 at 08:08

1 Answers1

0

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:

  1. Unless you specify OPENSSL_RAW_DATA, openssl_encrypt() will automatically base64 encode the output for you, so the second output is double-encoded.
  2. 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.

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206