@@ -10,6 +10,11 @@ const IConfig = require('./iconfig')
1010const PASSWORD_HASHING_ROUNDS = 1000000
1111const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000 //! 5min
1212
13+ const ARGON_TIME_COST = 3
14+ const ARGON_MEMORY_COST = 65536
15+ const ARGON_PARALLELLISM = 4
16+ const ARGON_TYPE = 'argon2id'
17+
1318class SecureConfig extends IConfig {
1419
1520 /**
@@ -20,15 +25,19 @@ class SecureConfig extends IConfig {
2025 * @param {IConfig } config The underlying IConfig to use for storage
2126 * @param {number } timeoutMs Timeout since last unlock, after which the config will be locked. Defaults to 5 minutes.
2227 * @param {boolean } includeActivity When set to `true` the timeout is reset after any read/write activity. Defaults to `true`
28+ * @param {Argon2 } argon Instance of argon2 from either `npm:argon2` or `npm:argon2-browser`
2329 */
2430 constructor ( {
2531 id = 'secure-config' ,
26- config, timeoutMs= DEFAULT_TIMEOUT_MS , includeActivity= true
32+ config, timeoutMs= DEFAULT_TIMEOUT_MS , includeActivity= true ,
33+ argon
2734 } ) {
2835 super ( )
2936 this . id = id || 'secure-config'
3037 this . config = config
3138
39+ this . argon = argon
40+
3241 this . content = null
3342 this . identity = null
3443 this . timer = null
@@ -84,6 +93,16 @@ class SecureConfig extends IConfig {
8493
8594 return ( salt != undefined && salt . length > 16 && rounds > 100000 )
8695
96+ } else if ( keyType == 'argon2' ) {
97+
98+ let salt = await this . config . read ( this . id + '.settings.salt' )
99+ let timeCost = await this . config . read ( this . id + '.settings.timeCost' )
100+ let memoryCost = await this . config . read ( this . id + '.settings.memoryCost' )
101+ let parallelism = await this . config . read ( this . id + '.settings.parallelism' )
102+ let argonType = await this . config . read ( this . id + '.settings.argonType' )
103+
104+ return ( salt != undefined && salt . length > 16 && memoryCost > 1024 )
105+
87106 } else if ( keyType == 'key' ) {
88107 return true
89108 } else if ( ! keyType ) {
@@ -111,28 +130,59 @@ class SecureConfig extends IConfig {
111130 * @method module:Config.SecureConfig.setPassword
112131 * @param {string } password
113132 * @param {object } defaults
114- * @param {('pbkdf2') } type
115133 * @async
116134 */
117- async setPassword ( password , defaults = { } , type = 'pbkdf2' ) {
135+ async setPassword ( password , defaults = { } ) {
118136 debug ( 'setPassword' )
119137 if ( await this . isInitialized ( ) ) { throw new Error ( 'already initialized' ) }
120138
121139 let key = null
122140 let settings = null
123141
124- if ( type == 'pbkdf2' ) {
142+ if ( ! this . argon ) {
143+ //! pbkdf2
125144 const salt = await dataparty_crypto . Routines . generateSalt ( )
126145 const rounds = PASSWORD_HASHING_ROUNDS
127146
128147 settings = {
129- type : type ,
148+ type : 'pbkdf2' ,
130149 salt : salt . toString ( 'hex' ) ,
131150 rounds
132151 }
133152
134- key = await dataparty_crypto . Routines . createKeyFromPassword ( password , salt , rounds )
153+ key = await dataparty_crypto . Routines . createKeyFromPasswordPbkdf2 ( password , salt , rounds )
154+
155+ } else if ( this . argon ) {
156+ //! argon2
157+
158+ const salt = await dataparty_crypto . Routines . generateSalt ( )
159+ let timeCost = ARGON_TIME_COST
160+ let memoryCost = ARGON_MEMORY_COST
161+ let parallelism = ARGON_PARALLELLISM
162+ let argonType = ARGON_TYPE
163+
164+ settings = {
165+ type : 'argon2' ,
166+ salt : salt . toString ( 'hex' ) ,
167+ timeCost,
168+ memoryCost,
169+ parallelism,
170+ argonType
171+ }
172+
173+ if ( ! this . argon ) {
174+ this . argon = argon
175+ }
135176
177+ key = await dataparty_crypto . Routines . createKeyFromPasswordArgon2 (
178+ this . argon ,
179+ password ,
180+ salt ,
181+ timeCost ,
182+ memoryCost ,
183+ parallelism ,
184+ argonType
185+ )
136186 } else {
137187 throw new Error ( 'unsupported KDF[' + type + ']' )
138188 }
@@ -263,10 +313,37 @@ class SecureConfig extends IConfig {
263313 this . timer = null
264314 }
265315
266- let salt = Buffer . from ( await this . config . read ( this . id + '.settings.salt' ) , 'hex' )
267- let rounds = await this . config . read ( this . id + '.settings.rounds' )
316+ let key = null
317+ let keyType = await this . config . read ( this . id + '.settings.type' )
318+
319+ if ( keyType == 'pbkdf2' ) {
320+
321+ let salt = Buffer . from ( await this . config . read ( this . id + '.settings.salt' ) , 'hex' )
322+ let rounds = await this . config . read ( this . id + '.settings.rounds' )
323+
324+ key = await dataparty_crypto . Routines . createKeyFromPasswordPbkdf2 ( password , salt , rounds )
325+
326+ } else if ( keyType == 'argon2' ) {
327+
328+ let salt = Buffer . from ( await this . config . read ( this . id + '.settings.salt' ) , 'hex' )
329+ let timeCost = await this . config . read ( this . id + '.settings.timeCost' )
330+ let memoryCost = await this . config . read ( this . id + '.settings.memoryCost' )
331+ let parallelism = await this . config . read ( this . id + '.settings.parallelism' )
332+ let argonType = await this . config . read ( this . id + '.settings.argonType' )
333+
334+
335+ key = await dataparty_crypto . Routines . createKeyFromPasswordArgon2 (
336+ this . argon ,
337+ password ,
338+ salt ,
339+ timeCost ,
340+ memoryCost ,
341+ parallelism ,
342+ argonType
343+ )
344+
345+ }
268346
269- let key = await dataparty_crypto . Routines . createKeyFromPassword ( password , salt , rounds )
270347
271348 const pwIdentity = new dataparty_crypto . Identity ( {
272349 key,
0 commit comments