11type DetailedEncryptionResult = {
22 vault : string ;
33 exportedKeyString : string ;
4+ keyDerivationOptions : KeyDerivationOptions ;
45} ;
56
67type EncryptionResult = {
@@ -35,7 +36,7 @@ export async function encrypt<R>(
3536 key ?: CryptoKey ,
3637 salt : string = generateSalt ( ) ,
3738) : Promise < string > {
38- const cryptoKey = key || ( await keyFromPassword ( password , salt ) ) ;
39+ const cryptoKey = key || ( await keyFromPassword ( { password, salt } ) ) . key ;
3940 const payload = await encryptWithKey ( cryptoKey , dataObj ) ;
4041 payload . salt = salt ;
4142 return JSON . stringify ( payload ) ;
@@ -55,13 +56,17 @@ export async function encryptWithDetail<R>(
5556 dataObj : R ,
5657 salt = generateSalt ( ) ,
5758) : Promise < DetailedEncryptionResult > {
58- const key = await keyFromPassword ( password , salt ) ;
59+ const { key, keyDerivationOptions } = await keyFromPassword ( {
60+ password,
61+ salt,
62+ } ) ;
5963 const exportedKeyString = await exportKey ( key ) ;
6064 const vault = await encrypt ( password , dataObj , key , salt ) ;
6165
6266 return {
6367 vault,
6468 exportedKeyString,
69+ keyDerivationOptions,
6570 } ;
6671}
6772
@@ -117,7 +122,7 @@ export async function decrypt(
117122 const payload = JSON . parse ( text ) ;
118123 const { salt } = payload ;
119124
120- const cryptoKey = key || ( await keyFromPassword ( password , salt ) ) ;
125+ const cryptoKey = key || ( await keyFromPassword ( { password, salt } ) ) . key ;
121126
122127 const result = await decryptWithKey ( cryptoKey , payload ) ;
123128 return result ;
@@ -137,7 +142,11 @@ export async function decryptWithDetail(
137142) : Promise < DetailedDecryptResult > {
138143 const payload = JSON . parse ( text ) ;
139144 const { salt } = payload ;
140- const key = await keyFromPassword ( password , salt ) ;
145+
146+ const { key } = await keyFromPassword ( {
147+ password,
148+ salt,
149+ } ) ;
141150 const exportedKeyString = await exportKey ( key ) ;
142151 const vault = await decrypt ( password , text , key ) ;
143152
@@ -211,42 +220,96 @@ export async function exportKey(key: CryptoKey): Promise<string> {
211220 return JSON . stringify ( exportedKey ) ;
212221}
213222
223+ type AllowedImportAlgorithms = 'PBKDF2' ;
224+ type AllowedDerivationAlgorithms = {
225+ name : 'PBKDF2' ;
226+ iterations : 10000 ;
227+ hash : 'SHA-256' ;
228+ } ;
229+ type AllowedDerivedKeyAlgorithms = {
230+ name : 'AES-GCM' ;
231+ length : 256 ;
232+ } ;
233+
234+ export type KeyDerivationOptions = {
235+ /**
236+ * The algorithm used to import a key from the password
237+ * (see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey}).
238+ */
239+ importAlgorithm ?: AllowedImportAlgorithms ;
240+ /**
241+ * The algorithm used to derive an encryption/decryption key
242+ * from the imported key (see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey}).
243+ */
244+ derivationAlgorithm ?: AllowedDerivationAlgorithms ;
245+ /**
246+ * The algorithm the derived key will be used for
247+ * (see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey}).
248+ */
249+ derivedKeyAlgorithm ?: AllowedDerivedKeyAlgorithms ;
250+ } ;
251+
214252/**
215253 * Generate a CryptoKey from a password and random salt.
216254 *
217- * @param password - The password to use to generate key.
218- * @param salt - The salt string to use in key derivation.
219- * @returns A CryptoKey for encryption and decryption.
255+ * @param options - Key derivation options.
256+ * @param options.keyDerivationOptions - Key derivation options.
257+ * @param options.password - The password to use to generate key.
258+ * @param options.salt - The salt string to use in key derivation.
259+ * @returns The derived key, along with all encryption options used.
220260 */
221- export async function keyFromPassword (
222- password : string ,
223- salt : string ,
224- ) : Promise < CryptoKey > {
261+ export async function keyFromPassword ( {
262+ keyDerivationOptions = { } ,
263+ password,
264+ salt,
265+ } : {
266+ keyDerivationOptions ?: KeyDerivationOptions ;
267+ password : string ;
268+ salt : string ;
269+ } ) : Promise < {
270+ keyDerivationOptions : KeyDerivationOptions ;
271+ key : CryptoKey ;
272+ } > {
225273 const passBuffer = Buffer . from ( password , STRING_ENCODING ) ;
226274 const saltBuffer = Buffer . from ( salt , 'base64' ) ;
275+ const importAlgorithm = keyDerivationOptions . importAlgorithm || 'PBKDF2' ;
276+ const derivationAlgorithm = keyDerivationOptions . derivationAlgorithm || {
277+ name : 'PBKDF2' ,
278+ iterations : 10000 ,
279+ hash : 'SHA-256' ,
280+ } ;
281+ const derivedKeyAlgorithm = keyDerivationOptions . derivedKeyAlgorithm || {
282+ name : 'AES-GCM' ,
283+ length : 256 ,
284+ } ;
227285
228286 const key = await global . crypto . subtle . importKey (
229287 'raw' ,
230288 passBuffer ,
231- { name : 'PBKDF2' } ,
289+ importAlgorithm ,
232290 false ,
233291 [ 'deriveBits' , 'deriveKey' ] ,
234292 ) ;
235293
236294 const derivedKey = await global . crypto . subtle . deriveKey (
237295 {
238- name : 'PBKDF2' ,
296+ ... derivationAlgorithm ,
239297 salt : saltBuffer ,
240- iterations : 10000 ,
241- hash : 'SHA-256' ,
242298 } ,
243299 key ,
244- { name : DERIVED_KEY_FORMAT , length : 256 } ,
300+ derivedKeyAlgorithm ,
245301 true ,
246302 [ 'encrypt' , 'decrypt' ] ,
247303 ) ;
248304
249- return derivedKey ;
305+ return {
306+ key : derivedKey ,
307+ keyDerivationOptions : {
308+ importAlgorithm,
309+ derivationAlgorithm,
310+ derivedKeyAlgorithm,
311+ } ,
312+ } ;
250313}
251314
252315/**
0 commit comments