(编辑) 仍在此。我更改了代码,现在直接从库的Github页面中使用示例函数,但是仍然存在相同的问题。我在这里错过明显的东西吗?我唯一的偏差是使用内置 crypto_genrichash函数,用于在32个字符(64个字符过长)中创建密钥。使用他们的示例,创建的密钥太小:
var key = sodium.randombytes_buf(sodium.crypto_shorthash_KEYBYTES),
hash1 = sodium.crypto_shorthash(new Uint8Array([1, 2, 3, 4]), key),
hash2 = sodium.crypto_shorthash('user_password', key);
原始钠文件的链接 https://raw.githubusercontent.com/jedisct1/libsodium.js/master/dist/browsers/sodium.js
这是导致错误的函数:
function RA(A, I, e, B) {
var C = [];
E(B),
A = w(C, A, "ciphertext");
var i, a = g._crypto_secretbox_macbytes(), r = A.length;
r < a && _(C, "ciphertext is too short"),
i = s(A),
C.push(i),
I = w(C, I, "nonce");
var t, Q = 0 | g._crypto_secretbox_noncebytes();
I.length !== Q && _(C, "invalid nonce length"),
t = s(I),
C.push(t),
e = w(C, e, "key");
var o, h = 0 | g._crypto_secretbox_keybytes();
e.length !== h && _(C, "invalid key length"),
o = s(e),
C.push(o);
var p = new c(r - g._crypto_secretbox_macbytes() | 0)
, u = p.address;
if (C.push(u),
0 == (0 | g._crypto_secretbox_open_easy(u, i, r, 0, t, o))) {
var l = n(p, B);
return y(C),
l
}
f(C, "wrong secret key for the given ciphertext")
}
(/编辑)
我相信我会尽量减少这段代码以供自己学习,我已经消除了盐分或随机数等式中的某些内容。但是,不管怎么说,我不明白的是,如果按原样运行它,似乎可以正常工作,因为两个控制台日志在加密之前和解密之后都显示相同的privateKey精确值。但是,在实际使用中,加密部分将位于单独的脚本中,例如用户创建/编辑pw页,发送给mysql进行存储(通过ajax / php)的新加密的privateKey以及用户中的解密部分。登录脚本..这是当我在控制台中收到“给定密文的错误密钥”错误时。但是我已经检查过,从表面上看,ajax在身份验证时返回的值(注意:位于带有其他确认的数组中)与解密PrivateKey(result [6],password_normal_input)完全相同。就像第一次创建时一样……至少在视觉上(检查返回和密码输入中的空格)。
和钠包装(带有示例)来自: https://github.com/jedisct1/libsodium.js
<script src="components/sodium/sodium.js" async></script>
<script>
window.sodium =
{
onload: function (sodium)
{
function encrypt_and_prepend_nonce(message,password)
{
let key = sodium.crypto_generichash(32, sodium.from_string(password));
let nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
let nonce_arr = sodium.to_hex(nonce);
return sodium.from_hex(nonce_arr.concat(sodium.to_hex(sodium.crypto_secretbox_easy(message, nonce, key))));
}
function decrypt_after_extracting_nonce(nonce_and_ciphertext,password)
{
let key = sodium.crypto_generichash(32, sodium.from_string(password));
if (nonce_and_ciphertext.length < sodium.crypto_secretbox_NONCEBYTES +
sodium.crypto_secretbox_MACBYTES)
{
throw "Short message";
}
let nonce = nonce_and_ciphertext.slice(0, sodium.crypto_secretbox_NONCEBYTES),
ciphertext = nonce_and_ciphertext.slice(sodium.crypto_secretbox_NONCEBYTES);
return sodium.crypto_secretbox_open_easy(ciphertext, nonce, key);
}
var password = 'user_password';
let keypair = sodium.crypto_box_keypair();
let privateKey = keypair.privateKey;
console.log(privateKey);
var privateKey_encrypted = encrypt_and_prepend_nonce(privateKey,password);
var privateKey_decrypted = decrypt_after_extracting_nonce(privateKey_encrypted,password);
console.log(privateKey_decrypted);
}
};
</script>
答案 0 :(得分:0)
最后找到了。我没想到的是,我正在发送dataType: 'text'
,从而将密文转换为字符串。正如我最初提到的,我将它与其他用户和与身份验证相关的数据在一个数组中来回发送,因此即使存在dataType二进制函数,对我也不起作用。
问题是我只是在关注和比较“看起来”相同的视觉数据,来回移动。如果运行代码,您将得到一个Uint8Array密文,类似...
244,107,218,84,102,170,55,208,32,148,192,251,218,140,254,204,69,192,24,120,135,88,254,96,56,203,191,65,250,106,42,16,118,179,151,29,220,221,224,6,105,200,235,106,190,248,150,208,233,161,36,4,63,16,2,188,238,21,247,117,4,89,37,43,26,103,135,33,160,44,129,75
与开头的24个字节随机数
串联244,107,218,84,102,170,55,208,32,148,192,251,218,140,254,204,69,192,24,120,135,88,254,96
解密时,我们将随机数和密文切片,再次使用crypto_secretbox_NONCEBYTES ..也称为“ 24” ...
let nonce = nonce_and_ciphertext.slice(0, sodium.crypto_secretbox_NONCEBYTES),
ciphertext = nonce_and_ciphertext.slice(sodium.crypto_secretbox_NONCEBYTES);
但是,但是,如果它是字符串,则切片将为:
244,107,218,84,102,170,5
..从而为密文创建了错误的密钥,并导致我需要Stack Overflow和Github帐户。请注意最后一部分,我说过“在返回和输入密码时检查了空格”。...嗯,是的。
无论如何,所以我的解决方案包含非常宽松的示例...首先是加密
<script src="components/sodium/sodium.js" async></script>
<script>
window.sodium =
{
onload: function (sodium)
{
function encrypt_and_prepend_nonce(message,password)
{
let key = sodium.crypto_generichash(32, sodium.from_string(password));
let nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
console.log(nonce);
let nonce_arr = sodium.to_hex(nonce);
return sodium.from_hex(nonce_arr.concat(sodium.to_hex(sodium.crypto_secretbox_easy(message, nonce, key))));
}
//Password from some text input, but for the example we'll just use a string.
var password = 'user_password';
let keypair = sodium.crypto_box_keypair();
let privateKey = keypair.privateKey;
var privateKey_encrypted = encrypt_and_prepend_nonce(privateKey,password);
/* Send it to the server for storage. Just sending public key and password as makes sense
* for this example, as we just created the keypair
*/
$.ajax(
{
type: "POST",
url: "server.php",
dataType: "text",
data: 'my_new_encrypted_privateKey=' + privateKey_encrypted + '&publicKey=' +
keypair.publicKey + '&user_password=' + password
});
}
};
</script>
然后解密privateKey ...
<script src="components/sodium/sodium.js" async></script>
<script>
window.sodium =
{
onload: function (sodium)
{
//Function to turn privateKey ciphertext string to Uint8Array
function strToBuffer (string)
{
let array = string.split(',');
let newUint = new Uint8Array(array);
return newUint;
}
function decrypt_after_extracting_nonce(nonce_and_ciphertext,password)
{
let key = sodium.crypto_generichash(32, sodium.from_string(password));
if (nonce_and_ciphertext.length < sodium.crypto_secretbox_NONCEBYTES +
sodium.crypto_secretbox_MACBYTES)
{
throw "Short message";
}
nonce_and_ciphertext = strToBuffer(nonce_and_ciphertext);
//now a Uint8Array, will produce the correct nonce & ciphertext slices
let nonce = nonce_and_ciphertext.slice(0, sodium.crypto_secretbox_NONCEBYTES),
ciphertext = nonce_and_ciphertext.slice(sodium.crypto_secretbox_NONCEBYTES);
return sodium.crypto_secretbox_open_easy(ciphertext, nonce, key);
}
/* Password from some text input, but for the example we'll just use a string. The privateKey_
* encrypted will likely be in an ajax callback
*/
$.ajax(
{
type: "POST",
url: "server.php",
dataType: "text",
data: 'some_user_data=' + some_user_data,
success: function(response)
{
//Response will be the string...
var privateKey_encrypted = response.trim();
var privateKey_decrypted = decrypt_after_extracting_nonce(privateKey_encrypted,password);
//You can now use your Keypair to open sealed boxes.
}
});
}
};
</script>