From ab46c0d08b824d0600926c21de3b541d71f596e2 Mon Sep 17 00:00:00 2001 From: antelle Date: Tue, 31 Jan 2017 23:18:58 +0100 Subject: [PATCH] argon2 kdf settings editor --- app/scripts/locales/base.json | 4 + app/scripts/models/file-model.js | 75 ++++++++++++++----- .../views/settings/settings-file-view.js | 21 +++++- app/styles/areas/_settings.scss | 20 +++++ app/styles/base/_forms.scss | 8 +- app/templates/settings/settings-file.hbs | 21 ++++++ bower.json | 2 +- 7 files changed, 129 insertions(+), 22 deletions(-) diff --git a/app/scripts/locales/base.json b/app/scripts/locales/base.json index e4644505..36dd3b72 100644 --- a/app/scripts/locales/base.json +++ b/app/scripts/locales/base.json @@ -397,6 +397,10 @@ "setFileBackupMonthly": "Monthly", "setFileBackupManually": "Manually, no auto-backups", "setFileRounds": "Key encryption rounds", + "setFileKdfParams": "Key derivation function", + "setFileKdfParamsIter": "Iterations", + "setFileKdfParamsMem": "Memory, KB", + "setFileKdfParamsPar": "Parallelism", "setFileKeyChangeForce": "Ask to change key after (days)", "setFileUseKeyFile": "Use key file", "setFileUseGenKeyFile": "Use generated key file", diff --git a/app/scripts/models/file-model.js b/app/scripts/models/file-model.js index 02b7cef3..e8a4bd22 100644 --- a/app/scripts/models/file-model.js +++ b/app/scripts/models/file-model.js @@ -59,23 +59,8 @@ const FileModel = Backbone.Model.extend({ if (keyFileData) { kdbxweb.ByteUtils.zeroBuffer(keyFileData); } - let kdfParams = ''; - if (db.header.kdfParameters) { - kdfParams = db.header.kdfParameters.keys().map(key => { - let val = db.header.kdfParameters.get(key); - if (val instanceof ArrayBuffer) { - return; - } - if (val.value) { - val = val.value; - } - return key + '=' + val; - }).filter(p => p).join('&'); - } else if (db.header.keyEncryptionRounds) { - kdfParams = db.header.keyEncryptionRounds + ' rounds'; - } logger.info('Opened file ' + this.get('name') + ': ' + logger.ts(ts) + ', ' + - kdfParams + ', ' + Math.round(fileData.byteLength / 1024) + ' kB'); + this.kdfArgsToString(db.header) + ', ' + Math.round(fileData.byteLength / 1024) + ' kB'); callback(); }) .catch(err => { @@ -92,6 +77,22 @@ const FileModel = Backbone.Model.extend({ } }, + kdfArgsToString: function(header) { + if (header.kdfParameters) { + return header.kdfParameters.keys().map(key => { + const val = header.kdfParameters.get(key); + if (val instanceof ArrayBuffer) { + return; + } + return key + '=' + val; + }).filter(p => p).join('&'); + } else if (header.keyEncryptionRounds) { + return header.keyEncryptionRounds + ' rounds'; + } else { + return '?'; + } + }, + create: function(name) { const password = kdbxweb.ProtectedValue.fromString(''); const credentials = new kdbxweb.Credentials(password); @@ -162,7 +163,8 @@ const FileModel = Backbone.Model.extend({ historyMaxItems: this.db.meta.historyMaxItems, historyMaxSize: this.db.meta.historyMaxSize, keyEncryptionRounds: this.db.header.keyEncryptionRounds, - keyChangeForce: this.db.meta.keyChangeForce + keyChangeForce: this.db.meta.keyChangeForce, + kdfParameters: this.readKdfParams() }, { silent: true }); this.db.groups.forEach(function(group) { let groupModel = this.getGroup(this.subId(group.uuid.id)); @@ -177,6 +179,26 @@ const FileModel = Backbone.Model.extend({ this.resolveFieldReferences(); }, + readKdfParams: function() { + const kdfParameters = this.db.header.kdfParameters; + if (!kdfParameters) { + return undefined; + } + let uuid = kdfParameters.get('$UUID'); + if (!uuid) { + return undefined; + } + uuid = kdbxweb.ByteUtils.bytesToBase64(uuid); + if (uuid !== kdbxweb.Consts.KdfId.Argon2) { + return undefined; + } + return { + parallelism: kdfParameters.get('P').valueOf(), + iterations: kdfParameters.get('I').valueOf(), + memory: kdfParameters.get('M').valueOf() + }; + }, + subId: function(id) { return this.id + ':' + id; }, @@ -496,6 +518,25 @@ const FileModel = Backbone.Model.extend({ this.setModified(); }, + setKdfParameter: function(field, value) { + const ValueType = kdbxweb.VarDictionary.ValueType; + switch (field) { + case 'memory': + this.db.header.kdfParameters.set('M', ValueType.UInt64, kdbxweb.Int64.from(value)); + break; + case 'iterations': + this.db.header.kdfParameters.set('I', ValueType.UInt64, kdbxweb.Int64.from(value)); + break; + case 'parallelism': + this.db.header.kdfParameters.set('P', ValueType.UInt32, value); + break; + default: + return; + } + this.set('kdfParameters', this.readKdfParams()); + this.setModified(); + }, + emptyTrash: function() { const trashGroup = this.getTrashGroup(); if (trashGroup) { diff --git a/app/scripts/views/settings/settings-file-view.js b/app/scripts/views/settings/settings-file-view.js index 4c0b0781..44d102e8 100644 --- a/app/scripts/views/settings/settings-file-view.js +++ b/app/scripts/views/settings/settings-file-view.js @@ -43,7 +43,8 @@ const SettingsFileView = Backbone.View.extend({ 'input #settings__file-hist-len': 'changeHistoryLength', 'input #settings__file-hist-size': 'changeHistorySize', 'input #settings__file-key-rounds': 'changeKeyRounds', - 'input #settings__file-key-change-force': 'changeKeyChangeForce' + 'input #settings__file-key-change-force': 'changeKeyChangeForce', + 'input .settings__input-kdf': 'changeKdfParameter' }, appModel: null, @@ -86,6 +87,7 @@ const SettingsFileView = Backbone.View.extend({ historyMaxSize: Math.round(this.model.get('historyMaxSize') / 1024 / 1024), keyEncryptionRounds: this.model.get('keyEncryptionRounds'), keyChangeForce: this.model.get('keyChangeForce') > 0 ? this.model.get('keyChangeForce') : null, + kdfParameters: this.kdfParametersToUi(this.model.get('kdfParameters')), storageProviders: storageProviders }); if (!this.model.get('created')) { @@ -94,6 +96,10 @@ const SettingsFileView = Backbone.View.extend({ this.renderKeyFileSelect(); }, + kdfParametersToUi: function(kdfParameters) { + return kdfParameters ? _.extend({}, kdfParameters, { memory: Math.round(kdfParameters.memory / 1024) }) : null; + }, + renderKeyFileSelect: function() { const keyFileName = this.model.get('keyFileName'); const oldKeyFileName = this.model.get('oldKeyFileName'); @@ -494,6 +500,19 @@ const SettingsFileView = Backbone.View.extend({ value = -1; } this.model.setKeyChange(true, value); + }, + + changeKdfParameter: function(e) { + const field = $(e.target).data('field'); + const mul = $(e.target).data('mul') || 1; + const value = e.target.value * mul; + if (isNaN(value)) { + e.target.value = Math.round(this.model.get('kdfParameters')[field] / mul); + return; + } + if (value > 0) { + this.model.setKdfParameter(field, value); + } } }); diff --git a/app/styles/areas/_settings.scss b/app/styles/areas/_settings.scss index 093ffe13..0a20c395 100644 --- a/app/styles/areas/_settings.scss +++ b/app/styles/areas/_settings.scss @@ -62,6 +62,26 @@ height: 2em; } + &__row { + display: flex; + justify-content: space-between; + @extend .input-size-base; + } + + &__col-small { + width: 30%; + position: relative; + >.settings__input { + width: 100%; + } + } + + &__col-small-label { + text-overflow: ellipsis; + overflow: hidden; + width: 100%; + } + &__pre { @include user-select(text); white-space: pre-wrap; diff --git a/app/styles/base/_forms.scss b/app/styles/base/_forms.scss index 6b8e9d87..42b69010 100644 --- a/app/styles/base/_forms.scss +++ b/app/styles/base/_forms.scss @@ -250,11 +250,13 @@ input[type=range] { } } - - -.input-base { +.input-size-base { width: 60%; @include tablet { width: calc(100% - 20px); } } + +.input-base { + @extend .input-size-base; +} diff --git a/app/templates/settings/settings-file.hbs b/app/templates/settings/settings-file.hbs index e356bcea..d77814f1 100644 --- a/app/templates/settings/settings-file.hbs +++ b/app/templates/settings/settings-file.hbs @@ -101,8 +101,29 @@

{{res 'advanced'}}

+ {{#if keyEncryptionRounds}} + {{else if kdfParameters}} + +
+
+ + +
+
+ + +
+
+ + +
+
+ {{/if}} diff --git a/bower.json b/bower.json index 753b0614..7cde104b 100644 --- a/bower.json +++ b/bower.json @@ -27,7 +27,7 @@ "bourbon": "4.2.7", "dropbox": "keeweb/dropbox-js#0ac0efdc2711eece73f6ac044459e1fd0d5e9390", "font-awesome": "4.6.3", - "kdbxweb": "c44761da37d41c799ece04799e3c164cfa79804c", + "kdbxweb": "a4d58631f2c98667e0de2f46915db2dd79bddd07", "normalize.css": "4.2.0", "pikaday": "1.4.0", "FileSaver.js": "eligrey/FileSaver.js",