Skip to content

Commit

Permalink
Merge branch 'dev-E2EE-2403-encrypted-password-helper' into 'master'
Browse files Browse the repository at this point in the history
feat(E2EE-2403): Add encrypt password helper for OIDC signup

See merge request TankerHQ/sdk-js!1030
  • Loading branch information
ntalfer committed Oct 24, 2024
2 parents c4499e2 + 3d224f0 commit 88fb5c8
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 5 deletions.
2 changes: 1 addition & 1 deletion packages/client-browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ class Tanker extends TankerCore {
authenticateWithIdP = this._authenticateWithIdP;
}

export { errors, fromBase64, toBase64, prehashPassword, Padding } from '@tanker/core';
export { errors, fromBase64, toBase64, prehashPassword, prehashAndEncryptPassword, Padding } from '@tanker/core';
export { Tanker };
export default Tanker; // eslint-disable-line no-restricted-exports
28 changes: 27 additions & 1 deletion packages/core/src/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { InvalidArgument } from '@tanker/errors';
import { expect } from '@tanker/test-utils';

import { toBase64, fromBase64, prehashPassword } from '../utils';
import { toBase64, fromBase64, prehashPassword, prehashAndEncryptPassword } from '../utils';
import { tcrypto, random, generichash, utils as cryptoUtils } from '@tanker/crypto';

const notStringTypes = [undefined, null, 0, {}, [], new Uint8Array(0)];
const notUint8ArrayTypes = [undefined, null, 0, {}, [], 'wat'];
Expand All @@ -24,5 +25,30 @@ describe('utils (core)', () => {
// @ts-expect-error
await Promise.all(notStringTypes.map((v, i) => expect(prehashPassword(v), `#${i}`).to.be.rejectedWith(InvalidArgument)));
});

it('should throw when prehashAndEncryptPassword is given an invalid password type', async () => {
const keyPair = tcrypto.makeEncryptionKeyPair();
const publicKey = toBase64(keyPair.publicKey);
// @ts-expect-error
await Promise.all(notStringTypes.map((v, i) => expect(prehashAndEncryptPassword(v, publicKey), `#${i}`).to.be.rejectedWith(InvalidArgument)));
});

it('should throw when prehashAndEncryptPassword is given an invalid public key', async () => {
// public key is expected to be a base-64 encoded array of 32 bytes
const invalidPublicKeys = ["I'm a teapot", toBase64(random(19))];
await Promise.all(invalidPublicKeys.map((pk) => expect(prehashAndEncryptPassword('P@ssword1234', pk), `#${pk}`).to.be.rejectedWith(InvalidArgument)));
});
});

describe('checking prehashAndEncryptPassword behavior', () => {
it('should be able to retrieve hashed password when decrypting the result', async () => {
const password = 'P@assword1234';
const keyPair = tcrypto.makeEncryptionKeyPair();
const encrypted = await prehashAndEncryptPassword(password, toBase64(keyPair.publicKey));

const decryptedHashedPassword = tcrypto.sealDecrypt(fromBase64(encrypted), keyPair);
const hashedPassword = generichash(cryptoUtils.fromString(password));
expect(decryptedHashedPassword).to.deep.equal(hashedPassword);
});
});
});
3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import { Padding } from '@tanker/crypto';
import { Tanker, optionsWithDefaults } from './Tanker';
import { Status, statuses } from './Session/status';
import { fromBase64, toBase64, prehashPassword } from './utils';
import { fromBase64, toBase64, prehashPassword, prehashAndEncryptPassword } from './utils';

// export
export type { b64string } from '@tanker/crypto';
Expand Down Expand Up @@ -82,5 +82,6 @@ export {
statuses,
toBase64,
prehashPassword,
prehashAndEncryptPassword,
Padding,
};
13 changes: 11 additions & 2 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { b64string } from '@tanker/crypto';
import { ready as cryptoReady, utils } from '@tanker/crypto';
import { ready as cryptoReady, utils, tcrypto, generichash } from '@tanker/crypto';
import { assertString, assertNotEmptyString } from '@tanker/types';
import { InvalidArgument } from '@tanker/errors';

Expand All @@ -15,11 +15,20 @@ export function fromBase64(str: b64string): Uint8Array {
return utils.fromBase64(str);
}

// Keep this function asynchronous for compat with future asynchronous libsodium init
export async function prehashPassword(password: string): Promise<b64string> {
assertNotEmptyString(password, 'password');

await cryptoReady;

return utils.toBase64(utils.prehashPassword(utils.fromString(password)));
}

export async function prehashAndEncryptPassword(password: string, publicKey: b64string): Promise<b64string> {
assertNotEmptyString(password, 'password');
utils.assertB64StringWithSize(publicKey, 'publicKey', 32);

await cryptoReady;

const prehashedPassword = generichash(utils.fromString(password));
return toBase64(tcrypto.sealEncrypt(prehashedPassword, fromBase64(publicKey)));
}

0 comments on commit 88fb5c8

Please sign in to comment.