我花了令人尴尬的几个小时试图让Libsodium.js正常工作。
(以及下面粘贴的代码)。
我一直在找Error: wrong secret key for the given ciphertext
。
我更喜欢将这个PHP example of function simpleEncrypt($message, $key)
复制到Libsodium.js中。
但作为一个初学者,即使让基本的sample from the Libsodium.js repo正常工作,我也会很高兴。
有什么提示吗?
这里是代码(也显示在working 中):
const _sodium = require("libsodium-wrappers");
const concatTypedArray = require("concat-typed-array");
(async () => {
await _sodium.ready;
const sodium = _sodium;
const utf8 = "utf-8";
const td = new TextDecoder(utf8);
const te = new TextEncoder(utf8);
const nonceBytes = sodium.crypto_secretbox_NONCEBYTES;
const macBytes = sodium.crypto_secretbox_MACBYTES;
let key = sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed");
function encrypt_and_prepend_nonce(message, key) {
let nonce = sodium.randombytes_buf(nonceBytes);
var encrypted = sodium.crypto_secretbox_easy(message, nonce, key);
var combined2 = concatTypedArray(Uint8Array, nonce, encrypted);
return combined2;
}
function decrypt_after_extracting_nonce(nonce_and_ciphertext, key) {
if (nonce_and_ciphertext.length < nonceBytes + macBytes) {
throw "Short message";
}
let nonce = nonce_and_ciphertext.slice(0, nonceBytes);
let ciphertext = nonce_and_ciphertext.slice(nonceBytes);
return sodium.crypto_secretbox_open_easy(ciphertext, nonce, key);
}
function encrypt(message, key) {
var x = encrypt_and_prepend_nonce(message, key);
return td.decode(x);
}
function decrypt(nonce_and_ciphertext_str, key) {
var nonce_and_ciphertext = te.encode(nonce_and_ciphertext_str);
return decrypt_after_extracting_nonce(nonce_and_ciphertext, key);
}
var inputStr = "shhh this is a secret";
var garbledStr = encrypt(inputStr, key);
try {
var decryptedStr = decrypt(garbledStr, key);
console.log("Recovered input string:", decryptedStr);
console.log("Check whether the following text matches the original:", decryptedStr === inputStr);
} catch (e) {
console.error(e);
}
})();
发布于 2018-08-13 09:51:35
哇,我终于让它工作了!
真正对我有帮助的部分是:
的Uint8Array)
const concatTypedArray = require("concat-typed-array");
require("babel-core/register");
和require("babel-polyfill");
的function u_atob(ascii)
这是有效的fiddle sandbox。
如果这一点消失了,这里是重要的部分:
const nonceBytes = sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
let key = sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed");
var nonceTest;
/**
* @param {string} message
* @param {string} key
* @returns {Uint8Array}
*/
function encrypt_and_prepend_nonce(message, key) {
let nonce = sodium.randombytes_buf(nonceBytes);
nonceTest = nonce.toString();
var encrypted = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(message, null, nonce, nonce, key);
var nonce_and_ciphertext = concatTypedArray(Uint8Array, nonce, encrypted); //https://github.com/jedisct1/libsodium.js/issues/130#issuecomment-361399594
return nonce_and_ciphertext;
}
/**
* @param {Uint8Array} nonce_and_ciphertext
* @param {string} key
* @returns {string}
*/
function decrypt_after_extracting_nonce(nonce_and_ciphertext, key) {
let nonce = nonce_and_ciphertext.slice(0, nonceBytes); //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice
let ciphertext = nonce_and_ciphertext.slice(nonceBytes);
var result = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(nonce, ciphertext, null, nonce, key, "text");
return result;
}
/**
* @param {string} message
* @param {string} key
* @returns {string}
*/
function encrypt(message, key) {
var uint8ArrayMsg = encrypt_and_prepend_nonce(message, key);
return u_btoa(uint8ArrayMsg); //returns ascii string of garbled text
}
/**
* @param {string} nonce_and_ciphertext_str
* @param {string} key
* @returns {string}
*/
function decrypt(nonce_and_ciphertext_str, key) {
var nonce_and_ciphertext = u_atob(nonce_and_ciphertext_str); //converts ascii string of garbled text into binary
return decrypt_after_extracting_nonce(nonce_and_ciphertext, key);
}
function u_atob(ascii) { //https://stackoverflow.com/a/43271130/
return Uint8Array.from(atob(ascii), c => c.charCodeAt(0));
}
function u_btoa(buffer) { //https://stackoverflow.com/a/43271130/
var binary = [];
var bytes = new Uint8Array(buffer);
for (var i = 0, il = bytes.byteLength; i < il; i++) {
binary.push(String.fromCharCode(bytes[i]));
}
return btoa(binary.join(""));
}
发布于 2018-08-13 05:59:51
这就是我在https://emberclear.io中做的事情:
实现的代码片段(typescript中):
import libsodiumWrapper, { ISodium } from 'libsodium-wrappers';
import { concat } from 'emberclear/src/utils/arrays/utils';
export async function libsodium(): Promise<ISodium> {
const sodium = libsodiumWrapper.sodium;
await sodium.ready;
return sodium;
}
export async function encryptFor(
message: Uint8Array,
recipientPublicKey: Uint8Array,
senderPrivateKey: Uint8Array): Promise<Uint8Array> {
const sodium = await libsodium();
const nonce = await generateNonce();
const ciphertext = sodium.crypto_box_easy(
message, nonce,
recipientPublicKey, senderPrivateKey
);
return concat(nonce, ciphertext);
}
export async function decryptFrom(
ciphertextWithNonce: Uint8Array,
senderPublicKey: Uint8Array,
recipientPrivateKey: Uint8Array): Promise<Uint8Array> {
const sodium = await libsodium();
const [nonce, ciphertext] = await splitNonceFromMessage(ciphertextWithNonce);
const decrypted = sodium.crypto_box_open_easy(
ciphertext, nonce,
senderPublicKey, recipientPrivateKey
);
return decrypted;
}
export async function splitNonceFromMessage(messageWithNonce: Uint8Array): Promise<[Uint8Array, Uint8Array]> {
const sodium = await libsodium();
const bytes = sodium.crypto_box_NONCEBYTES;
const nonce = messageWithNonce.slice(0, bytes);
const message = messageWithNonce.slice(bytes, messageWithNonce.length);
return [nonce, message];
}
export async function generateNonce(): Promise<Uint8Array> {
const sodium = await libsodium();
return await randomBytes(sodium.crypto_box_NONCEBYTES);
}
export async function randomBytes(length: number): Promise<Uint8Array> {
const sodium = await libsodium();
return sodium.randombytes_buf(length);
}
测试片段:
import * as nacl from './utils';
import { module, test } from 'qunit';
module('Unit | Utility | nacl', function() {
test('libsodium uses wasm', async function(assert) {
const sodium = await nacl.libsodium();
const isUsingWasm = sodium.libsodium.usingWasm;
assert.ok(isUsingWasm);
});
test('generateAsymmetricKeys | works', async function(assert) {
const boxKeys = await nacl.generateAsymmetricKeys();
assert.ok(boxKeys.publicKey);
assert.ok(boxKeys.privateKey);
});
test('encryptFor/decryptFrom | works with Uint8Array', async function(assert) {
const receiver = await nacl.generateAsymmetricKeys();
const sender = await nacl.generateAsymmetricKeys();
const msgAsUint8 = Uint8Array.from([104, 101, 108, 108, 111]); // hello
const ciphertext = await nacl.encryptFor(msgAsUint8, receiver.publicKey, sender.privateKey);
const decrypted = await nacl.decryptFrom(ciphertext, sender.publicKey, receiver.privateKey);
assert.deepEqual(msgAsUint8, decrypted);
});
发布于 2020-05-24 22:44:00
我一直在尝试@Ryan的答案,并发现当它工作时,一个简单得多的解决方案是使用sodium-plus。钠加脚本的一个示例可以在here中找到。简而言之,加密端如下所示:
<script type='text/javascript' src='sodium-plus.min.js'></script>
<script>
async function encryptString(clearText) {
if (!window.sodium) window.sodium = await SodiumPlus.auto();
let publicKey = await X25519PublicKey.from('[Place your 64-char public key hex or variable name here]','hex');
let cipherText = await sodium.crypto_box_seal(clearText, publicKey);
return cipherText.toString('hex');
}
(async function () {
let clearText = "String that contains secret.";
console.log(await encryptString(clearText));
})();
</script>
简单多了。在PHP端,您需要做的就是使用sodium
方法处理字符串的加密/解密。
钠+唯一的缺点是我还没有找到浏览器版本的CDN。
https://stackoverflow.com/questions/51812991
复制相似问题