如何使用 JS-NaCl 加密 JSON 对象并使用 php Libsodium 解密
How to encrypt JSON object with JS-NaCl and decrypt with php Libsodium
我设法找到了用于前端加密的 Libsodium js 库 (JS-NaCl),并且还为 Libsodium encrypt/decrypt 设置了我的 PHP 后端。当我像下面这样加密 JSON 对象时
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");
}
});
}
当我启动登录方法时,它会使用加密方法加密 JSON 对象,因此我发送如下内容:
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}
在 php 后端代码我这样做:
<?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);
?>
相同的密钥,相同的随机数,但它不回显任何内容。我该如何解密??
代码需要一些修改。在 JavaScript 端(前端):
JavaScript对象必须转换成字符串。
除了data,nonce和key也必须使用utf8编码。虽然密钥也可以十六进制编码为 16 字节密钥,但在这种情况下,它必须是 Utf8 编码为 32 字节密钥,因为 sodium.crypto_secretbox
需要 32 字节密钥。预期的 nonce 大小必须为 24 个字节。
现在可以加密数据了。
sodium.crypto_secretbox
returns 数据为 Uint8Array
,因此必须对其进行编码以便传输为合适的格式,例如十六进制.
对应的代码为:
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, "\n"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-nacl/1.3.2/nacl_factory.js"></script>
在PHP端(后端):
必须解码十六进制字符串$encryptedHex
。
解码后的数据待解密。为此,必须使用加密的密钥和随机数。在发布的代码中使用了不同的密钥,这在 crypto_secretbox
(symmetric encryption), i.e. both sides use the same key. For asymmetric encryption there is crypto_box
的上下文中是不可能的。
结果可以解码为JavaScript对象,其对象可以正常访问。
对应的代码为:
// 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";
我设法找到了用于前端加密的 Libsodium js 库 (JS-NaCl),并且还为 Libsodium encrypt/decrypt 设置了我的 PHP 后端。当我像下面这样加密 JSON 对象时
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");
}
});
}
当我启动登录方法时,它会使用加密方法加密 JSON 对象,因此我发送如下内容:
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}
在 php 后端代码我这样做:
<?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);
?>
相同的密钥,相同的随机数,但它不回显任何内容。我该如何解密??
代码需要一些修改。在 JavaScript 端(前端):
JavaScript对象必须转换成字符串。
除了data,nonce和key也必须使用utf8编码。虽然密钥也可以十六进制编码为 16 字节密钥,但在这种情况下,它必须是 Utf8 编码为 32 字节密钥,因为
sodium.crypto_secretbox
需要 32 字节密钥。预期的 nonce 大小必须为 24 个字节。现在可以加密数据了。
sodium.crypto_secretbox
returns 数据为Uint8Array
,因此必须对其进行编码以便传输为合适的格式,例如十六进制.
对应的代码为:
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, "\n"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-nacl/1.3.2/nacl_factory.js"></script>
在PHP端(后端):
必须解码十六进制字符串
$encryptedHex
。解码后的数据待解密。为此,必须使用加密的密钥和随机数。在发布的代码中使用了不同的密钥,这在
crypto_secretbox
(symmetric encryption), i.e. both sides use the same key. For asymmetric encryption there iscrypto_box
的上下文中是不可能的。结果可以解码为JavaScript对象,其对象可以正常访问。
对应的代码为:
// 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";