diff options
author | Marius David Wieschollek <passwords.public@mdns.eu> | 2024-01-04 17:25:37 +0300 |
---|---|---|
committer | Marius David Wieschollek <passwords.public@mdns.eu> | 2024-01-04 17:25:37 +0300 |
commit | 501ebf83509f88ba93aece92ed8d73b13d2c62af (patch) | |
tree | 57c0bfcc5d84e88cc2057197d66cb657c54fc8e3 | |
parent | 6e716981adeeade0a71414dbc445870614902a91 (diff) |
Fix export encryption
Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
-rw-r--r-- | src/ClassLoader/DefaultClassLoader.js | 8 | ||||
-rw-r--r-- | src/Encryption/ExportV1Encryption.js | 35 | ||||
-rw-r--r-- | src/Services/EncryptionService.js | 85 |
3 files changed, 92 insertions, 36 deletions
diff --git a/src/ClassLoader/DefaultClassLoader.js b/src/ClassLoader/DefaultClassLoader.js index 16ff9ec..a54e6f5 100644 --- a/src/ClassLoader/DefaultClassLoader.js +++ b/src/ClassLoader/DefaultClassLoader.js @@ -67,6 +67,8 @@ import Logger from "../Logger/Logger"; import DefectField from "../Model/CustomField/DefectField"; import PreconditionFailedError from "../Exception/Http/PreconditionFailedError"; import EventEmitter from "../Event/EventEmitter"; +import EncryptionService from "../Services/EncryptionService"; +import InvalidRangeError from "../Exception/Services/InvalidRangeError"; export default class DefaultClassLoader extends BasicClassLoader { @@ -120,13 +122,14 @@ export default class DefaultClassLoader extends BasicClassLoader { 'encryption.none' : () => { return new NoEncryption(this.getInstance('classes')); }, 'encryption.csev1': () => { return new CSEv1Encryption(this.getInstance('classes')); }, - 'encryption.expv1': () => { return new ExportV1Encryption(this.getInstance('classes')); }, + 'encryption.expv1': () => { return new ExportV1Encryption(this.getInstance('service.encryption')); }, 'keychain.csev1': (k, p) => { return new CSEv1Keychain(this.getInstance('classes'), k, p); }, - 'service.hash' : () => { return new HashService(this.getInstance('classes')); }, + 'service.hash' : () => { return new HashService(this.getInstance('client')); }, 'service.model' : () => { return new ModelService(this.getInstance('classes')); }, 'service.password': () => { return new PasswordService(this.getInstance('client')); }, + 'service.encryption': () => { return new EncryptionService(this.getInstance('classes')); }, 'logger': Logger, @@ -160,6 +163,7 @@ export default class DefaultClassLoader extends BasicClassLoader { 'exception.encryption.key.missing': MissingEncryptionKeyError, 'exception.encryption.text.length': InvalidEncryptedTextLength, 'exception.configuration' : ConfigurationError, + 'exception.service.range' : InvalidRangeError, // Old deprecated errors diff --git a/src/Encryption/ExportV1Encryption.js b/src/Encryption/ExportV1Encryption.js index 4cd743e..609daec 100644 --- a/src/Encryption/ExportV1Encryption.js +++ b/src/Encryption/ExportV1Encryption.js @@ -1,36 +1,33 @@ import sodium from 'libsodium-wrappers'; -import CSEv1Encryption from './CSEv1Encryption'; -export default class ExportV1Encryption extends CSEv1Encryption { +export default class ExportV1Encryption { + + /** + * @param {EncryptionService} encryptionService + */ + constructor(encryptionService) { + this._encryptionService = encryptionService; + } /** * Encrypts the message with the user defined password * - * @param message - * @param password + * @param {String} message + * @param {String} password * @returns {*} */ - encryptWithPassword(message, password) { - let salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES), - key = this._passwordToKey(password, salt), - encrypted = this._encrypt(message, key); - - return sodium.to_hex(new Uint8Array([...salt, ...encrypted])); + async encrypt(message, password) { + return await this._encryptionService.encryptAsync(message, password); } /** * Decrypts the message with the user defined password * - * @param message - * @param password + * @param {String} message + * @param {String} password * @returns {*} */ - decryptWithPassword(message, password) { - let encrypted = sodium.from_hex(message), - salt = encrypted.slice(0, sodium.crypto_pwhash_SALTBYTES), - text = encrypted.slice(sodium.crypto_pwhash_SALTBYTES), - key = this._passwordToKey(password, salt); - - return sodium.to_string(this._decrypt(text, key)); + async decrypt(message, password) { + return await this._encryptionService.decryptAsync(message, password); } }
\ No newline at end of file diff --git a/src/Services/EncryptionService.js b/src/Services/EncryptionService.js index 7f81498..af4c778 100644 --- a/src/Services/EncryptionService.js +++ b/src/Services/EncryptionService.js @@ -2,18 +2,43 @@ import sodium from 'libsodium-wrappers'; export default class EncryptionService { - constructor() { + /** + * + * @param {BasicClassLoader} classLoader + */ + constructor(classLoader) { + this._ready = classLoader.getClass('state.boolean', false); + this._classLoader = classLoader; + + sodium.ready.then(() => {this._ready.set(true);}); + } + + /** + * + * @returns {Promise<Boolean>} + */ + async ready() { + await this._ready.awaitTrue(); + return true; + } + + /** + * @returns {Boolean} + */ + enabled() { + return this._ready.get(); } /** * Encrypt the message with the given key and return a hex encoded string * * @param {String} message - * @param {String} key + * @param {String} passphrase * @returns {String} - * @private */ encrypt(message, passphrase) { + if(!this.enabled()) throw this._classLoader.getClass('exception.encryption.enabled'); + let {key, salt} = this._passwordToKey(passphrase); let encrypted = this._encrypt(message, key); @@ -21,20 +46,48 @@ export default class EncryptionService { } /** - * Decrypt the hex or base64 encoded message with the given key + * Decrypt the hex encoded message with the given key * - * @param {String} encodedString - * @param {Uint8Array} key + * @param {String} message + * @param {Uint8Array} passphrase * @returns {String} - * @private */ - _decryptString(encodedString, passphrase) { - let salt = encodedString.slice(0, sodium.crypto_pwhash_SALTBYTES), + decrypt(message, passphrase) { + if(!this.enabled()) throw this._classLoader.getClass('exception.encryption.enabled'); + + let encodedString = sodium.from_hex(message), + salt = encodedString.slice(0, sodium.crypto_pwhash_SALTBYTES), text = encodedString.slice(sodium.crypto_pwhash_SALTBYTES), - key = this._passwordToKey(passphrase, salt); + {key, } = this._passwordToKey(passphrase, salt); return sodium.to_string(this._decrypt(text, key)); } + + /** + * Encrypt the message with the given key and return a hex encoded string + * + * @param {String} message + * @param {String} passphrase + * @returns {Promise<String>} + */ + async encryptAsync(message, passphrase) { + await this.ready(); + return this.encrypt(message, passphrase); + } + + + /** + Decrypt the hex encoded message with the given key + + @param {String} message + @param {Uint8Array} passphrase + * @returns {Promise<String>} + */ + async decryptAsync(message, passphrase) { + await this.ready(); + return this.decrypt(message, passphrase); + } + /** * Encrypt the message with the given key * @@ -69,13 +122,15 @@ export default class EncryptionService { // noinspection JSMethodCanBeStatic /** * - * @param password - * @param salt - * @returns {Uint8Array} + * @param {String} password + * @param {String} salt + * @return {{salt: *, key: *}} * @private */ - _passwordToKey(password) { - let salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); + _passwordToKey(password, salt = null) { + if(salt === null) { + salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); + } let key = sodium.crypto_pwhash( sodium.crypto_box_SEEDBYTES, |