I managed to find a Libsodium js library (JS-NaCl) for front end encryption and has setup my PHP backend for Libsodium encrypt/decrypt also. When I encrypt a JSON object like below
const key = "827ccb0eea8a706c4c34a16891f84e7b"; const nonce = "0123456789abcdefghijvbnm"; var credentials = { "zip":"265", "account_number":"10028979739", "passcode":"1234", "account_type":"personal", "request":"login", "device":"iPhone 11" }; function encrypt(data){ return sodium.crypto_secretbox(sodium.encode_utf8(data),nonce,key); }; function decrypt(data){ return sodium.decode_utf8(sodium.crypto_secretbox_open(data, nonce, key)); } function login(data){ $.ajax({ url:baseURL+"account/account.php", method:"POST", contentType:"application/x-www-form-urlencoded", dataType:"json", data:"datax="+JSON.stringify(encrypt(credentials)), beforeSend:()=>{ console.log(credentials); },success:(response)=>{ console.log(response); },error:(e)=>{ swal("Connection Error","Failed to connect to the server!","error"); } }); }
When I fire the login method with it encrypts the JSON object using the encrypt method hence I send something like this:
datax: {"0":191,"1":118,"2":248,"3":134,"4":45,"5":163,"6":3,"7":157,"8":78,"9":73,"10":157,"11":137,"12":178,"13":6,"14":68,"15":91,"16":217,"17":219,"18":50,"19":11,"20":127,"21":177,"22":130,"23":25,"24":209,"25":254,"26":210,"27":44,"28":119,"29":13,"30":144}
at the php backend code I am doing this:
<?php function decrypt($data){ $key = "e9897cea109576c2f8088c277125d553e4f83afbc0abbb92cfb1f7b776b4fee0"; $nonce = "0123456789abcdefghijvbnm"; return sodium_crypto_secretbox_open($data,$nonce,$key); } function encrypt($data){ $data = utf8_encode($data); $key = "e9897cea109576c2f8088c277125d553e4f83afbc0abbb92cfb1f7b776b4fee0"; $nonce = "0123456789abcdefghijvbnm"; return sodium_crypto_secretbox($data,$nonce,$key); } $credentials = $_POST["datax"]; echo decrypt($credentials); ?>
Same Key, Same nonce but it doesn’t echo back anything. How to I decrypt this??
Advertisement
Answer
The code needs some changes. On the JavaScript side (frontend):
The JavaScript object must be converted into a string.
Besides the data, nonce and key must also be encoded using Utf8. Although the key could also be hexadecimal encoded to a 16 bytes key, in this context it must be Utf8 encoded to a 32 bytes key, because
sodium.crypto_secretbox
expects a 32 bytes key. The expected nonce must be 24 bytes in size.Now the data can be encrypted.
sodium.crypto_secretbox
returns the data asUint8Array
, which must therefore be encoded for transfer into a suitable format, e.g. hexadecimal.
The corresponding code is:
nacl_factory.instantiate(function (sodium) { var credentials = { "zip":"265", "account_number":"10028979739", "passcode":"1234", "account_type":"personal", "request":"login", "device":"iPhone 11" }; // Convert JavaScript object to string var data = JSON.stringify(credentials); // Utf8 encode key, nonce and data var keyUtf8 = sodium.encode_utf8("827ccb0eea8a706c4c34a16891f84e7b"); var nonceUtf8 = sodium.encode_utf8("0123456789abcdefghijvbnm"); var dataUtf8 = sodium.encode_utf8(data); // Encrypt var encrypted = sodium.crypto_secretbox(dataUtf8, nonceUtf8, keyUtf8); // Hex encode encrypted data for transfer var encryptedHex = sodium.to_hex(encrypted); console.log("Ciphertext (hex):n" + encryptedHex.replace(/(.{64})/g, "$1n")); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-nacl/1.3.2/nacl_factory.js"></script>
On the PHP side (backend):
The hexadecimal string
$encryptedHex
must be decoded.The decoded data are to be decrypted. For this, key and nonce of the encryption must be used. In the posted code a different key is used, which is not possible in the context of
crypto_secretbox
(symmetric encryption), i.e. both sides use the same key. For asymmetric encryption there iscrypto_box
.The result can be decoded into a JavaScript object whose objects can be accessed as usual.
The corresponding code is:
// Hex decode $encrypted = sodium_hex2bin($encryptedHex); // Decrypt $nonce = "0123456789abcdefghijvbnm"; $key = "827ccb0eea8a706c4c34a16891f84e7b"; $decrypted = sodium_crypto_secretbox_open($encrypted, $nonce, $key); // Convert to JavaScript object $decryptedJSON = json_decode($decrypted); echo "Zip: " . $decryptedJSON->zip . "n"; echo "Account number: " . $decryptedJSON->account_number . "n"; echo "Passcode: " . $decryptedJSON->passcode . "n"; echo "Account type: " . $decryptedJSON->account_type . "n"; echo "Request: " . $decryptedJSON->request . "n"; echo "Device: " . $decryptedJSON->device . "n";