Files
notesnook/packages/core/utils/crypto.js

88 lines
2.0 KiB
JavaScript
Raw Normal View History

2020-04-11 17:02:11 +05:00
import _sodium from "libsodium-wrappers";
export async function newSodium() {
await _sodium.ready;
return _sodium;
}
class Crypto {
constructor() {
this.isReady = false;
this.sodium = _sodium;
}
async init() {
this.sodium = await newSodium();
this.isReady = true;
}
_throwIfNotReady() {
if (!this.isReady)
throw new Error("libsodium is not ready yet. Please call init()");
}
_deriveKey(password, keyLength, salt) {
this._throwIfNotReady();
salt =
salt || this.sodium.randombytes_buf(this.sodium.crypto_pwhash_SALTBYTES);
const key = this.sodium.crypto_pwhash(
keyLength,
password,
salt,
3, // operations limit
1024 * 1024 * 4, // memory limit (4MB)
this.sodium.crypto_pwhash_ALG_ARGON2I13
);
const saltHex = this.sodium.to_hex(salt);
this.sodium.memzero(salt);
return { key, salt: saltHex };
}
encrypt({ password, data }) {
2020-04-11 17:02:11 +05:00
this._throwIfNotReady();
const { key, salt } = this._deriveKey(
password,
this.sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES
);
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_hex(nonce);
this.sodium.memzero(nonce);
this.sodium.memzero(key);
return {
cipher,
iv,
salt,
};
}
decrypt({ password, data: { salt, iv, cipher } }) {
2020-04-11 17:02:11 +05:00
this._throwIfNotReady();
const { key } = this._deriveKey(
password,
this.sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
this.sodium.from_hex(salt)
);
const plainText = this.sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
undefined,
this.sodium.from_base64(cipher),
undefined,
this.sodium.from_hex(iv),
key,
"text"
);
this.sodium.memzero(key);
return plainText;
}
}
export default Crypto;