diff --git a/web/apps/auth/src/services/remote.ts b/web/apps/auth/src/services/remote.ts index 21c756ea23..1af10ddb0e 100644 --- a/web/apps/auth/src/services/remote.ts +++ b/web/apps/auth/src/services/remote.ts @@ -1,4 +1,4 @@ -import { decryptBoxB64, decryptMetadataJSON_New } from "ente-base/crypto"; +import { decryptBox, decryptMetadataJSON_New } from "ente-base/crypto"; import { authenticatedRequestHeaders, ensureOk, @@ -265,7 +265,7 @@ const decryptAuthenticatorKey = async ( remote: AuthenticatorEntityKey, masterKey: Uint8Array, ) => - decryptBoxB64( + decryptBox( { encryptedData: remote.encryptedKey, // Remote calls it the header, but it really is the nonce. diff --git a/web/apps/cast/src/services/render.ts b/web/apps/cast/src/services/render.ts index a99dfaa74d..35f5388e8a 100644 --- a/web/apps/cast/src/services/render.ts +++ b/web/apps/cast/src/services/render.ts @@ -195,7 +195,7 @@ const decryptEnteFile = async ( pubMagicMetadata, ...restFileProps } = encryptedFile; - const fileKey = await worker.decryptBoxB64( + const fileKey = await worker.decryptBox( { encryptedData: encryptedKey, nonce: keyDecryptionNonce }, collectionKey, ); diff --git a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx index 095034e3b5..ddbfe612f3 100644 --- a/web/packages/accounts/components/VerifyMasterPasswordForm.tsx +++ b/web/packages/accounts/components/VerifyMasterPasswordForm.tsx @@ -171,7 +171,7 @@ export const VerifyMasterPasswordForm: React.FC< let key: string; try { - key = await cryptoWorker.decryptBoxB64( + key = await cryptoWorker.decryptBox( { encryptedData: keyAttributes.encryptedKey, nonce: keyAttributes.keyDecryptionNonce, diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index 6ea11ba5c8..0e8820512f 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -140,14 +140,14 @@ const Page: React.FC = () => { if (kekEncryptedAttributes && keyAttributes) { removeKey("keyEncryptionKey"); const cryptoWorker = await sharedCryptoWorker(); - const kek = await cryptoWorker.decryptBoxB64( + const kek = await cryptoWorker.decryptBox( { encryptedData: kekEncryptedAttributes.encryptedData, nonce: kekEncryptedAttributes.nonce, }, kekEncryptedAttributes.key, ); - const key = await cryptoWorker.decryptBoxB64( + const key = await cryptoWorker.decryptBox( { encryptedData: keyAttributes.encryptedKey, nonce: keyAttributes.keyDecryptionNonce, diff --git a/web/packages/accounts/pages/recover.tsx b/web/packages/accounts/pages/recover.tsx index 76db2cfcf5..af2ea04bc5 100644 --- a/web/packages/accounts/pages/recover.tsx +++ b/web/packages/accounts/pages/recover.tsx @@ -13,7 +13,7 @@ import { type SingleInputFormProps, } from "ente-base/components/SingleInputForm"; import { useBaseContext } from "ente-base/context"; -import { decryptBoxB64 } from "ente-base/crypto"; +import { decryptBox } from "ente-base/crypto"; import log from "ente-base/log"; import { decryptAndStoreToken, @@ -63,7 +63,7 @@ const Page: React.FC = () => { ) => { try { const keyAttr = keyAttributes!; - const masterKey = await decryptBoxB64( + const masterKey = await decryptBox( { encryptedData: keyAttr.masterKeyEncryptedWithRecoveryKey!, nonce: keyAttr.masterKeyDecryptionNonce!, diff --git a/web/packages/accounts/pages/two-factor/recover.tsx b/web/packages/accounts/pages/two-factor/recover.tsx index 8a6d2fe3a7..5c4af55b8a 100644 --- a/web/packages/accounts/pages/two-factor/recover.tsx +++ b/web/packages/accounts/pages/two-factor/recover.tsx @@ -18,7 +18,7 @@ import { type SingleInputFormProps, } from "ente-base/components/SingleInputForm"; import { useBaseContext } from "ente-base/context"; -import { decryptBoxB64 } from "ente-base/crypto"; +import { decryptBox } from "ente-base/crypto"; import type { B64EncryptionResult } from "ente-base/crypto/libsodium"; import log from "ente-base/log"; import { ApiError } from "ente-shared/error"; @@ -93,7 +93,7 @@ const Page: React.FC = ({ twoFactorType }) => { ) => { try { const { encryptedData, nonce } = encryptedTwoFactorSecret!; - const twoFactorSecret = await decryptBoxB64( + const twoFactorSecret = await decryptBox( { encryptedData, nonce }, await recoveryKeyB64FromMnemonic(recoveryKey), ); diff --git a/web/packages/accounts/services/recovery-key.ts b/web/packages/accounts/services/recovery-key.ts index 8db572d782..cd70de86cc 100644 --- a/web/packages/accounts/services/recovery-key.ts +++ b/web/packages/accounts/services/recovery-key.ts @@ -1,7 +1,7 @@ import * as bip39 from "bip39"; import type { KeyAttributes } from "ente-accounts/services/user"; import { - decryptBoxB64, + decryptBox, fromHex, sharedCryptoWorker, toHex, @@ -69,7 +69,7 @@ export const getUserRecoveryKeyB64 = async () => { keyAttributes; if (recoveryKeyEncryptedWithMasterKey && recoveryKeyDecryptionNonce) { - return decryptBoxB64( + return decryptBox( { encryptedData: recoveryKeyEncryptedWithMasterKey, nonce: recoveryKeyDecryptionNonce, diff --git a/web/packages/base/crypto/ente-impl.ts b/web/packages/base/crypto/ente-impl.ts index 39bc8eac9a..e6123ae1c5 100644 --- a/web/packages/base/crypto/ente-impl.ts +++ b/web/packages/base/crypto/ente-impl.ts @@ -20,13 +20,16 @@ export const _encryptBoxB64 = libsodium.encryptBoxB64; export const _encryptBlob = libsodium.encryptBlob; -export const _encryptBlobB64 = libsodium.encryptBlobB64; +export const _encryptBlobBytes = libsodium.encryptBlobBytes; export const _encryptThumbnail = async ( data: BytesOrB64, key: BytesOrB64, ): Promise => { - const { encryptedData, decryptionHeader } = await _encryptBlob(data, key); + const { encryptedData, decryptionHeader } = await _encryptBlobBytes( + data, + key, + ); return { encryptedData, decryptionHeader: await libsodium.toB64(decryptionHeader), @@ -40,7 +43,7 @@ export const _initChunkEncryption = libsodium.initChunkEncryption; export const _encryptStreamChunk = libsodium.encryptStreamChunk; export const _encryptMetadataJSON_New = (jsonValue: unknown, key: BytesOrB64) => - _encryptBlobB64(new TextEncoder().encode(JSON.stringify(jsonValue)), key); + _encryptBlob(new TextEncoder().encode(JSON.stringify(jsonValue)), key); // Deprecated, translates to the old API for now. export const _encryptMetadataJSON = async (r: { @@ -57,9 +60,9 @@ export const _encryptMetadataJSON = async (r: { }; }; -export const _decryptBox = libsodium.decryptBox; +export const _decryptBoxBytes = libsodium.decryptBoxBytes; -export const _decryptBoxB64 = libsodium.decryptBoxB64; +export const _decryptBox = libsodium.decryptBox; export const _decryptBlob = libsodium.decryptBlob; diff --git a/web/packages/base/crypto/index.ts b/web/packages/base/crypto/index.ts index d7abbb7a13..9c1fbb3198 100644 --- a/web/packages/base/crypto/index.ts +++ b/web/packages/base/crypto/index.ts @@ -162,7 +162,7 @@ export const generateBlobOrStreamKey = () => * * Both the encrypted data and the nonce are returned as base64 strings. * - * Use {@link decryptBoxB64} to decrypt the result. + * Use {@link decryptBox} to decrypt the result. * * > The suffix "Box" comes from the fact that it uses the so called secretbox * > APIs provided by libsodium under the hood. @@ -176,7 +176,7 @@ export const encryptBoxB64 = (data: BytesOrB64, key: BytesOrB64) => /** * Encrypt the given data, returning a blob containing the encrypted data and a - * decryption header. + * decryption header as base64 strings. * * This function is usually used to encrypt data associated with an Ente object * (file, collection, entity) using the object's key. @@ -189,22 +189,24 @@ export const encryptBoxB64 = (data: BytesOrB64, key: BytesOrB64) => * > See: [Note: 3 forms of encryption (Box | Blob | Stream)] */ export const encryptBlob = (data: BytesOrB64, key: BytesOrB64) => - assertInWorker(ei._encryptBlob(data, key)); + inWorker() + ? ei._encryptBlob(data, key) + : sharedWorker().then((w) => w.encryptBlob(data, key)); /** - * A variant of {@link encryptBlob} that returns the result components as base64 - * strings. + * A variant of {@link encryptBlob} that returns the result components as bytes + * instead of as base64 strings. + * + * Use {@link decryptBlob} to decrypt the result. */ -export const encryptBlobB64 = (data: BytesOrB64, key: BytesOrB64) => - inWorker() - ? ei._encryptBlobB64(data, key) - : sharedWorker().then((w) => w.encryptBlobB64(data, key)); +export const encryptBlobBytes = (data: BytesOrB64, key: BytesOrB64) => + assertInWorker(ei._encryptBlobBytes(data, key)); /** * Encrypt the thumbnail for a file. * - * This is midway variant of {@link encryptBlob} and {@link encryptBlobB64} that - * returns the decryption header as a base64 string, but leaves the data + * This is midway variant of {@link encryptBlobBytes} and {@link encryptBlob} + * that returns the decryption header as a base64 string, but leaves the data * unchanged. * * Use {@link decryptThumbnail} to decrypt the result. @@ -249,7 +251,7 @@ export const encryptStreamChunk = async ( * Encrypt the JSON metadata associated with an Ente object (file, collection or * entity) using the object's key. * - * This is a variant of {@link encryptBlobB64} tailored for encrypting any + * This is a variant of {@link encryptBlob} tailored for encrypting any * arbitrary metadata associated with an Ente object. For example, it is used * for encrypting the various metadata fields associated with a file, using that * file's key. @@ -283,7 +285,7 @@ export const encryptMetadataJSON = async (r: { /** * Decrypt a box encrypted using {@link encryptBoxB64} and returns the decrypted - * bytes. + * bytes as a base64 string. */ export const decryptBox = (box: EncryptedBox, key: BytesOrB64) => inWorker() @@ -291,16 +293,17 @@ export const decryptBox = (box: EncryptedBox, key: BytesOrB64) => : sharedWorker().then((w) => w.decryptBox(box, key)); /** - * Variant of {@link decryptBox} that returns the result as a base64 string. + * Variant of {@link decryptBox} that returns the decrypted bytes as it is + * (without encoding them to base64). */ -export const decryptBoxB64 = (box: EncryptedBox, key: BytesOrB64) => +export const decryptBoxBytes = (box: EncryptedBox, key: BytesOrB64) => inWorker() - ? ei._decryptBoxB64(box, key) - : sharedWorker().then((w) => w.decryptBoxB64(box, key)); + ? ei._decryptBoxBytes(box, key) + : sharedWorker().then((w) => w.decryptBoxBytes(box, key)); /** - * Decrypt a blob encrypted using either {@link encryptBlob} or - * {@link encryptBlobB64}. + * Decrypt a blob encrypted using either {@link encryptBlobBytes} or + * {@link encryptBlob}. */ export const decryptBlob = (blob: EncryptedBlob, key: BytesOrB64) => inWorker() diff --git a/web/packages/base/crypto/libsodium.ts b/web/packages/base/crypto/libsodium.ts index 1f58fccbab..efa31aeaf6 100644 --- a/web/packages/base/crypto/libsodium.ts +++ b/web/packages/base/crypto/libsodium.ts @@ -150,7 +150,7 @@ const bytes = async (bob: BytesOrB64) => * hypothetical "generateBoxKey") and {@link generateBlobOrStreamKey} produce * 256-bits of entropy that does not have any ties to a particular algorithm. * - * @returns A new randomly generated 256-bit key. + * @returns A new randomly generated 256-bit key (as a base64 string). */ export const generateKey = async () => { await sodium.ready; @@ -161,8 +161,8 @@ export const generateKey = async () => { * Generate a new key for use with the *Blob or *Stream encryption functions, * and return its base64 string representation. * - * This returns a new randomly generated 256-bit key suitable for being used - * with libsodium's secretstream APIs. + * This returns a new randomly generated 256-bit key (as a base64 string) + * suitable for being used with libsodium's secretstream APIs. */ export const generateBlobOrStreamKey = async () => { await sodium.ready; @@ -173,7 +173,7 @@ export const generateBlobOrStreamKey = async () => { * Encrypt the given data using libsodium's secretbox APIs, using a randomly * generated nonce. * - * Use {@link decryptBox} to decrypt the result. + * Use {@link decryptBoxBytes} to decrypt the result. * * @param data The data to encrypt. * @@ -298,7 +298,7 @@ export const encryptBoxB64 = async ( * * - See: https://doc.libsodium.org/secret-key_cryptography/secretstream */ -export const encryptBlob = async ( +export const encryptBlobBytes = async ( data: BytesOrB64, key: BytesOrB64, ): Promise => { @@ -319,14 +319,19 @@ export const encryptBlob = async ( }; /** - * A variant of {@link encryptBlob} that returns the both the encrypted data and - * decryption header as base64 strings. + * A higher level variant of {@link encryptBlobBytes} that returns the both the + * encrypted data and decryption header as base64 strings. + * + * This is the variant expected to serve majority of the public API use cases. */ -export const encryptBlobB64 = async ( +export const encryptBlob = async ( data: BytesOrB64, key: BytesOrB64, ): Promise => { - const { encryptedData, decryptionHeader } = await encryptBlob(data, key); + const { encryptedData, decryptionHeader } = await encryptBlobBytes( + data, + key, + ); return { encryptedData: await toB64(encryptedData), decryptionHeader: await toB64(decryptionHeader), @@ -466,7 +471,7 @@ export const encryptStreamChunk = async ( /** * Decrypt the result of {@link encryptBoxB64} and return the decrypted bytes. */ -export const decryptBox = async ( +export const decryptBoxBytes = async ( { encryptedData, nonce }: EncryptedBox, key: BytesOrB64, ): Promise => { @@ -479,15 +484,15 @@ export const decryptBox = async ( }; /** - * Variant of {@link decryptBox} that returns the data as a base64 string. + * Variant of {@link decryptBoxBytes} that returns the data as a base64 string. */ -export const decryptBoxB64 = ( +export const decryptBox = ( box: EncryptedBox, key: BytesOrB64, -): Promise => decryptBox(box, key).then(toB64); +): Promise => decryptBoxBytes(box, key).then(toB64); /** - * Decrypt the result of {@link encryptBlob} or {@link encryptBlobB64}. + * Decrypt the result of {@link encryptBlobBytes} or {@link encryptBlob}. */ export const decryptBlob = async ( { encryptedData, decryptionHeader }: EncryptedBlob, @@ -628,13 +633,13 @@ export async function encryptUTF8(data: string, key: string) { return await encryptToB64(b64Data, key); } -/** Deprecated, use {@link decryptBoxB64} instead. */ +/** Deprecated, use {@link decryptBox} instead. */ export async function decryptB64( encryptedData: string, nonce: string, keyB64: string, ) { - return decryptBoxB64({ encryptedData, nonce }, keyB64); + return decryptBox({ encryptedData, nonce }, keyB64); } /** Deprecated */ @@ -644,7 +649,7 @@ export async function decryptToUTF8( keyB64: string, ) { await sodium.ready; - const decrypted = await decryptBox({ encryptedData, nonce }, keyB64); + const decrypted = await decryptBoxBytes({ encryptedData, nonce }, keyB64); return sodium.to_string(decrypted); } diff --git a/web/packages/base/crypto/worker.ts b/web/packages/base/crypto/worker.ts index 720b993d1d..64737f61fe 100644 --- a/web/packages/base/crypto/worker.ts +++ b/web/packages/base/crypto/worker.ts @@ -22,14 +22,14 @@ export class CryptoWorker { generateBlobOrStreamKey = ei._generateBlobOrStreamKey; encryptBoxB64 = ei._encryptBoxB64; encryptThumbnail = ei._encryptThumbnail; - encryptBlobB64 = ei._encryptBlobB64; + encryptBlob = ei._encryptBlob; encryptStreamBytes = ei._encryptStreamBytes; initChunkEncryption = ei._initChunkEncryption; encryptStreamChunk = ei._encryptStreamChunk; encryptMetadataJSON_New = ei._encryptMetadataJSON_New; encryptMetadataJSON = ei._encryptMetadataJSON; + decryptBoxBytes = ei._decryptBoxBytes; decryptBox = ei._decryptBox; - decryptBoxB64 = ei._decryptBoxB64; decryptBlob = ei._decryptBlob; decryptBlobB64 = ei._decryptBlobB64; decryptThumbnail = ei._decryptThumbnail; diff --git a/web/packages/base/session.ts b/web/packages/base/session.ts index b4bbb93ba4..d895068d52 100644 --- a/web/packages/base/session.ts +++ b/web/packages/base/session.ts @@ -1,5 +1,5 @@ import { z } from "zod/v4"; -import { decryptBox } from "./crypto"; +import { decryptBoxBytes } from "./crypto"; import { toB64 } from "./crypto/libsodium"; /** @@ -81,7 +81,7 @@ export const masterKeyFromSessionIfLoggedIn = async () => { const { encryptedData, key, nonce } = SessionKeyData.parse( JSON.parse(value), ); - return decryptBox({ encryptedData, nonce }, key); + return decryptBoxBytes({ encryptedData, nonce }, key); }; /** @@ -116,5 +116,5 @@ export const unstashKeyEncryptionKeyFromSession = async () => { const { encryptedData, key, nonce } = SessionKeyData.parse( JSON.parse(value), ); - return decryptBox({ encryptedData, nonce }, key); + return decryptBoxBytes({ encryptedData, nonce }, key); }; diff --git a/web/packages/gallery/services/file-data.ts b/web/packages/gallery/services/file-data.ts index e460c32f97..6e456fa122 100644 --- a/web/packages/gallery/services/file-data.ts +++ b/web/packages/gallery/services/file-data.ts @@ -1,4 +1,4 @@ -import { encryptBlobB64 } from "ente-base/crypto"; +import { encryptBlob } from "ente-base/crypto"; import type { EncryptedBlobB64 } from "ente-base/crypto/types"; import { authenticatedPublicAlbumsRequestHeaders, @@ -293,7 +293,7 @@ export const putFileData = async ( data: Uint8Array, lastUpdatedAt: number, ) => { - const { encryptedData, decryptionHeader } = await encryptBlobB64( + const { encryptedData, decryptionHeader } = await encryptBlob( data, file.key, ); diff --git a/web/packages/gallery/services/video.ts b/web/packages/gallery/services/video.ts index 6a33969f10..b3f4ebb775 100644 --- a/web/packages/gallery/services/video.ts +++ b/web/packages/gallery/services/video.ts @@ -1,6 +1,6 @@ import { isDesktop } from "ente-base/app"; import { assertionFailed } from "ente-base/assert"; -import { decryptBlob, encryptBlobB64 } from "ente-base/crypto"; +import { decryptBlob, encryptBlob } from "ente-base/crypto"; import type { EncryptedBlob } from "ente-base/crypto/types"; import { ensureElectron } from "ente-base/electron"; import { isHTTP4xxError, type PublicAlbumsCredentials } from "ente-base/http"; @@ -1056,7 +1056,7 @@ const processQueueItem = async ({ size: videoSize, }); - const encryptedPlaylist = await encryptBlobB64(playlistData, file.key); + const encryptedPlaylist = await encryptBlob(playlistData, file.key); try { await putVideoData( diff --git a/web/packages/media/file.ts b/web/packages/media/file.ts index bc6c3bc483..dda205381d 100644 --- a/web/packages/media/file.ts +++ b/web/packages/media/file.ts @@ -321,7 +321,7 @@ export async function decryptFile( pubMagicMetadata, ...restFileProps } = file; - const fileKey = await worker.decryptBoxB64( + const fileKey = await worker.decryptBox( { encryptedData: encryptedKey, nonce: keyDecryptionNonce }, collectionKey, ); diff --git a/web/packages/new/photos/services/user-entity/index.ts b/web/packages/new/photos/services/user-entity/index.ts index 16d3a904e6..f90a95c122 100644 --- a/web/packages/new/photos/services/user-entity/index.ts +++ b/web/packages/new/photos/services/user-entity/index.ts @@ -1,6 +1,6 @@ import { - decryptBoxB64, - encryptBlobB64, + decryptBox, + encryptBlob, encryptBoxB64, generateBlobOrStreamKey, } from "ente-base/crypto"; @@ -194,7 +194,7 @@ export const encryptedUserEntityData = async ( const bytes = isGzipped(type) ? await gzip(json) : new TextEncoder().encode(json); - return encryptBlobB64(bytes, entityKeyB64); + return encryptBlob(bytes, entityKeyB64); }; /** @@ -280,7 +280,7 @@ const decryptEntityKey = async ( remote: RemoteUserEntityKey, masterKey: Uint8Array, ) => - decryptBoxB64( + decryptBox( { encryptedData: remote.encryptedKey, // Remote calls it the header, but it really is the nonce. diff --git a/web/packages/shared/crypto/helpers.ts b/web/packages/shared/crypto/helpers.ts index 15b4a631bd..f63eb67f3c 100644 --- a/web/packages/shared/crypto/helpers.ts +++ b/web/packages/shared/crypto/helpers.ts @@ -116,7 +116,7 @@ export const decryptDeleteAccountChallenge = async ( const cryptoWorker = await sharedCryptoWorker(); const masterKey = await masterKeyFromSession(); const keyAttributes = getData("keyAttributes"); - const secretKey = await cryptoWorker.decryptBoxB64( + const secretKey = await cryptoWorker.decryptBox( { encryptedData: keyAttributes.encryptedSecretKey, nonce: keyAttributes.secretKeyDecryptionNonce,