Reputation: 271
I want to decrypt a encrypted string (encrypted in Nodejs) using PHP passed to the server.
I have found the perfect Nodejs encrypt/decrypt library: Cryptr. I've created a connection in my JavaScript file sending a request to my server with the encrypted string in it.
Now basically I want to decrypt that string.
Taking a look at the Cryptr source, it seems they're using aes-256-ctr
as algo method, and sha256
as encryption method.
My Nodejs: https://runkit.com/embed/keu82yjhwyxj
Encrypted string: 1d510024ad0a5da624b76a2be72022bff3aaadfe8ac5e0b6c178b00333
Then I do this in PHP:
<?php
$encrypted = "1d510024ad0a5da624b76a2be72022bff3aaadfe8ac5e0b6c178b00333";
$algorithm = "aes-256-ctr";
$secret_key = "myTotalySecretKey";
$iv = "";
$decrypted_data = openssl_decrypt(pack('H*', $encrypted), $algorithm, $secret_key, OPENSSL_RAW_DATA, $iv);
echo $decrypted_data;
But since the IV is randomly generated in Cryptr, how would I generate this in PHP?
How can I decrypt Cryptr encrypted strings using PHP, so it returns "I love pizza!"?
Edit:
Instead pack('H*', $encrypted) try with $encrypted only. Also, you need only data, method and key for decryption.
<?php
$encrypted = "1d510024ad0a5da624b76a2be72022bff3aaadfe8ac5e0b6c178b00333";
$algorithm = "aes-256-ctr";
$secret_key = "myTotalySecretKey";
$decrypted_data = openssl_decrypt($encrypted, $algorithm, $secret_key);
echo $decrypted_data;
Upvotes: 1
Views: 340
Reputation:
DO NOT USE CRYPTR. It is insecure. I have opened an issue with the developer, although I'm not sure how it can be fixed without a complete rewrite of the module.
Cryptr uses the CTR encryption mode. This mode is designed for specific use cases, and is not resistant to malleability attacks. If the contents of any encrypted message are known, it is possible to transform that message into any other message. For example, given the encrypted string from the usage sample:
const cryptr = new Cryptr('myTotalySecretKey');
const encryptedString = cryptr.encrypt('bacon');
const decryptedString = cryptr.decrypt(encryptedString);
console.log(encryptedString); // "bcb23b81c4839d06644792878e569de4f251f08007"
(Note that the encrypted string isn't even the same length as what is shown in the module usage. This is an apparent error in their documentation.)
Without knowledge of the key, it is possible to modify this string to make it decrypt to "hello":
var tmp = Buffer.from(encryptedString, "hex");
var b1 = Buffer.from("bacon"), b2 = Buffer.from("hello");
for (var i = 0; i < b1.length; i++) {
tmp[i + 16] ^= b1[i] ^ b2[i];
}
var ep = tmp.toString("hex");
console.log(ep); // "bcb23b81c4839d06644792878e569de4f855ff8306"
And indeed:
var dp = cryptr.decrypt(ep);
console.log(dp); // "hello"
This is a really big deal from a cryptographic perspective. An attacker has just modified an encrypted message in transit, and you have no way of detecting it.
Don't use this module. If you need portable encryption, use the Sodium library; there are bindings available for both Node and PHP.
Upvotes: 2
Reputation: 372
You need to pass IV as you pass message and security key.
So I did little test
$encrypted = openssl_encrypt("test", "aes-256-ctr", "123", 0, "aaaaaaaaaaaaaaaa");
$algorithm = "aes-256-ctr";
$secret_key = "123";
$iv = "";
$decrypted_data = openssl_decrypt($encrypted, $algorithm, $secret_key, 0, "aaaaaaaaaaaaaaaa");
echo $decrypted_data;
And it Works. Yes, it's randomly generated, but you can and have to pass it(as encrypted message) to the server.
I'm not sure what is the purpose of IV parameter but PHP gives you warning if IV param is empty.
I just found this on GitHub page for Cryptr. It says:
The iv is randomly generated and prepended to the result
Upvotes: 0