[cast] Remove unused code
This commit is contained in:
parent
73885f6f0a
commit
d2c088b9ef
3 changed files with 0 additions and 796 deletions
|
@ -1,8 +0,0 @@
|
|||
/** Enums of supported locale */
|
||||
export enum Language {
|
||||
en = 'en',
|
||||
fr = 'fr',
|
||||
zh = 'zh',
|
||||
nl = 'nl',
|
||||
es = 'es',
|
||||
}
|
|
@ -1,366 +0,0 @@
|
|||
import { KeyAttributes, SRPSetupAttributes } from 'types/user';
|
||||
import { SESSION_KEYS, setKey } from 'utils/storage/sessionStorage';
|
||||
import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
|
||||
import { setRecoveryKey } from 'services/userService';
|
||||
import { logError } from '@ente/shared/sentry';
|
||||
import isElectron from 'is-electron';
|
||||
// import safeStorageService from 'services/electron/safeStorage';
|
||||
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
|
||||
import { PasswordStrength } from 'constants/crypto';
|
||||
import zxcvbn from 'zxcvbn';
|
||||
import { SRP, SrpClient } from 'fast-srp-hap';
|
||||
import { convertBase64ToBuffer, convertBufferToBase64 } from 'utils/user';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { addLocalLog } from 'utils/logging';
|
||||
import { getActualKey } from '@ente/shared/user';
|
||||
import { getToken } from '@ente/shared/storage/localStorage/helpers';
|
||||
|
||||
const SRP_PARAMS = SRP.params['4096'];
|
||||
|
||||
const LOGIN_SUB_KEY_LENGTH = 32;
|
||||
const LOGIN_SUB_KEY_ID = 1;
|
||||
const LOGIN_SUB_KEY_CONTEXT = 'loginctx';
|
||||
const LOGIN_SUB_KEY_BYTE_LENGTH = 16;
|
||||
|
||||
export async function generateKeyAndSRPAttributes(passphrase: string): Promise<{
|
||||
keyAttributes: KeyAttributes;
|
||||
masterKey: string;
|
||||
srpSetupAttributes: SRPSetupAttributes;
|
||||
}> {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const masterKey = await cryptoWorker.generateEncryptionKey();
|
||||
const recoveryKey = await cryptoWorker.generateEncryptionKey();
|
||||
const kekSalt = await cryptoWorker.generateSaltToDeriveKey();
|
||||
const kek = await cryptoWorker.deriveSensitiveKey(passphrase, kekSalt);
|
||||
|
||||
const masterKeyEncryptedWithKek = await cryptoWorker.encryptToB64(
|
||||
masterKey,
|
||||
kek.key
|
||||
);
|
||||
const masterKeyEncryptedWithRecoveryKey = await cryptoWorker.encryptToB64(
|
||||
masterKey,
|
||||
recoveryKey
|
||||
);
|
||||
const recoveryKeyEncryptedWithMasterKey = await cryptoWorker.encryptToB64(
|
||||
recoveryKey,
|
||||
masterKey
|
||||
);
|
||||
|
||||
const keyPair = await cryptoWorker.generateKeyPair();
|
||||
const encryptedKeyPairAttributes = await cryptoWorker.encryptToB64(
|
||||
keyPair.privateKey,
|
||||
masterKey
|
||||
);
|
||||
|
||||
const loginSubKey = await generateLoginSubKey(kek.key);
|
||||
|
||||
const srpSetupAttributes = await generateSRPSetupAttributes(loginSubKey);
|
||||
|
||||
const keyAttributes: KeyAttributes = {
|
||||
kekSalt,
|
||||
encryptedKey: masterKeyEncryptedWithKek.encryptedData,
|
||||
keyDecryptionNonce: masterKeyEncryptedWithKek.nonce,
|
||||
publicKey: keyPair.publicKey,
|
||||
encryptedSecretKey: encryptedKeyPairAttributes.encryptedData,
|
||||
secretKeyDecryptionNonce: encryptedKeyPairAttributes.nonce,
|
||||
opsLimit: kek.opsLimit,
|
||||
memLimit: kek.memLimit,
|
||||
masterKeyEncryptedWithRecoveryKey:
|
||||
masterKeyEncryptedWithRecoveryKey.encryptedData,
|
||||
masterKeyDecryptionNonce: masterKeyEncryptedWithRecoveryKey.nonce,
|
||||
recoveryKeyEncryptedWithMasterKey:
|
||||
recoveryKeyEncryptedWithMasterKey.encryptedData,
|
||||
recoveryKeyDecryptionNonce: recoveryKeyEncryptedWithMasterKey.nonce,
|
||||
};
|
||||
|
||||
return {
|
||||
keyAttributes,
|
||||
masterKey,
|
||||
srpSetupAttributes,
|
||||
};
|
||||
}
|
||||
|
||||
// We encrypt the masterKey, with an intermediate key derived from the
|
||||
// passphrase (with Interactive mem and ops limits) to avoid saving it to local
|
||||
// storage in plain text. This means that on the web user will always have to
|
||||
// enter their passphrase to access their masterKey.
|
||||
export async function generateAndSaveIntermediateKeyAttributes(
|
||||
passphrase: string,
|
||||
existingKeyAttributes: KeyAttributes,
|
||||
key: string
|
||||
): Promise<KeyAttributes> {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const intermediateKekSalt = await cryptoWorker.generateSaltToDeriveKey();
|
||||
const intermediateKek = await cryptoWorker.deriveInteractiveKey(
|
||||
passphrase,
|
||||
intermediateKekSalt
|
||||
);
|
||||
const encryptedKeyAttributes = await cryptoWorker.encryptToB64(
|
||||
key,
|
||||
intermediateKek.key
|
||||
);
|
||||
|
||||
const intermediateKeyAttributes = Object.assign(existingKeyAttributes, {
|
||||
kekSalt: intermediateKekSalt,
|
||||
encryptedKey: encryptedKeyAttributes.encryptedData,
|
||||
keyDecryptionNonce: encryptedKeyAttributes.nonce,
|
||||
opsLimit: intermediateKek.opsLimit,
|
||||
memLimit: intermediateKek.memLimit,
|
||||
});
|
||||
setData(LS_KEYS.KEY_ATTRIBUTES, intermediateKeyAttributes);
|
||||
return intermediateKeyAttributes;
|
||||
}
|
||||
|
||||
export const saveKeyInSessionStore = async (
|
||||
keyType: SESSION_KEYS,
|
||||
key: string,
|
||||
fromDesktop?: boolean
|
||||
) => {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const sessionKeyAttributes = await cryptoWorker.generateKeyAndEncryptToB64(
|
||||
key
|
||||
);
|
||||
setKey(keyType, sessionKeyAttributes);
|
||||
if (
|
||||
isElectron() &&
|
||||
!fromDesktop &&
|
||||
keyType === SESSION_KEYS.ENCRYPTION_KEY
|
||||
) {
|
||||
// safeStorageService.setEncryptionKey(key);
|
||||
}
|
||||
};
|
||||
|
||||
export const getRecoveryKey = async () => {
|
||||
let recoveryKey: string = null;
|
||||
try {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
|
||||
const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
|
||||
const {
|
||||
recoveryKeyEncryptedWithMasterKey,
|
||||
recoveryKeyDecryptionNonce,
|
||||
} = keyAttributes;
|
||||
const masterKey = await getActualKey();
|
||||
if (recoveryKeyEncryptedWithMasterKey) {
|
||||
recoveryKey = await cryptoWorker.decryptB64(
|
||||
recoveryKeyEncryptedWithMasterKey,
|
||||
recoveryKeyDecryptionNonce,
|
||||
masterKey
|
||||
);
|
||||
} else {
|
||||
recoveryKey = await createNewRecoveryKey();
|
||||
}
|
||||
recoveryKey = await cryptoWorker.toHex(recoveryKey);
|
||||
return recoveryKey;
|
||||
} catch (e) {
|
||||
logError(e, 'getRecoveryKey failed');
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
// Used only for legacy users for whom we did not generate recovery keys during
|
||||
// sign up
|
||||
async function createNewRecoveryKey() {
|
||||
const masterKey = await getActualKey();
|
||||
const existingAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
|
||||
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
|
||||
const recoveryKey = await cryptoWorker.generateEncryptionKey();
|
||||
const encryptedMasterKey = await cryptoWorker.encryptToB64(
|
||||
masterKey,
|
||||
recoveryKey
|
||||
);
|
||||
const encryptedRecoveryKey = await cryptoWorker.encryptToB64(
|
||||
recoveryKey,
|
||||
masterKey
|
||||
);
|
||||
const recoveryKeyAttributes = {
|
||||
masterKeyEncryptedWithRecoveryKey: encryptedMasterKey.encryptedData,
|
||||
masterKeyDecryptionNonce: encryptedMasterKey.nonce,
|
||||
recoveryKeyEncryptedWithMasterKey: encryptedRecoveryKey.encryptedData,
|
||||
recoveryKeyDecryptionNonce: encryptedRecoveryKey.nonce,
|
||||
};
|
||||
await setRecoveryKey(getToken(), recoveryKeyAttributes);
|
||||
|
||||
const updatedKeyAttributes = Object.assign(
|
||||
existingAttributes,
|
||||
recoveryKeyAttributes
|
||||
);
|
||||
setData(LS_KEYS.KEY_ATTRIBUTES, updatedKeyAttributes);
|
||||
|
||||
return recoveryKey;
|
||||
}
|
||||
|
||||
export async function decryptAndStoreToken(
|
||||
keyAttributes: KeyAttributes,
|
||||
masterKey: string
|
||||
) {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const user = getData(LS_KEYS.USER);
|
||||
let decryptedToken = null;
|
||||
const { encryptedToken } = user;
|
||||
if (encryptedToken && encryptedToken.length > 0) {
|
||||
const secretKey = await cryptoWorker.decryptB64(
|
||||
keyAttributes.encryptedSecretKey,
|
||||
keyAttributes.secretKeyDecryptionNonce,
|
||||
masterKey
|
||||
);
|
||||
const urlUnsafeB64DecryptedToken = await cryptoWorker.boxSealOpen(
|
||||
encryptedToken,
|
||||
keyAttributes.publicKey,
|
||||
secretKey
|
||||
);
|
||||
const decryptedTokenBytes = await cryptoWorker.fromB64(
|
||||
urlUnsafeB64DecryptedToken
|
||||
);
|
||||
decryptedToken = await cryptoWorker.toURLSafeB64(decryptedTokenBytes);
|
||||
setData(LS_KEYS.USER, {
|
||||
...user,
|
||||
token: decryptedToken,
|
||||
encryptedToken: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function encryptWithRecoveryKey(key: string) {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const hexRecoveryKey = await getRecoveryKey();
|
||||
const recoveryKey = await cryptoWorker.fromHex(hexRecoveryKey);
|
||||
const encryptedKey = await cryptoWorker.encryptToB64(key, recoveryKey);
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
export async function decryptDeleteAccountChallenge(
|
||||
encryptedChallenge: string
|
||||
) {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const masterKey = await getActualKey();
|
||||
const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
|
||||
const secretKey = await cryptoWorker.decryptB64(
|
||||
keyAttributes.encryptedSecretKey,
|
||||
keyAttributes.secretKeyDecryptionNonce,
|
||||
masterKey
|
||||
);
|
||||
const b64DecryptedChallenge = await cryptoWorker.boxSealOpen(
|
||||
encryptedChallenge,
|
||||
keyAttributes.publicKey,
|
||||
secretKey
|
||||
);
|
||||
const utf8DecryptedChallenge = atob(b64DecryptedChallenge);
|
||||
return utf8DecryptedChallenge;
|
||||
}
|
||||
|
||||
export function estimatePasswordStrength(password: string): PasswordStrength {
|
||||
if (!password) {
|
||||
return PasswordStrength.WEAK;
|
||||
}
|
||||
|
||||
const zxcvbnResult = zxcvbn(password);
|
||||
if (zxcvbnResult.score < 2) {
|
||||
return PasswordStrength.WEAK;
|
||||
} else if (zxcvbnResult.score < 3) {
|
||||
return PasswordStrength.MODERATE;
|
||||
} else {
|
||||
return PasswordStrength.STRONG;
|
||||
}
|
||||
}
|
||||
|
||||
export const isWeakPassword = (password: string) => {
|
||||
return estimatePasswordStrength(password) === PasswordStrength.WEAK;
|
||||
};
|
||||
|
||||
export const generateLoginSubKey = async (kek: string) => {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
const kekSubKeyString = await cryptoWorker.generateSubKey(
|
||||
kek,
|
||||
LOGIN_SUB_KEY_LENGTH,
|
||||
LOGIN_SUB_KEY_ID,
|
||||
LOGIN_SUB_KEY_CONTEXT
|
||||
);
|
||||
const kekSubKey = await cryptoWorker.fromB64(kekSubKeyString);
|
||||
|
||||
// use first 16 bytes of generated kekSubKey as loginSubKey
|
||||
const loginSubKey = await cryptoWorker.toB64(
|
||||
kekSubKey.slice(0, LOGIN_SUB_KEY_BYTE_LENGTH)
|
||||
);
|
||||
|
||||
return loginSubKey;
|
||||
};
|
||||
|
||||
export const generateSRPSetupAttributes = async (
|
||||
loginSubKey: string
|
||||
): Promise<SRPSetupAttributes> => {
|
||||
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
|
||||
|
||||
const srpSalt = await cryptoWorker.generateSaltToDeriveKey();
|
||||
|
||||
const srpUserID = uuidv4();
|
||||
|
||||
const srpVerifierBuffer = SRP.computeVerifier(
|
||||
SRP_PARAMS,
|
||||
convertBase64ToBuffer(srpSalt),
|
||||
Buffer.from(srpUserID),
|
||||
convertBase64ToBuffer(loginSubKey)
|
||||
);
|
||||
|
||||
const srpVerifier = convertBufferToBase64(srpVerifierBuffer);
|
||||
|
||||
addLocalLog(
|
||||
() => `SRP setup attributes generated',
|
||||
${JSON.stringify({
|
||||
srpSalt,
|
||||
srpUserID,
|
||||
srpVerifier,
|
||||
loginSubKey,
|
||||
})}`
|
||||
);
|
||||
|
||||
return {
|
||||
srpUserID,
|
||||
srpSalt,
|
||||
srpVerifier,
|
||||
loginSubKey,
|
||||
};
|
||||
};
|
||||
|
||||
export const computeVerifierHelper = (
|
||||
srpSalt: string,
|
||||
srpUserID: string,
|
||||
loginSubKey: string
|
||||
) => {
|
||||
const srpVerifierBuffer = SRP.computeVerifier(
|
||||
SRP_PARAMS,
|
||||
convertBase64ToBuffer(srpSalt),
|
||||
Buffer.from(srpUserID),
|
||||
convertBase64ToBuffer(loginSubKey)
|
||||
);
|
||||
return convertBufferToBase64(srpVerifierBuffer);
|
||||
};
|
||||
export const generateSRPClient = async (
|
||||
srpSalt: string,
|
||||
srpUserID: string,
|
||||
loginSubKey: string
|
||||
) => {
|
||||
return new Promise<SrpClient>((resolve, reject) => {
|
||||
SRP.genKey(function (err, secret1) {
|
||||
try {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
const srpClient = new SrpClient(
|
||||
SRP_PARAMS,
|
||||
convertBase64ToBuffer(srpSalt),
|
||||
Buffer.from(srpUserID),
|
||||
convertBase64ToBuffer(loginSubKey),
|
||||
secret1,
|
||||
false
|
||||
);
|
||||
|
||||
resolve(srpClient);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,422 +0,0 @@
|
|||
import sodium, { StateAddress } from 'libsodium-wrappers';
|
||||
import { ENCRYPTION_CHUNK_SIZE } from 'constants/crypto';
|
||||
import { B64EncryptionResult } from 'types/crypto';
|
||||
import { CustomError } from '@ente/shared/error';
|
||||
|
||||
export async function decryptChaChaOneShot(
|
||||
data: Uint8Array,
|
||||
header: Uint8Array,
|
||||
key: string
|
||||
) {
|
||||
await sodium.ready;
|
||||
const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(
|
||||
header,
|
||||
await fromB64(key)
|
||||
);
|
||||
const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
pullState,
|
||||
data,
|
||||
null
|
||||
);
|
||||
return pullResult.message;
|
||||
}
|
||||
|
||||
export async function decryptChaCha(
|
||||
data: Uint8Array,
|
||||
header: Uint8Array,
|
||||
key: string
|
||||
) {
|
||||
await sodium.ready;
|
||||
const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(
|
||||
header,
|
||||
await fromB64(key)
|
||||
);
|
||||
const decryptionChunkSize =
|
||||
ENCRYPTION_CHUNK_SIZE +
|
||||
sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||
let bytesRead = 0;
|
||||
const decryptedData = [];
|
||||
let tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
|
||||
while (tag !== sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
|
||||
let chunkSize = decryptionChunkSize;
|
||||
if (bytesRead + chunkSize > data.length) {
|
||||
chunkSize = data.length - bytesRead;
|
||||
}
|
||||
const buffer = data.slice(bytesRead, bytesRead + chunkSize);
|
||||
const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
pullState,
|
||||
buffer
|
||||
);
|
||||
if (!pullResult.message) {
|
||||
throw new Error(CustomError.PROCESSING_FAILED);
|
||||
}
|
||||
for (let index = 0; index < pullResult.message.length; index++) {
|
||||
decryptedData.push(pullResult.message[index]);
|
||||
}
|
||||
tag = pullResult.tag;
|
||||
bytesRead += chunkSize;
|
||||
}
|
||||
return Uint8Array.from(decryptedData);
|
||||
}
|
||||
|
||||
export async function initChunkDecryption(header: Uint8Array, key: Uint8Array) {
|
||||
await sodium.ready;
|
||||
const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(
|
||||
header,
|
||||
key
|
||||
);
|
||||
const decryptionChunkSize =
|
||||
ENCRYPTION_CHUNK_SIZE +
|
||||
sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||
const tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
|
||||
return { pullState, decryptionChunkSize, tag };
|
||||
}
|
||||
|
||||
export async function decryptFileChunk(
|
||||
data: Uint8Array,
|
||||
pullState: StateAddress
|
||||
) {
|
||||
await sodium.ready;
|
||||
const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
pullState,
|
||||
data
|
||||
);
|
||||
if (!pullResult.message) {
|
||||
throw new Error(CustomError.PROCESSING_FAILED);
|
||||
}
|
||||
const newTag = pullResult.tag;
|
||||
return { decryptedData: pullResult.message, newTag };
|
||||
}
|
||||
|
||||
export async function encryptChaChaOneShot(data: Uint8Array, key: string) {
|
||||
await sodium.ready;
|
||||
|
||||
const uintkey: Uint8Array = await fromB64(key);
|
||||
const initPushResult =
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_push(uintkey);
|
||||
const [pushState, header] = [initPushResult.state, initPushResult.header];
|
||||
|
||||
const pushResult = sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
pushState,
|
||||
data,
|
||||
null,
|
||||
sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
|
||||
);
|
||||
return {
|
||||
key: await toB64(uintkey),
|
||||
file: {
|
||||
encryptedData: pushResult,
|
||||
decryptionHeader: await toB64(header),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function encryptChaCha(data: Uint8Array) {
|
||||
await sodium.ready;
|
||||
|
||||
const uintkey: Uint8Array =
|
||||
sodium.crypto_secretstream_xchacha20poly1305_keygen();
|
||||
|
||||
const initPushResult =
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_push(uintkey);
|
||||
const [pushState, header] = [initPushResult.state, initPushResult.header];
|
||||
let bytesRead = 0;
|
||||
let tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
|
||||
|
||||
const encryptedData = [];
|
||||
|
||||
while (tag !== sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
|
||||
let chunkSize = ENCRYPTION_CHUNK_SIZE;
|
||||
if (bytesRead + chunkSize >= data.length) {
|
||||
chunkSize = data.length - bytesRead;
|
||||
tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL;
|
||||
}
|
||||
|
||||
const buffer = data.slice(bytesRead, bytesRead + chunkSize);
|
||||
bytesRead += chunkSize;
|
||||
const pushResult = sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
pushState,
|
||||
buffer,
|
||||
null,
|
||||
tag
|
||||
);
|
||||
for (let index = 0; index < pushResult.length; index++) {
|
||||
encryptedData.push(pushResult[index]);
|
||||
}
|
||||
}
|
||||
return {
|
||||
key: await toB64(uintkey),
|
||||
file: {
|
||||
encryptedData: new Uint8Array(encryptedData),
|
||||
decryptionHeader: await toB64(header),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function initChunkEncryption() {
|
||||
await sodium.ready;
|
||||
const key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
|
||||
const initPushResult =
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
|
||||
const [pushState, header] = [initPushResult.state, initPushResult.header];
|
||||
return {
|
||||
key: await toB64(key),
|
||||
decryptionHeader: await toB64(header),
|
||||
pushState,
|
||||
};
|
||||
}
|
||||
|
||||
export async function encryptFileChunk(
|
||||
data: Uint8Array,
|
||||
pushState: sodium.StateAddress,
|
||||
isFinalChunk: boolean
|
||||
) {
|
||||
await sodium.ready;
|
||||
const tag = isFinalChunk
|
||||
? sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
|
||||
: sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
|
||||
const pushResult = sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
pushState,
|
||||
data,
|
||||
null,
|
||||
tag
|
||||
);
|
||||
|
||||
return pushResult;
|
||||
}
|
||||
export async function encryptToB64(data: string, key: string) {
|
||||
await sodium.ready;
|
||||
const encrypted = await encrypt(await fromB64(data), await fromB64(key));
|
||||
|
||||
return {
|
||||
encryptedData: await toB64(encrypted.encryptedData),
|
||||
key: await toB64(encrypted.key),
|
||||
nonce: await toB64(encrypted.nonce),
|
||||
} as B64EncryptionResult;
|
||||
}
|
||||
|
||||
export async function generateKeyAndEncryptToB64(data: string) {
|
||||
await sodium.ready;
|
||||
const key = sodium.crypto_secretbox_keygen();
|
||||
return await encryptToB64(data, await toB64(key));
|
||||
}
|
||||
|
||||
export async function encryptUTF8(data: string, key: string) {
|
||||
const b64Data = await toB64(await fromUTF8(data));
|
||||
return await encryptToB64(b64Data, key);
|
||||
}
|
||||
|
||||
export async function decryptB64(data: string, nonce: string, key: string) {
|
||||
await sodium.ready;
|
||||
const decrypted = await decrypt(
|
||||
await fromB64(data),
|
||||
await fromB64(nonce),
|
||||
await fromB64(key)
|
||||
);
|
||||
|
||||
return await toB64(decrypted);
|
||||
}
|
||||
|
||||
export async function decryptToUTF8(data: string, nonce: string, key: string) {
|
||||
await sodium.ready;
|
||||
const decrypted = await decrypt(
|
||||
await fromB64(data),
|
||||
await fromB64(nonce),
|
||||
await fromB64(key)
|
||||
);
|
||||
|
||||
return sodium.to_string(decrypted);
|
||||
}
|
||||
|
||||
async function encrypt(data: Uint8Array, key: Uint8Array) {
|
||||
await sodium.ready;
|
||||
const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
|
||||
const encryptedData = sodium.crypto_secretbox_easy(data, nonce, key);
|
||||
return {
|
||||
encryptedData,
|
||||
key,
|
||||
nonce,
|
||||
};
|
||||
}
|
||||
|
||||
async function decrypt(data: Uint8Array, nonce: Uint8Array, key: Uint8Array) {
|
||||
await sodium.ready;
|
||||
return sodium.crypto_secretbox_open_easy(data, nonce, key);
|
||||
}
|
||||
|
||||
export async function initChunkHashing() {
|
||||
await sodium.ready;
|
||||
const hashState = sodium.crypto_generichash_init(
|
||||
null,
|
||||
sodium.crypto_generichash_BYTES_MAX
|
||||
);
|
||||
return hashState;
|
||||
}
|
||||
|
||||
export async function hashFileChunk(
|
||||
hashState: sodium.StateAddress,
|
||||
chunk: Uint8Array
|
||||
) {
|
||||
await sodium.ready;
|
||||
sodium.crypto_generichash_update(hashState, chunk);
|
||||
}
|
||||
|
||||
export async function completeChunkHashing(hashState: sodium.StateAddress) {
|
||||
await sodium.ready;
|
||||
const hash = sodium.crypto_generichash_final(
|
||||
hashState,
|
||||
sodium.crypto_generichash_BYTES_MAX
|
||||
);
|
||||
const hashString = toB64(hash);
|
||||
return hashString;
|
||||
}
|
||||
|
||||
export async function deriveKey(
|
||||
passphrase: string,
|
||||
salt: string,
|
||||
opsLimit: number,
|
||||
memLimit: number
|
||||
) {
|
||||
await sodium.ready;
|
||||
return await toB64(
|
||||
sodium.crypto_pwhash(
|
||||
sodium.crypto_secretbox_KEYBYTES,
|
||||
await fromUTF8(passphrase),
|
||||
await fromB64(salt),
|
||||
opsLimit,
|
||||
memLimit,
|
||||
sodium.crypto_pwhash_ALG_ARGON2ID13
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export async function deriveSensitiveKey(passphrase: string, salt: string) {
|
||||
await sodium.ready;
|
||||
const minMemLimit = sodium.crypto_pwhash_MEMLIMIT_MIN;
|
||||
let opsLimit = sodium.crypto_pwhash_OPSLIMIT_SENSITIVE;
|
||||
let memLimit = sodium.crypto_pwhash_MEMLIMIT_SENSITIVE;
|
||||
while (memLimit > minMemLimit) {
|
||||
try {
|
||||
const key = await deriveKey(passphrase, salt, opsLimit, memLimit);
|
||||
return {
|
||||
key,
|
||||
opsLimit,
|
||||
memLimit,
|
||||
};
|
||||
} catch (e) {
|
||||
opsLimit *= 2;
|
||||
memLimit /= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function deriveInteractiveKey(passphrase: string, salt: string) {
|
||||
await sodium.ready;
|
||||
const key = await toB64(
|
||||
sodium.crypto_pwhash(
|
||||
sodium.crypto_secretbox_KEYBYTES,
|
||||
await fromUTF8(passphrase),
|
||||
await fromB64(salt),
|
||||
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
|
||||
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
|
||||
sodium.crypto_pwhash_ALG_ARGON2ID13
|
||||
)
|
||||
);
|
||||
return {
|
||||
key,
|
||||
opsLimit: sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
|
||||
memLimit: sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateEncryptionKey() {
|
||||
await sodium.ready;
|
||||
return await toB64(sodium.crypto_kdf_keygen());
|
||||
}
|
||||
|
||||
export async function generateSaltToDeriveKey() {
|
||||
await sodium.ready;
|
||||
return await toB64(sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES));
|
||||
}
|
||||
|
||||
export async function generateKeyPair() {
|
||||
await sodium.ready;
|
||||
const keyPair: sodium.KeyPair = sodium.crypto_box_keypair();
|
||||
return {
|
||||
privateKey: await toB64(keyPair.privateKey),
|
||||
publicKey: await toB64(keyPair.publicKey),
|
||||
};
|
||||
}
|
||||
|
||||
export async function boxSealOpen(
|
||||
input: string,
|
||||
publicKey: string,
|
||||
secretKey: string
|
||||
) {
|
||||
await sodium.ready;
|
||||
return await toB64(
|
||||
sodium.crypto_box_seal_open(
|
||||
await fromB64(input),
|
||||
await fromB64(publicKey),
|
||||
await fromB64(secretKey)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export async function boxSeal(input: string, publicKey: string) {
|
||||
await sodium.ready;
|
||||
return await toB64(
|
||||
sodium.crypto_box_seal(await fromB64(input), await fromB64(publicKey))
|
||||
);
|
||||
}
|
||||
|
||||
export async function generateSubKey(
|
||||
key: string,
|
||||
subKeyLength: number,
|
||||
subKeyID: number,
|
||||
context: string
|
||||
) {
|
||||
await sodium.ready;
|
||||
return await toB64(
|
||||
sodium.crypto_kdf_derive_from_key(
|
||||
subKeyLength,
|
||||
subKeyID,
|
||||
context,
|
||||
await fromB64(key)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export async function fromB64(input: string) {
|
||||
await sodium.ready;
|
||||
return sodium.from_base64(input, sodium.base64_variants.ORIGINAL);
|
||||
}
|
||||
|
||||
export async function toB64(input: Uint8Array) {
|
||||
await sodium.ready;
|
||||
return sodium.to_base64(input, sodium.base64_variants.ORIGINAL);
|
||||
}
|
||||
|
||||
export async function toURLSafeB64(input: Uint8Array) {
|
||||
await sodium.ready;
|
||||
return sodium.to_base64(input, sodium.base64_variants.URLSAFE);
|
||||
}
|
||||
|
||||
export async function fromUTF8(input: string) {
|
||||
await sodium.ready;
|
||||
return sodium.from_string(input);
|
||||
}
|
||||
|
||||
export async function toUTF8(input: string) {
|
||||
await sodium.ready;
|
||||
return sodium.to_string(await fromB64(input));
|
||||
}
|
||||
export async function toHex(input: string) {
|
||||
await sodium.ready;
|
||||
return sodium.to_hex(await fromB64(input));
|
||||
}
|
||||
|
||||
export async function fromHex(input: string) {
|
||||
await sodium.ready;
|
||||
return await toB64(sodium.from_hex(input));
|
||||
}
|
Loading…
Add table
Reference in a new issue