diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /services/fxaccounts/Credentials.jsm | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'services/fxaccounts/Credentials.jsm')
-rw-r--r-- | services/fxaccounts/Credentials.jsm | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/services/fxaccounts/Credentials.jsm b/services/fxaccounts/Credentials.jsm new file mode 100644 index 000000000..56e8b3db7 --- /dev/null +++ b/services/fxaccounts/Credentials.jsm @@ -0,0 +1,136 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This module implements client-side key stretching for use in Firefox + * Accounts account creation and login. + * + * See https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol + */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["Credentials"]; + +const {utils: Cu, interfaces: Ci} = Components; + +Cu.import("resource://gre/modules/Log.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); +Cu.import("resource://services-crypto/utils.js"); +Cu.import("resource://services-common/utils.js"); + +const PROTOCOL_VERSION = "identity.mozilla.com/picl/v1/"; +const PBKDF2_ROUNDS = 1000; +const STRETCHED_PW_LENGTH_BYTES = 32; +const HKDF_SALT = CommonUtils.hexToBytes("00"); +const HKDF_LENGTH = 32; +const HMAC_ALGORITHM = Ci.nsICryptoHMAC.SHA256; +const HMAC_LENGTH = 32; + +// loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO", +// "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by +// default. +const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel"; +try { + this.LOG_LEVEL = + Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING + && Services.prefs.getCharPref(PREF_LOG_LEVEL); +} catch (e) { + this.LOG_LEVEL = Log.Level.Error; +} + +var log = Log.repository.getLogger("Identity.FxAccounts"); +log.level = LOG_LEVEL; +log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); + +this.Credentials = Object.freeze({ + /** + * Make constants accessible to tests + */ + constants: { + PROTOCOL_VERSION: PROTOCOL_VERSION, + PBKDF2_ROUNDS: PBKDF2_ROUNDS, + STRETCHED_PW_LENGTH_BYTES: STRETCHED_PW_LENGTH_BYTES, + HKDF_SALT: HKDF_SALT, + HKDF_LENGTH: HKDF_LENGTH, + HMAC_ALGORITHM: HMAC_ALGORITHM, + HMAC_LENGTH: HMAC_LENGTH, + }, + + /** + * KW function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol + * + * keyWord derivation for use as a salt. + * + * + * @param {String} context String for use in generating salt + * + * @return {bitArray} the salt + * + * Note that PROTOCOL_VERSION does not refer in any way to the version of the + * Firefox Accounts API. + */ + keyWord: function(context) { + return CommonUtils.stringToBytes(PROTOCOL_VERSION + context); + }, + + /** + * KWE function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol + * + * keyWord extended with a name and an email. + * + * @param {String} name The name of the salt + * @param {String} email The email of the user. + * + * @return {bitArray} the salt combination with the namespace + * + * Note that PROTOCOL_VERSION does not refer in any way to the version of the + * Firefox Accounts API. + */ + keyWordExtended: function(name, email) { + return CommonUtils.stringToBytes(PROTOCOL_VERSION + name + ':' + email); + }, + + setup: function(emailInput, passwordInput, options={}) { + let deferred = Promise.defer(); + log.debug("setup credentials for " + emailInput); + + let hkdfSalt = options.hkdfSalt || HKDF_SALT; + let hkdfLength = options.hkdfLength || HKDF_LENGTH; + let hmacLength = options.hmacLength || HMAC_LENGTH; + let hmacAlgorithm = options.hmacAlgorithm || HMAC_ALGORITHM; + let stretchedPWLength = options.stretchedPassLength || STRETCHED_PW_LENGTH_BYTES; + let pbkdf2Rounds = options.pbkdf2Rounds || PBKDF2_ROUNDS; + + let result = {}; + + let password = CommonUtils.encodeUTF8(passwordInput); + let salt = this.keyWordExtended("quickStretch", emailInput); + + let runnable = () => { + let start = Date.now(); + let quickStretchedPW = CryptoUtils.pbkdf2Generate( + password, salt, pbkdf2Rounds, stretchedPWLength, hmacAlgorithm, hmacLength); + + result.quickStretchedPW = quickStretchedPW; + + result.authPW = + CryptoUtils.hkdf(quickStretchedPW, hkdfSalt, this.keyWord("authPW"), hkdfLength); + + result.unwrapBKey = + CryptoUtils.hkdf(quickStretchedPW, hkdfSalt, this.keyWord("unwrapBkey"), hkdfLength); + + log.debug("Credentials set up after " + (Date.now() - start) + " ms"); + deferred.resolve(result); + } + + Services.tm.currentThread.dispatch(runnable, + Ci.nsIThread.DISPATCH_NORMAL); + log.debug("Dispatched thread for credentials setup crypto work"); + + return deferred.promise; + } +}); + |