services/fxaccounts/Credentials.jsm

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /**
michael@0 6 * This module implements client-side key stretching for use in Firefox
michael@0 7 * Accounts account creation and login.
michael@0 8 *
michael@0 9 * See https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
michael@0 10 */
michael@0 11
michael@0 12 "use strict";
michael@0 13
michael@0 14 this.EXPORTED_SYMBOLS = ["Credentials"];
michael@0 15
michael@0 16 const {utils: Cu, interfaces: Ci} = Components;
michael@0 17
michael@0 18 Cu.import("resource://gre/modules/Log.jsm");
michael@0 19 Cu.import("resource://gre/modules/Services.jsm");
michael@0 20 Cu.import("resource://gre/modules/Promise.jsm");
michael@0 21 Cu.import("resource://services-crypto/utils.js");
michael@0 22 Cu.import("resource://services-common/utils.js");
michael@0 23
michael@0 24 const PROTOCOL_VERSION = "identity.mozilla.com/picl/v1/";
michael@0 25 const PBKDF2_ROUNDS = 1000;
michael@0 26 const STRETCHED_PW_LENGTH_BYTES = 32;
michael@0 27 const HKDF_SALT = CommonUtils.hexToBytes("00");
michael@0 28 const HKDF_LENGTH = 32;
michael@0 29 const HMAC_ALGORITHM = Ci.nsICryptoHMAC.SHA256;
michael@0 30 const HMAC_LENGTH = 32;
michael@0 31
michael@0 32 // loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO",
michael@0 33 // "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by
michael@0 34 // default.
michael@0 35 const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel";
michael@0 36 try {
michael@0 37 this.LOG_LEVEL =
michael@0 38 Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING
michael@0 39 && Services.prefs.getCharPref(PREF_LOG_LEVEL);
michael@0 40 } catch (e) {
michael@0 41 this.LOG_LEVEL = Log.Level.Error;
michael@0 42 }
michael@0 43
michael@0 44 let log = Log.repository.getLogger("Identity.FxAccounts");
michael@0 45 log.level = LOG_LEVEL;
michael@0 46 log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
michael@0 47
michael@0 48 this.Credentials = Object.freeze({
michael@0 49 /**
michael@0 50 * Make constants accessible to tests
michael@0 51 */
michael@0 52 constants: {
michael@0 53 PROTOCOL_VERSION: PROTOCOL_VERSION,
michael@0 54 PBKDF2_ROUNDS: PBKDF2_ROUNDS,
michael@0 55 STRETCHED_PW_LENGTH_BYTES: STRETCHED_PW_LENGTH_BYTES,
michael@0 56 HKDF_SALT: HKDF_SALT,
michael@0 57 HKDF_LENGTH: HKDF_LENGTH,
michael@0 58 HMAC_ALGORITHM: HMAC_ALGORITHM,
michael@0 59 HMAC_LENGTH: HMAC_LENGTH,
michael@0 60 },
michael@0 61
michael@0 62 /**
michael@0 63 * KW function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
michael@0 64 *
michael@0 65 * keyWord derivation for use as a salt.
michael@0 66 *
michael@0 67 *
michael@0 68 * @param {String} context String for use in generating salt
michael@0 69 *
michael@0 70 * @return {bitArray} the salt
michael@0 71 *
michael@0 72 * Note that PROTOCOL_VERSION does not refer in any way to the version of the
michael@0 73 * Firefox Accounts API.
michael@0 74 */
michael@0 75 keyWord: function(context) {
michael@0 76 return CommonUtils.stringToBytes(PROTOCOL_VERSION + context);
michael@0 77 },
michael@0 78
michael@0 79 /**
michael@0 80 * KWE function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
michael@0 81 *
michael@0 82 * keyWord extended with a name and an email.
michael@0 83 *
michael@0 84 * @param {String} name The name of the salt
michael@0 85 * @param {String} email The email of the user.
michael@0 86 *
michael@0 87 * @return {bitArray} the salt combination with the namespace
michael@0 88 *
michael@0 89 * Note that PROTOCOL_VERSION does not refer in any way to the version of the
michael@0 90 * Firefox Accounts API.
michael@0 91 */
michael@0 92 keyWordExtended: function(name, email) {
michael@0 93 return CommonUtils.stringToBytes(PROTOCOL_VERSION + name + ':' + email);
michael@0 94 },
michael@0 95
michael@0 96 setup: function(emailInput, passwordInput, options={}) {
michael@0 97 let deferred = Promise.defer();
michael@0 98 log.debug("setup credentials for " + emailInput);
michael@0 99
michael@0 100 let hkdfSalt = options.hkdfSalt || HKDF_SALT;
michael@0 101 let hkdfLength = options.hkdfLength || HKDF_LENGTH;
michael@0 102 let hmacLength = options.hmacLength || HMAC_LENGTH;
michael@0 103 let hmacAlgorithm = options.hmacAlgorithm || HMAC_ALGORITHM;
michael@0 104 let stretchedPWLength = options.stretchedPassLength || STRETCHED_PW_LENGTH_BYTES;
michael@0 105 let pbkdf2Rounds = options.pbkdf2Rounds || PBKDF2_ROUNDS;
michael@0 106
michael@0 107 let result = {
michael@0 108 emailUTF8: emailInput,
michael@0 109 passwordUTF8: passwordInput,
michael@0 110 };
michael@0 111
michael@0 112 let password = CommonUtils.encodeUTF8(passwordInput);
michael@0 113 let salt = this.keyWordExtended("quickStretch", emailInput);
michael@0 114
michael@0 115 let runnable = () => {
michael@0 116 let start = Date.now();
michael@0 117 let quickStretchedPW = CryptoUtils.pbkdf2Generate(
michael@0 118 password, salt, pbkdf2Rounds, stretchedPWLength, hmacAlgorithm, hmacLength);
michael@0 119
michael@0 120 result.quickStretchedPW = quickStretchedPW;
michael@0 121
michael@0 122 result.authPW =
michael@0 123 CryptoUtils.hkdf(quickStretchedPW, hkdfSalt, this.keyWord("authPW"), hkdfLength);
michael@0 124
michael@0 125 result.unwrapBKey =
michael@0 126 CryptoUtils.hkdf(quickStretchedPW, hkdfSalt, this.keyWord("unwrapBkey"), hkdfLength);
michael@0 127
michael@0 128 log.debug("Credentials set up after " + (Date.now() - start) + " ms");
michael@0 129 deferred.resolve(result);
michael@0 130 }
michael@0 131
michael@0 132 Services.tm.currentThread.dispatch(runnable,
michael@0 133 Ci.nsIThread.DISPATCH_NORMAL);
michael@0 134 log.debug("Dispatched thread for credentials setup crypto work");
michael@0 135
michael@0 136 return deferred.promise;
michael@0 137 }
michael@0 138 });
michael@0 139

mercurial