I see base64_encode can encode values, but without a key. I need a function that takes a salt and data, encodes it, and can be decoded with the same salt (but if you try to decode it without the salt, it gives you gibberish).
Is there a PHP function for this (can't find it, only modified versions of base64_encode).
EDIT: Found the answer: use mcrypt ciphers
What about taking a look at http://www.php.net/manual/en/book.mcrypt.php
Related
I'm using esp32 (Arduino platform not esp-idf) with the "HTTPClient.h" library to send get requests with parameters to my PHP server.
I want to encrypt the parameter values and decrypt them in my PHP code And vice versa (my server sends back JSON data to my esp32).
I tried using the XXTEA protocol with these libraries for PHP, and for esp32.
But the encrypted string won't decrypt properly on PHP.
Example:
When I encrypt "HELLO WORLD" on my esp32 with the key "ENCRYPTION KEY" I get this:
35bd3126715874f741518f4d
And when I decrypt it on PHP it returns blank.
Moreover, when I encrypt it on my PHP server I get this:
T1YNYC4P4R2Y5eCxUqtjuw==
My esp32 sketch looks like this:
#include <xxtea-iot-crypt.h>
void setup() {
Serial.begin(115200);
}
void loop() {
String plaintext = "HELLO WORLD";
// Set the Password
xxtea.setKey("ENCRYPTION KEY");
// Perform Encryption on the Data
Serial.print(F(" Encrypted Data: "));
String result = xxtea.encrypt(plaintext);
Serial.println(result);
// Perform Decryption
Serial.print(F(" Decrypted Data: "));
Serial.println(xxtea.decrypt(result));
delay(2000);
}
My PHP code looks like this:
require_once('xxtea.php');
$str = "HELLO WORLD"
$key = "ENCRYPTION KEY";
$encrypt_data = xxtea_encrypt($str, $key);
error_log($encrypt_data);
Is there a way to have an encrypted strings communication between PHP and esp32?
Thanks in advance.
This problem may result from inputs being of different data type, since no current XXTEA implementation seems to do any type or range checking.
Or it could be due to different endian behavior of the two computers involved, since binary is typically stored as an array of words constructed from bytes.
Or it could be due to lack of official or standard reference examples for correct encryption of a specific string and key. In the absence of reference examples (using either hexadecimal or base64 conversion of the binary encryption result) there is no way to tell whether an implementation of encryption is correct, even if its results decrypt correctly using a corresponding decryption implementation.
ADDED:
I think I've found one compatibility problem in the published code for XXTEA. It may be worth taking some space here to discuss it.
Specifically, the problem is that different implementations create different results for encrypting the same plaintext and key.
Discussion:
This problem results from the addition of the length of the plaintext as the last element of the array of longs. While this solves the problem of plaintext that has a length that is not a multiple of 4, it generates a different encrypted value than is generated by the JavaScript implementation.
If you insert "$w=false;" at the start of the long2str and str2long functions, the encrypted value for the PHP implementation becomes the same as the JavaScript implementation, but the decrypted value has garbage at the end.
Here are some test case results with this change:
PHP:
text: >This is an example. !##$%^&*(){}[]:;<
Base64: PlRoaXMgaXMgYW4gZXhhbXBsZS4gIUAjJCVeJiooKXt9W106Ozw=
key: 8GmZWww5T97jb39W
encrypt: sIubYrII6jVXvMikX1oQivyOXC07bV1CoC81ZswcCV4tkg5CnrTtqQ==
decrypt: >This is an example. !##$%^&*(){}[]:;<��
Note: there are two UTF-8 question-mark characters at the end of the "decrypt" line.
JavaScript:
text: >This is an example. !##$%^&*(){}[]:;<
Base64: PlRoaXMgaXMgYW4gZXhhbXBsZS4gIUAjJCVeJiooKXt9W106Ozw=
key: 8GmZWww5T97jb39W
encrypt: sIubYrII6jVXvMikX1oQivyOXC07bV1CoC81ZswcCV4tkg5CnrTtqQ==
decrypt: >This is an example. !##$%^&*(){}[]:;<
The reason there is no garbage in the JavaScript implementation even though it does not save the length of the plaintext is given in a comment there: "note running off the end of the string generates nulls since bitwise operators treat NaN as 0". In other words, the generated string is padded with NULs that are never seen, even though JavaScript, like PHP, can include NULs in strings because it stores the length separately.
I don't have an opinion about which approach is best, but one should be chosen for all implementations.
The reason that there should be a standard for the result of encryption (regardless of whether the binary is converted to hex or to base64 for safe transit) is that one might want to use, say, PHP for encoding but JavaScript for decoding, depending on which languages are natural to use at two locations. After all, encryption is most often used to communicate between two locations, and the language used at the target location might not even be known.
Why not using the wificlientsecure library? Works great on the esp32.
Let's say we need to store in a crypted way some confidential data into a db. And say that we need them into json format as will be more suitable for data reconstruction.
There's something that I miss that is driving me crazy.
Take that json for instance
$json = {"customer":{"customer_address":"Fake address 123","customer_city":"Fake City","customer_company":"","customer_countrycode":"it","customer_email":"","customer_telephone":"+39.347.xxxxxxx","customer_zip":"yyyyy"},"currency_code":"EUR","commision_amount":"84"}
now I want to crypt this json and I do the following
$pubKey = openssl_pkey_get_public($puk);
openssl_public_encrypt($json, $json_crypted, $pubKey);
if I echo $json_crypted it doesn't show anything, but if I remove some field (like customer_company, that is empty) all seems to work. I've tried to find something into documentation about this strange behaviour but I can't find anything.
Is someone aware of the reason behind that result?
Edit
Even if I remove other field (not an empty one) all seems to work. I'm speechless because it has to be a silly thing that I can't understand
From the comments in documentation:
http://www.php.net/manual/en/function.openssl-public-encrypt.php#95307
openssl_private_encrypt() has a low limit for the length of the data
it can encrypt due to the nature of the algorithm.
To encrypt the larger data you can use openssl_encrypt() with a random
password (like sha1(microtime(true))), and encrypt the password with
openssl_public_encrypt(). This way the data can be encrypted with a
public key and decrypted with the private one.
Your json must exceed the length limit...
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.
for a small project I need identical md5 hashes for both JS and PHP.
Im using this javascript to convert a word to md5 (the .min version)
the word 'hello' outputs in
JS: ec59d44dee488759467970486fc9402d
PHP: 5d41402abc4b2a76b9719d911017c592
so they are not identical. I've tried to use md5(utf8_encode($word)); instead of md5($word);
but both gave the same result.
Any ideas? Help is much appreciated
The md5 function on phpjs gives the correct results. It is dependent on utf8_encode, so you need that as well.
If you want to generate md5 value in Javascript, you may use this md5 package
var md5 = require('md5');
console.log(md5('message'));
Then, use this md5 online tool to verify the result.
I was attempting to
encrypt de cookie data with md5, but I can not validate the hash back.
It has got to do, with the fact that cookie_data is a serialized array, because normal stringvalues work ok.
It's actually from a codeigniter class, but it does not work??
Does anyone know what the problem might be?
$hash = substr($session, strlen($session)-32);
$session= substr($session, 0, strlen($session)-32);
if ($hash !== md5($session.$this->encrypt_key))
{........
and the cookie value is encrypted like this
$cookie_data = $cookie_data.md5($cookie_data.$this->encrypt_key);
EDIT
I found that the answer is to use urlencode en urldecode in the proces of creating and validate
md5 hashes, because setcookie does urlencode automaticly, and thereby possibly changing the hash.
thanks, Richard
You have a typo:
md5($sessie.$this->encrypt_key))
should be
md5($session.$this->encrypt_key))
If you develop with notices turned on you'll catch this kind of thing much more easily.
You're not encrypting your data, you're signing it.
md5 is a oneway function. It is not a reversible one, so you can't decrypt the data.
The only thing you can do is encrypt the original data (if you saved it elsewhere) and check the result of this second computation.
If the value retrieved and the new value calculated are the same, the hash you received is valid (As you are doing in your code).
EDIT
You know, with just three lines of code I will guess some possible causes:
$session doesn't contains at the beginning of your code the same value of cookie_data.
you are using multibyte strings and strlen is not mb aware (use the idioms substr($session,0,-32) to get the payload part of the string.
maybe substr doesn't cope with multibyte strings too, use explicitally mb_substr (or whatever it is called).
To me the first case is the more probable. For what I can see.
I was attempting to encrypt de cookie
data with md5, but I can not decrypt
it back for validation.
md5 isnt an encryption method. it creates a one-way hash that cant be turned back into the original data.
If you want to encrypt data try mcrypt