Skip to content

Commit

Permalink
add isHashed flag to createSrpSession to allow users to defer passwor…
Browse files Browse the repository at this point in the history
…d hashing to signSrpSession
  • Loading branch information
Simon McAllister committed Mar 9, 2024
1 parent 605d5ea commit 9f57fe1
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 11 deletions.
28 changes: 19 additions & 9 deletions src/cognito-srp-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,31 +101,33 @@ const createTimestamp = (): string => {
return `${weekDay} ${month} ${day} ${time} UTC ${year}`;
};

export const createSecretHash = (username: string, clientId: string, secretId: string): string => {
const hmac = CryptoJS.HmacSHA256(`${username}${clientId}`, secretId);
export const createSecretHash = (userId: string, clientId: string, secretId: string): string => {
const hmac = CryptoJS.HmacSHA256(`${userId}${clientId}`, secretId);
const secretHash = hmac.toString(CryptoJS.enc.Base64);

return secretHash;
};

export const createPasswordHash = (username: string, password: string, poolId: string): string => {
export const createPasswordHash = (userId: string, password: string, poolId: string): string => {
const poolIdAbbr = poolId.split("_")[1];
const usernamePassword = `${poolIdAbbr}${username}:${password}`;
const usernamePassword = `${poolIdAbbr}${userId}:${password}`;
const passwordHash = hash(usernamePassword);

return passwordHash;
};

export const createSrpSession = (username: string, passwordHash: string, poolId: string): SrpSession => {
export const createSrpSession = (username: string, password: string, poolId: string, isHashed = true): SrpSession => {
const poolIdAbbr = poolId.split("_")[1];
const timestamp = createTimestamp();
const smallA = generateSmallA();
const largeA = calculateLargeA(smallA);

return {
username,
poolId,
poolIdAbbr,
passwordHash,
password,
isHashed,
timestamp,
smallA: smallA.toString(16),
largeA: largeA.toString(16),
Expand All @@ -139,12 +141,20 @@ export const signSrpSession = (session: SrpSession, response: InitiateAuthRespon
if (!response.ChallengeParameters.SECRET_BLOCK) throw new MissingSecretError();
if (!response.ChallengeParameters.SRP_B) throw new MissingLargeBError();

const { SALT: salt, SECRET_BLOCK: secret, SRP_B: largeB } = response.ChallengeParameters;
const { username, poolIdAbbr, passwordHash, timestamp, smallA, largeA } = session;
const {
SALT: salt,
SECRET_BLOCK: secret,
SRP_B: largeB,
USER_ID_FOR_SRP: userIdForSrp,
} = response.ChallengeParameters;
const { poolId, poolIdAbbr, password, isHashed, timestamp, smallA, largeA } = session;

// Check server public key isn't 0
if (largeB.replace(/^0+/, "") === "") throw new AbortOnZeroBSrpError();

// Hash the password if it isn't already hashed
const passwordHash = isHashed ? password : createPasswordHash(userIdForSrp, password, poolId);

const u = calculateU(new BigInteger(largeA, 16), new BigInteger(largeB, 16));
const x = calculateX(new BigInteger(salt, 16), passwordHash);
const s = calculateS(x, new BigInteger(largeB, 16), new BigInteger(smallA, 16), u);
Expand All @@ -154,7 +164,7 @@ export const signSrpSession = (session: SrpSession, response: InitiateAuthRespon
const message = CryptoJS.lib.WordArray.create(
Buffer.concat([
Buffer.from(poolIdAbbr, "utf8"),
Buffer.from(username, "utf8"),
Buffer.from(userIdForSrp, "utf8"),
Buffer.from(secret, "base64"),
Buffer.from(timestamp, "utf8"),
]),
Expand Down
8 changes: 6 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,12 @@ export type Credentials = {
export type SrpSession = {
/** Username of the user. It is stored here for convenience when passing parameters into `computePasswordSignature` */
username: string;
/** Password hash generated using the users credentials */
passwordHash: string;
/** Password used for authentication */
password: string;
/** Flag indicating whether the password has already been hashed */
isHashed: boolean;
/** Full un-abbreviated ID of the Cognito Userpool. Here it is the full ID that's used e.g. 'eu-west-2_abc123' */
poolId: string;
/** Abbreviated ID of the Cognito Userpool. Here it is just the succeeding ID that's used e.g. 'eu-west-2_abc123' becomes 'abc123' */
poolIdAbbr: string;
/** Timestamp captured in the format requiree for Cogntio */
Expand Down

0 comments on commit 9f57fe1

Please sign in to comment.