diff --git a/apps/photos/src/components/SignUp.tsx b/apps/photos/src/components/SignUp.tsx index 38509e8fd..95dcee276 100644 --- a/apps/photos/src/components/SignUp.tsx +++ b/apps/photos/src/components/SignUp.tsx @@ -7,9 +7,7 @@ import { useRouter } from 'next/router'; import SubmitButton from 'components/SubmitButton'; import { generateAndSaveIntermediateKeyAttributes, - generateKeyAttributes, - generateLoginSubKey, - generateSRPSetupAttributes, + generateKeyAndSRPAttributes, isWeakPassword, saveKeyInSessionStore, } from 'utils/crypto'; @@ -79,18 +77,8 @@ export default function SignUp(props: SignUpProps) { throw e; } try { - const { keyAttributes, masterKey } = - await generateKeyAttributes(passphrase); - - const loginSubKey = await generateLoginSubKey( - passphrase, - keyAttributes.kekSalt, - keyAttributes.memLimit, - keyAttributes.opsLimit - ); - const srpSetupAttributes = await generateSRPSetupAttributes( - loginSubKey - ); + const { keyAttributes, masterKey, srpSetupAttributes } = + await generateKeyAndSRPAttributes(passphrase); setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes); setData(LS_KEYS.SRP_SETUP_ATTRIBUTES, srpSetupAttributes); diff --git a/apps/photos/src/pages/change-password/index.tsx b/apps/photos/src/pages/change-password/index.tsx index 238a2dc6e..4c20ae0b3 100644 --- a/apps/photos/src/pages/change-password/index.tsx +++ b/apps/photos/src/pages/change-password/index.tsx @@ -69,12 +69,7 @@ export default function ChangePassword() { memLimit: kek.memLimit, }; - const loginSubKey = await generateLoginSubKey( - passphrase, - updatedKey.kekSalt, - updatedKey.opsLimit, - updatedKey.memLimit - ); + const loginSubKey = await generateLoginSubKey(kek.key); const { srpUserID, srpSalt, srpVerifier } = await generateSRPSetupAttributes(loginSubKey); diff --git a/apps/photos/src/pages/verify/index.tsx b/apps/photos/src/pages/verify/index.tsx index 641d6629e..24278717c 100644 --- a/apps/photos/src/pages/verify/index.tsx +++ b/apps/photos/src/pages/verify/index.tsx @@ -95,18 +95,19 @@ export default function Verify() { if (keyAttributes) { setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes); setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes); - } else if (getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES)) { - await putAttributes( - token, - getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES) - ); - } - - if (getData(LS_KEYS.SRP_SETUP_ATTRIBUTES)) { - const srpSetupAttributes: SRPSetupAttributes = getData( - LS_KEYS.SRP_SETUP_ATTRIBUTES - ); - await configureSRP(srpSetupAttributes); + } else { + if (getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES)) { + await putAttributes( + token, + getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES) + ); + } + if (getData(LS_KEYS.SRP_SETUP_ATTRIBUTES)) { + const srpSetupAttributes: SRPSetupAttributes = getData( + LS_KEYS.SRP_SETUP_ATTRIBUTES + ); + await configureSRP(srpSetupAttributes); + } } clearFiles(); setIsFirstLogin(true); diff --git a/apps/photos/src/services/userService.ts b/apps/photos/src/services/userService.ts index f48bc0876..22dade14c 100644 --- a/apps/photos/src/services/userService.ts +++ b/apps/photos/src/services/userService.ts @@ -33,6 +33,7 @@ import { SRPAttributes, UpdateSRPAndKeysRequest, UpdateSRPAndKeysResponse, + GetSRPAttributesResponse, } from 'types/user'; import { ServerErrorCodes } from 'utils/error'; import isElectron from 'is-electron'; @@ -46,6 +47,7 @@ import { addLocalLog } from 'utils/logging'; import { setUserSRPSetupPending } from 'utils/storage'; import { convertBase64ToBuffer, convertBufferToBase64 } from 'utils/user'; import { setLocalMapEnabled } from 'utils/storage'; +import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker'; const ENDPOINT = getEndpoint(); @@ -486,7 +488,7 @@ export const getSRPAttributes = async (email: string) => { const resp = await HTTPService.get(`${ENDPOINT}/users/srp/attributes`, { email, }); - return resp.data as SRPAttributes; + return (resp.data as GetSRPAttributesResponse).attributes; } catch (e) { if (e.status?.toString() === ServerErrorCodes.NOT_FOUND) { return null; @@ -613,12 +615,16 @@ export const loginViaSRP = async ( passphrase: string ) => { try { - const loginSubKey = await generateLoginSubKey( + const cryptoWorker = await ComlinkCryptoWorker.getInstance(); + + const kek = await cryptoWorker.deriveKey( passphrase, srpAttributes.kekSalt, - srpAttributes.memLimit, - srpAttributes.opsLimit + srpAttributes.opsLimit, + srpAttributes.memLimit ); + + const loginSubKey = await generateLoginSubKey(kek); const srpClient = await generateSRPClient( srpAttributes.srpSalt, srpAttributes.srpUserID, @@ -640,7 +646,14 @@ export const loginViaSRP = async ( srpAttributes.srpUserID, convertBufferToBase64(m1) ); - addLocalLog(() => `srp verify successful, ${verificationResponse}`); + addLocalLog( + () => `srp verify session successful, ${verificationResponse}` + ); + + srpClient.checkM2(convertBase64ToBuffer(verificationResponse.srpM2)); + + addLocalLog(() => `srp server verify successful`); + return verificationResponse; } catch (e) { logError(e, 'srp verify failed'); @@ -651,7 +664,7 @@ export const loginViaSRP = async ( export const createSRPSession = async (srpUserID: string, srpA: string) => { try { const resp = await HTTPService.post( - `${ENDPOINT}/users/srp/exchange-ab`, + `${ENDPOINT}/users/srp/create-session`, { srpUserID, srpA, @@ -691,7 +704,7 @@ export const verifySRPSession = async ( ) => { try { const resp = await HTTPService.post( - `${ENDPOINT}/users/srp/verify`, + `${ENDPOINT}/users/srp/verify-session`, { sessionID, srpUserID, diff --git a/apps/photos/src/types/user/index.ts b/apps/photos/src/types/user/index.ts index cf6372508..2c4c38585 100644 --- a/apps/photos/src/types/user/index.ts +++ b/apps/photos/src/types/user/index.ts @@ -59,6 +59,7 @@ export interface EmailVerificationResponse { encryptedToken?: string; token?: string; twoFactorSessionID: string; + srpM2?: string; } export interface TwoFactorVerificationResponse { @@ -123,6 +124,10 @@ export interface SRPAttributes { kekSalt: string; } +export interface GetSRPAttributesResponse { + attributes: SRPAttributes; +} + export interface SRPSetupAttributes { srpSalt: string; srpVerifier: string; diff --git a/apps/photos/src/utils/crypto/index.ts b/apps/photos/src/utils/crypto/index.ts index 14b175579..62f8c07ce 100644 --- a/apps/photos/src/utils/crypto/index.ts +++ b/apps/photos/src/utils/crypto/index.ts @@ -19,9 +19,11 @@ const LOGIN_SUB_KEY_LENGTH = 32; const LOGIN_SUB_KEY_ID = 1; const LOGIN_SUB_KEY_CONTEXT = 'loginctx'; -export async function generateKeyAttributes( - passphrase: string -): Promise<{ keyAttributes: KeyAttributes; masterKey: string }> { +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(); @@ -47,6 +49,10 @@ export async function generateKeyAttributes( masterKey ); + const loginSubKey = await generateLoginSubKey(kek.key); + + const srpSetupAttributes = await generateSRPSetupAttributes(loginSubKey); + const keyAttributes: KeyAttributes = { kekSalt, encryptedKey: masterKeyEncryptedWithKek.encryptedData, @@ -64,7 +70,11 @@ export async function generateKeyAttributes( recoveryKeyDecryptionNonce: recoveryKeyEncryptedWithMasterKey.nonce, }; - return { keyAttributes, masterKey }; + return { + keyAttributes, + masterKey, + srpSetupAttributes, + }; } // We encrypt the masterKey, with an intermediate key derived from the @@ -251,19 +261,8 @@ export const isWeakPassword = (password: string) => { return estimatePasswordStrength(password) === PasswordStrength.WEAK; }; -export const generateLoginSubKey = async ( - password: string, - kekSalt: string, - memLimit: number, - opsLimit: number -) => { +export const generateLoginSubKey = async (kek: string) => { const cryptoWorker = await ComlinkCryptoWorker.getInstance(); - const kek = await cryptoWorker.deriveKey( - password, - kekSalt, - memLimit, - opsLimit - ); const loginSubKey = await cryptoWorker.generateSubKey( kek, LOGIN_SUB_KEY_LENGTH,