1 import bcrypt from 'bcryptjs';
3 import { CryptoProxy } from '@proton/crypto';
10 } from '@proton/crypto/lib/utils';
11 import mergeUint8Arrays from '@proton/utils/mergeUint8Arrays';
13 import { BCRYPT_PREFIX } from './constants';
14 import { cleanUsername } from './utils/username';
19 export const expandHash = async (input: Uint8Array) => {
21 const arr = mergeUint8Arrays([input, new Uint8Array([0])]);
22 for (let i = 1; i <= 4; i++) {
23 promises.push(CryptoProxy.computeHash({ algorithm: 'SHA512', data: arr }));
24 arr[arr.length - 1] = i;
26 return mergeUint8Arrays(await Promise.all(promises));
32 const formatHash = async (password: string, salt: string, modulus: Uint8Array) => {
33 const unexpandedHash = await bcrypt.hash(password, BCRYPT_PREFIX + salt);
34 return expandHash(mergeUint8Arrays([binaryStringToArray(unexpandedHash), modulus]));
38 * Hash password in version 3.
40 const hashPassword3 = (password: string, salt: string, modulus: Uint8Array) => {
41 const saltBinary = binaryStringToArray(`${salt}proton`);
42 return formatHash(password, bcrypt.encodeBase64(saltBinary, 16), modulus);
46 * Hash password in version 1.
48 const hashPassword1 = async (password: string, username: string, modulus: Uint8Array) => {
49 const value = binaryStringToArray(encodeUtf8(username.toLowerCase()));
50 const salt = arrayToHexString(await CryptoProxy.computeHash({ algorithm: 'unsafeMD5', data: value }));
51 return formatHash(password, salt, modulus);
55 * Hash password in version 0.
57 const hashPassword0 = async (password: string, username: string, modulus: Uint8Array) => {
58 const value = await CryptoProxy.computeHash({
60 data: binaryStringToArray(username.toLowerCase() + encodeUtf8(password)),
62 const prehashed = encodeBase64(arrayToBinaryString(value));
63 return hashPassword1(prehashed, username, modulus);
69 export const hashPassword = ({
82 if (version === 4 || version === 3) {
84 throw new Error('Missing salt');
86 return hashPassword3(password, salt, modulus);
90 return hashPassword1(password, cleanUsername(username), modulus);
95 throw new Error('Missing username');
97 return hashPassword1(password, username, modulus);
102 throw new Error('Missing username');
104 return hashPassword0(password, username, modulus);
107 throw new Error('Unsupported auth version');