我正在开发Next.js中的一个服务,该服务使用xchacha20-Poly1305处理文件加密和解密.虽然我已经成功地实现了加密代码,但我在解密代码方面面临着挑战.您能为这个加密功能提供最合适的解密码的指导吗?此外,我还将密码作为来自用户的输入
我正在利用服务工作人员对浏览器中的文件进行加密,以确保它不会影响主线程.
const [file, setFile] = useState();
const [password, setPassword] = useState();
navigator.serviceWorker.ready.then((reg) => {
if (!reg || !reg.active) {
setIsEncrypting(false);
toast.error('Service worker is not ready or its not supported in your browser');
return;
}
reg.active.postMessage({
cmd: 'encryptFile',
file,
password
});
});
我使用libsodium-wrappers-sumo
库加密
service-worker.js
self.addEventListener('install', (event) =>
event.waitUntil(self.skipWaiting())
);
self.addEventListener('activate', (event) =>
event.waitUntil(self.clients.claim())
);
const _sodium = require('libsodium-wrappers-sumo');
const STATIC_SIGNATURE = 'Encrypted By XXXXXXX';
(async () => {
await _sodium.ready;
const sodium = _sodium;
addEventListener('message', async (e) => {
switch (e.data.cmd) {
case 'encryptFile':
const startTime = performance.now();
const { encryptedBlob, encryptedFileName } = await encryptFile(
e.data.file,
e.data.password
);
e.source.postMessage({
reply: 'encryptionFinished',
encryptedBlob,
encryptedFileName,
});
break;
}
});
const encryptFile = async (file, password) => {
// Generate encryption key
const salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);
const key = sodium.crypto_pwhash(
sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,
sodium.from_string(password),
salt,
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
sodium.crypto_pwhash_ALG_ARGON2ID13
);
// Initialize encryption
const { state, header } =
sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
// Create a stream controller for chunked processing
const streamController = new TransformStream();
const writer = streamController.writable.getWriter();
// Write signature, salt, and header to the stream
const signature = sodium.from_string(STATIC_SIGNATURE);
writer.write(signature);
writer.write(salt);
writer.write(header);
// Encrypt file in chunks
const chunkSize = 64 * 1024 * 1024;
const reader = file.stream().getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
// Finalize encryption and close the stream
const encryptedChunk =
sodium.crypto_secretstream_xchacha20poly1305_push(
state,
new Uint8Array(0),
null,
sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
);
writer.write(encryptedChunk);
writer.close();
// Get the encrypted file blob
const encryptedBlob = await new Response(
streamController.readable
).blob();
// send the encrypted file with the original filename + '.enc'
const encryptedFileName = `${file.name}.enc`;
return { encryptedBlob, encryptedFileName };
}
// Use chunkSize to control the size of each chunk
for (let i = 0; i < value.length; i += chunkSize) {
const chunk = value.slice(i, i + chunkSize);
const encryptedChunk =
sodium.crypto_secretstream_xchacha20poly1305_push(
state,
new Uint8Array(chunk),
null,
sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE
);
writer.write(encryptedChunk);
}
}
};
})();
现在,我需要一个decryptFile
函数来首先判断签名.它应该验证该文件是否由同一平台加密.之后,它应该判断用户提供的密码是否正确,以解密文件.之后,将进行解码过程,逐个块地解密文件块.最后,该函数应该返回decryptedBlob
,类似于我在encryptFile
函数中实现它的方式,使用const chunkSize = 64 * 1024 * 1024;
,并将文件名更改为.enc to non .enc
self.addEventListener('install', (event) =>
event.waitUntil(self.skipWaiting())
);
self.addEventListener('activate', (event) =>
event.waitUntil(self.clients.claim())
);
const _sodium = require('libsodium-wrappers-sumo');
const STATIC_SIGNATURE = 'Encrypted By XXXXXXX';
(async () => {
await _sodium.ready;
const sodium = _sodium;
addEventListener('message', async (e) => {
switch (e.data.cmd) {
case 'encryptFile':
...
break;
case 'decryptFile':
const {decryptedBlob, decryptedFileName} = await decryptFile(e.data.encFile, e.data.password);
e.source.postMessage({
reply: 'decryptionFinished',
decryptedBlob,
decryptedFileName
});
break;
}
});
const encryptFile = async (file, password) => {
...
};
const decryptFile = async (encFile, password) => {
... // help me to write this function
};
})();
我是网络密码学的新手,目前正在阅读libsodium
的文档.然而,我似乎找不到解决办法.请帮我写一下decryptFile
函数.
此外,如果您可以建议对当前代码进行任何更改,那将是最受欢迎的.请提供建议以获得更好的性能和可靠性.
const decryptFile = async (file, password) => {
const signature = await file
.slice(0, STATIC_SIGNATURE.length)
.arrayBuffer();
const decoder = new TextDecoder();
if (decoder.decode(signature) !== STATIC_SIGNATURE) {
throw new Error('Invalid signature');
}
const saltLength = sodium.crypto_pwhash_SALTBYTES;
const saltBuffer = await file
.slice(
STATIC_SIGNATURE.length,
STATIC_SIGNATURE.length + saltLength
)
.arrayBuffer();
const salt = new Uint8Array(saltBuffer);
const header = new Uint8Array(
await file
.slice(
STATIC_SIGNATURE.length + saltLength,
STATIC_SIGNATURE.length +
saltLength +
sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES
)
.arrayBuffer()
);
// Generate decryption key
const key = sodium.crypto_pwhash(
sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES,
sodium.from_string(password),
salt,
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
sodium.crypto_pwhash_ALG_ARGON2ID13
);
const { state_address, tag } =
sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, key);
// Create a stream controller for chunked processing
const streamController = new TransformStream();
const writer = streamController.writable.getWriter();
// Decrypt file in chunks
const chunkSize = 64 * 1024 * 1024;
const encryptedData = new Uint8Array(
await file
.slice(
STATIC_SIGNATURE.length +
saltLength +
sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES
)
.arrayBuffer()
);
let offset = 0;
while (offset < encryptedData.length) {
const chunk = new Uint8Array(
encryptedData.slice(offset, offset + chunkSize)
);
const { message, tag: decryptedTag } =
sodium.crypto_secretstream_xchacha20poly1305_pull(
state_address,
new Uint8Array(0),
chunk
);
if (
decryptedTag ===
sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
) {
break; // End of decryption
}
writer.write(message);
offset += chunkSize;
}
writer.close();
// Get the decrypted file blob
const decryptedBlob = await new Response(
streamController.readable
).blob();
return decryptedBlob;
};
这就是我到目前为止创建的内容,但它给出了一个错误,而且也没有首先判断小块上的密码是否正确.
错误如下所示:
service-worker.js:20245 Uncaught (in promise) TypeError: state_address cannot be null or undefined