Merge pull request #959 from ente-io/crypto-internal-review

Refactor CryptoWorker
This commit is contained in:
Abhinav Kumar 2023-02-28 17:15:14 +05:30 committed by GitHub
commit 9eb904c666
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 68 additions and 79 deletions

View file

@ -207,7 +207,7 @@ class DownloadManager {
);
const fileKey = await cryptoWorker.fromB64(file.key);
const { pullState, decryptionChunkSize } =
await cryptoWorker.initDecryption(
await cryptoWorker.initChunkDecryption(
decryptionHeader,
fileKey
);
@ -229,7 +229,7 @@ class DownloadManager {
decryptionChunkSize
);
const { decryptedData } =
await cryptoWorker.decryptChunk(
await cryptoWorker.decryptFileChunk(
fileData,
pullState
);
@ -242,7 +242,7 @@ class DownloadManager {
} else {
if (data) {
const { decryptedData } =
await cryptoWorker.decryptChunk(
await cryptoWorker.decryptFileChunk(
data,
pullState
);

View file

@ -214,7 +214,7 @@ class PublicCollectionDownloadManager {
);
const fileKey = await cryptoWorker.fromB64(file.key);
const { pullState, decryptionChunkSize } =
await cryptoWorker.initDecryption(
await cryptoWorker.initChunkDecryption(
decryptionHeader,
fileKey
);
@ -236,7 +236,7 @@ class PublicCollectionDownloadManager {
decryptionChunkSize
);
const { decryptedData } =
await cryptoWorker.decryptChunk(
await cryptoWorker.decryptFileChunk(
fileData,
pullState
);
@ -249,7 +249,7 @@ class PublicCollectionDownloadManager {
} else {
if (data) {
const { decryptedData } =
await cryptoWorker.decryptChunk(
await cryptoWorker.decryptFileChunk(
data,
pullState
);

View file

@ -1,7 +1,12 @@
import { Remote } from 'comlink';
import { EncryptionResult } from 'types/crypto';
import { DataStream, isDataStream } from 'types/upload';
import { DedicatedCryptoWorker } from 'worker/crypto.worker';
async function encryptFileStream(worker, fileData: DataStream) {
async function encryptFileStream(
worker: Remote<DedicatedCryptoWorker>,
fileData: DataStream
) {
const { stream, chunkCount } = fileData;
const fileStreamReader = stream.getReader();
const { key, decryptionHeader, pushState } =
@ -32,7 +37,7 @@ async function encryptFileStream(worker, fileData: DataStream) {
}
export async function encryptFiledata(
worker,
worker: Remote<DedicatedCryptoWorker>,
filedata: Uint8Array | DataStream
): Promise<EncryptionResult<Uint8Array | DataStream>> {
return isDataStream(filedata)

View file

@ -69,7 +69,7 @@ export async function readFile(
}
export async function extractFileMetadata(
worker,
worker: Remote<DedicatedCryptoWorker>,
parsedMetadataJSONMap: ParsedMetadataJSONMap,
collectionID: number,
fileTypeInfo: FileTypeInfo,

View file

@ -1,11 +1,16 @@
import { Remote } from 'comlink';
import { FILE_READER_CHUNK_SIZE } from 'constants/upload';
import { getFileStream, getElectronFileStream } from 'services/readerService';
import { ElectronFile, DataStream } from 'types/upload';
import { CustomError } from 'utils/error';
import { addLogLine, getFileNameSize } from 'utils/logging';
import { logError } from 'utils/sentry';
import { DedicatedCryptoWorker } from 'worker/crypto.worker';
export async function getFileHash(worker, file: File | ElectronFile) {
export async function getFileHash(
worker: Remote<DedicatedCryptoWorker>,
file: File | ElectronFile
) {
try {
addLogLine(`getFileHash called for ${getFileNameSize(file)}`);
let filedata: DataStream;

View file

@ -18,6 +18,8 @@ import { extractFileMetadata } from './fileService';
import { getFileHash } from './hashService';
import { generateThumbnail } from './thumbnailService';
import uploadCancelService from './uploadCancelService';
import { Remote } from 'comlink';
import { DedicatedCryptoWorker } from 'worker/crypto.worker';
interface LivePhotoIdentifier {
collectionID: number;
@ -44,7 +46,7 @@ export async function getLivePhotoFileType(
}
export async function extractLivePhotoMetadata(
worker,
worker: Remote<DedicatedCryptoWorker>,
parsedMetadataJSONMap: ParsedMetadataJSONMap,
collectionID: number,
fileTypeInfo: FileTypeInfo,

View file

@ -17,6 +17,8 @@ import {
tryToParseDateTime,
} from 'utils/time';
import { getFileHash } from './hashService';
import { Remote } from 'comlink';
import { DedicatedCryptoWorker } from 'worker/crypto.worker';
interface ParsedMetadataJSONWithTitle {
title: string;
@ -30,7 +32,7 @@ const NULL_PARSED_METADATA_JSON: ParsedMetadataJSON = {
};
export async function extractMetadata(
worker,
worker: Remote<DedicatedCryptoWorker>,
receivedFile: File | ElectronFile,
fileTypeInfo: FileTypeInfo
) {

View file

@ -105,7 +105,7 @@ class UploadService {
}
async extractAssetMetadata(
worker,
worker: Remote<DedicatedCryptoWorker>,
{ isLivePhoto, file, livePhotoAssets }: UploadAsset,
collectionID: number,
fileTypeInfo: FileTypeInfo

View file

@ -88,8 +88,11 @@ export const saveKeyInSessionStore = async (
key: string,
fromDesktop?: boolean
) => {
// the key is encrypted before saving in session storage, to obfuscate it from the browser
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
const sessionKeyAttributes = await cryptoWorker.encryptToB64(key);
const sessionKeyAttributes = await cryptoWorker.generateKeyAndEncryptToB64(
key
);
setKey(keyType, sessionKeyAttributes);
if (isElectron() && !fromDesktop) {
safeStorageService.setEncryptionKey(key);

View file

@ -69,7 +69,10 @@ export async function initChunkDecryption(header: Uint8Array, key: Uint8Array) {
return { pullState, decryptionChunkSize, tag };
}
export async function decryptChunk(data: Uint8Array, pullState: StateAddress) {
export async function decryptFileChunk(
data: Uint8Array,
pullState: StateAddress
) {
await sodium.ready;
const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
pullState,
@ -79,12 +82,10 @@ export async function decryptChunk(data: Uint8Array, pullState: StateAddress) {
return { decryptedData: pullResult.message, newTag };
}
export async function encryptChaChaOneShot(data: Uint8Array, key?: string) {
export async function encryptChaChaOneShot(data: Uint8Array, key: string) {
await sodium.ready;
const uintkey: Uint8Array = key
? await fromB64(key)
: sodium.crypto_secretstream_xchacha20poly1305_keygen();
const uintkey: Uint8Array = await fromB64(key);
const initPushResult =
sodium.crypto_secretstream_xchacha20poly1305_init_push(uintkey);
const [pushState, header] = [initPushResult.state, initPushResult.header];
@ -104,12 +105,11 @@ export async function encryptChaChaOneShot(data: Uint8Array, key?: string) {
};
}
export async function encryptChaCha(data: Uint8Array, key?: string) {
export async function encryptChaCha(data: Uint8Array) {
await sodium.ready;
const uintkey: Uint8Array = key
? await fromB64(key)
: sodium.crypto_secretstream_xchacha20poly1305_keygen();
const uintkey: Uint8Array =
sodium.crypto_secretstream_xchacha20poly1305_keygen();
const initPushResult =
sodium.crypto_secretstream_xchacha20poly1305_init_push(uintkey);
@ -159,14 +159,14 @@ export async function initChunkEncryption() {
pushState,
};
}
export async function encryptFileChunk(
data: Uint8Array,
pushState: sodium.StateAddress,
finalChunk?: boolean
isFinalChunk: boolean
) {
await sodium.ready;
const tag = finalChunk
const tag = isFinalChunk
? sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
: sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
const pushResult = sodium.crypto_secretstream_xchacha20poly1305_push(
@ -178,12 +178,9 @@ export async function encryptFileChunk(
return pushResult;
}
export async function encryptToB64(data: string, key?: string) {
export async function encryptToB64(data: string, key: string) {
await sodium.ready;
const encrypted = await encrypt(
await fromB64(data),
key ? await fromB64(key) : null
);
const encrypted = await encrypt(await fromB64(data), await fromB64(key));
return {
encryptedData: await toB64(encrypted.encryptedData),
@ -191,7 +188,13 @@ export async function encryptToB64(data: string, key?: string) {
nonce: await toB64(encrypted.nonce),
} as B64EncryptionResult;
}
export async function encryptUTF8(data: string, key?: string) {
export async function generateKeyAndEncryptToB64(data: string) {
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 fromString(data));
return await encryptToB64(b64Data, key);
}
@ -218,41 +221,22 @@ export async function decryptToUTF8(data: string, nonce: string, key: string) {
return sodium.to_string(decrypted);
}
export async function encrypt(data: Uint8Array, key?: Uint8Array) {
async function encrypt(data: Uint8Array, key: Uint8Array) {
await sodium.ready;
const uintkey: Uint8Array = key || sodium.crypto_secretbox_keygen();
const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
const encryptedData = sodium.crypto_secretbox_easy(data, nonce, uintkey);
const encryptedData = sodium.crypto_secretbox_easy(data, nonce, key);
return {
encryptedData,
key: uintkey,
key,
nonce,
};
}
export async function decrypt(
data: Uint8Array,
nonce: Uint8Array,
key: Uint8Array
) {
async function decrypt(data: Uint8Array, nonce: Uint8Array, key: Uint8Array) {
await sodium.ready;
return sodium.crypto_secretbox_open_easy(data, nonce, key);
}
export async function verifyHash(hash: string, input: string) {
await sodium.ready;
return sodium.crypto_pwhash_str_verify(hash, await fromB64(input));
}
export async function hash(input: string) {
await sodium.ready;
return sodium.crypto_pwhash_str(
await fromB64(input),
sodium.crypto_pwhash_OPSLIMIT_SENSITIVE,
sodium.crypto_pwhash_MEMLIMIT_MODERATE
);
}
export async function initChunkHashing() {
await sodium.ready;
const hashState = sodium.crypto_generichash_init(

View file

@ -49,44 +49,28 @@ export class DedicatedCryptoWorker {
return libsodium.encryptChaChaOneShot(fileData, key);
}
async encryptFile(fileData: Uint8Array, key: string) {
return libsodium.encryptChaCha(fileData, key);
async encryptFile(fileData: Uint8Array) {
return libsodium.encryptChaCha(fileData);
}
async encryptFileChunk(
data: Uint8Array,
pushState: StateAddress,
finalChunk: boolean
isFinalChunk: boolean
) {
return libsodium.encryptFileChunk(data, pushState, finalChunk);
return libsodium.encryptFileChunk(data, pushState, isFinalChunk);
}
async initChunkEncryption() {
return libsodium.initChunkEncryption();
}
async initDecryption(header: Uint8Array, key: Uint8Array) {
async initChunkDecryption(header: Uint8Array, key: Uint8Array) {
return libsodium.initChunkDecryption(header, key);
}
async decryptChunk(fileData: Uint8Array, pullState: StateAddress) {
return libsodium.decryptChunk(fileData, pullState);
}
async encrypt(data: Uint8Array, key: Uint8Array) {
return libsodium.encrypt(data, key);
}
async decrypt(data: Uint8Array, nonce: Uint8Array, key: Uint8Array) {
return libsodium.decrypt(data, nonce, key);
}
async hash(input: string) {
return libsodium.hash(input);
}
async verifyHash(hash: string, input: string) {
return libsodium.verifyHash(hash, input);
async decryptFileChunk(fileData: Uint8Array, pullState: StateAddress) {
return libsodium.decryptFileChunk(fileData, pullState);
}
async initChunkHashing() {
@ -126,10 +110,14 @@ export class DedicatedCryptoWorker {
return libsodium.decryptToUTF8(data, nonce, key);
}
async encryptToB64(data: string, key?: string) {
async encryptToB64(data: string, key: string) {
return libsodium.encryptToB64(data, key);
}
async generateKeyAndEncryptToB64(data: string) {
return libsodium.generateKeyAndEncryptToB64(data);
}
async encryptUTF8(data: string, key: string) {
return libsodium.encryptUTF8(data, key);
}