mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-03 12:41:45 +02:00
feat: add libsodium for crypto
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"framer-motion": "^1.9.1",
|
||||
"git": "^0.1.5",
|
||||
"immer": "^5.3.6",
|
||||
"libsodium-wrappers": "0.7.6",
|
||||
"localforage": "^1.7.3",
|
||||
"localforage-getitems": "https://github.com/thecodrr/localForage-getItems.git",
|
||||
"notes-core": "npm:@streetwriters/notesnook-core@latest",
|
||||
|
||||
109
apps/web/src/interfaces/crypto.js
Normal file
109
apps/web/src/interfaces/crypto.js
Normal file
@@ -0,0 +1,109 @@
|
||||
class Crypto {
|
||||
isReady = false;
|
||||
constructor() {
|
||||
this.sodium = undefined;
|
||||
}
|
||||
async _initialize() {
|
||||
if (this.isReady) return;
|
||||
const _sodium = require("libsodium-wrappers");
|
||||
await _sodium.ready;
|
||||
this.sodium = _sodium;
|
||||
this.isReady = true;
|
||||
}
|
||||
|
||||
deriveKey = async (password, salt, exportKey = false) => {
|
||||
await this._initialize();
|
||||
|
||||
if (!salt)
|
||||
salt = this.sodium.randombytes_buf(this.sodium.crypto_pwhash_SALTBYTES);
|
||||
else {
|
||||
salt = this.sodium.from_base64(salt);
|
||||
}
|
||||
|
||||
const key = this.sodium.crypto_pwhash(
|
||||
this.sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
|
||||
password,
|
||||
salt,
|
||||
3, // operations limit
|
||||
1024 * 1024 * 8, // memory limit (8MB)
|
||||
this.sodium.crypto_pwhash_ALG_ARGON2I13,
|
||||
exportKey ? "hex" : "uint8array"
|
||||
);
|
||||
const saltHex = this.sodium.to_base64(salt);
|
||||
this.sodium.memzero(salt);
|
||||
if (exportKey) {
|
||||
return key;
|
||||
}
|
||||
return { key, salt: saltHex };
|
||||
};
|
||||
|
||||
_getKey = async (passwordOrKey) => {
|
||||
let key, salt;
|
||||
if (passwordOrKey.password) {
|
||||
const result = await this.deriveKey(passwordOrKey.password);
|
||||
key = result.key;
|
||||
salt = result.salt;
|
||||
} else if (passwordOrKey.key && passwordOrKey.salt) {
|
||||
salt = passwordOrKey.salt;
|
||||
key = this.sodium.from_hex(passwordOrKey.key);
|
||||
}
|
||||
return { key, salt };
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{password: string}|{key:string, salt: string}} passwordOrKey - password or derived key
|
||||
* @param {string|Object} data - the plaintext data
|
||||
*/
|
||||
encrypt = async (passwordOrKey, data) => {
|
||||
await this._initialize();
|
||||
|
||||
if (typeof data === "object") data = JSON.stringify(data);
|
||||
|
||||
const { key, salt } = await this._getKey(passwordOrKey);
|
||||
|
||||
const nonce = this.sodium.randombytes_buf(
|
||||
this.sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
|
||||
);
|
||||
const cipher = this.sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
data,
|
||||
undefined,
|
||||
undefined,
|
||||
nonce,
|
||||
key,
|
||||
"base64"
|
||||
);
|
||||
const iv = this.sodium.to_base64(nonce);
|
||||
this.sodium.memzero(nonce);
|
||||
this.sodium.memzero(key);
|
||||
return {
|
||||
cipher,
|
||||
iv,
|
||||
salt,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{password: string}|{key:string, salt: string}} passwordOrKey - password or derived key
|
||||
* @param {{salt: string, iv: string, cipher: string}} cipher - the cipher data
|
||||
*/
|
||||
decrypt = async (passwordOrKey, { iv, cipher }) => {
|
||||
await this._initialize();
|
||||
|
||||
const { key } = await this._getKey(passwordOrKey);
|
||||
console.log(key, iv, cipher, passwordOrKey);
|
||||
|
||||
const plainText = this.sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
undefined,
|
||||
this.sodium.from_base64(cipher),
|
||||
undefined,
|
||||
this.sodium.from_base64(iv),
|
||||
key,
|
||||
"text"
|
||||
);
|
||||
this.sodium.memzero(key);
|
||||
return plainText;
|
||||
};
|
||||
}
|
||||
export default Crypto;
|
||||
@@ -1,7 +1,9 @@
|
||||
import localforage from "localforage";
|
||||
import { extendPrototype } from "localforage-getitems";
|
||||
import sort from "fast-sort";
|
||||
import Crypto from "./crypto";
|
||||
|
||||
const crypto = new Crypto();
|
||||
extendPrototype(localforage);
|
||||
|
||||
localforage.config({
|
||||
@@ -36,4 +38,7 @@ export default {
|
||||
write,
|
||||
remove,
|
||||
clear,
|
||||
deriveKey: crypto.deriveKey,
|
||||
encrypt: crypto.encrypt,
|
||||
decrypt: crypto.decrypt,
|
||||
};
|
||||
|
||||
@@ -6268,7 +6268,7 @@ levn@^0.3.0, levn@~0.3.0:
|
||||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
|
||||
libsodium-wrappers@^0.7.6:
|
||||
libsodium-wrappers@0.7.6, libsodium-wrappers@^0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.6.tgz#baed4c16d4bf9610104875ad8a8e164d259d48fb"
|
||||
integrity sha512-OUO2CWW5bHdLr6hkKLHIKI4raEkZrf3QHkhXsJ1yCh6MZ3JDA7jFD3kCATNquuGSG6MjjPHQIQms0y0gBDzjQg==
|
||||
@@ -6910,7 +6910,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1:
|
||||
|
||||
"notes-core@git+ssh://git@github.com:thecodrr/notes-core.git":
|
||||
version "1.2.0"
|
||||
resolved "git+ssh://git@github.com:thecodrr/notes-core.git#47dcb328be59c040c7ea50a6e1f26a2572ee1270"
|
||||
resolved "git+ssh://git@github.com:thecodrr/notes-core.git#d0e226b0ba97a44f7098955ee6d982904a51be9d"
|
||||
dependencies:
|
||||
fast-sort "^2.0.1"
|
||||
fuzzysearch "^1.0.3"
|
||||
|
||||
Reference in New Issue
Block a user