services/fxaccounts/Credentials.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/fxaccounts/Credentials.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,139 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/**
     1.9 + * This module implements client-side key stretching for use in Firefox
    1.10 + * Accounts account creation and login.
    1.11 + *
    1.12 + * See https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
    1.13 + */
    1.14 +
    1.15 +"use strict";
    1.16 +
    1.17 +this.EXPORTED_SYMBOLS = ["Credentials"];
    1.18 +
    1.19 +const {utils: Cu, interfaces: Ci} = Components;
    1.20 +
    1.21 +Cu.import("resource://gre/modules/Log.jsm");
    1.22 +Cu.import("resource://gre/modules/Services.jsm");
    1.23 +Cu.import("resource://gre/modules/Promise.jsm");
    1.24 +Cu.import("resource://services-crypto/utils.js");
    1.25 +Cu.import("resource://services-common/utils.js");
    1.26 +
    1.27 +const PROTOCOL_VERSION = "identity.mozilla.com/picl/v1/";
    1.28 +const PBKDF2_ROUNDS = 1000;
    1.29 +const STRETCHED_PW_LENGTH_BYTES = 32;
    1.30 +const HKDF_SALT = CommonUtils.hexToBytes("00");
    1.31 +const HKDF_LENGTH = 32;
    1.32 +const HMAC_ALGORITHM = Ci.nsICryptoHMAC.SHA256;
    1.33 +const HMAC_LENGTH = 32;
    1.34 +
    1.35 +// loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO",
    1.36 +// "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by
    1.37 +// default.
    1.38 +const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel";
    1.39 +try {
    1.40 +  this.LOG_LEVEL =
    1.41 +    Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING
    1.42 +    && Services.prefs.getCharPref(PREF_LOG_LEVEL);
    1.43 +} catch (e) {
    1.44 +  this.LOG_LEVEL = Log.Level.Error;
    1.45 +}
    1.46 +
    1.47 +let log = Log.repository.getLogger("Identity.FxAccounts");
    1.48 +log.level = LOG_LEVEL;
    1.49 +log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
    1.50 +
    1.51 +this.Credentials = Object.freeze({
    1.52 +  /**
    1.53 +   * Make constants accessible to tests
    1.54 +   */
    1.55 +  constants: {
    1.56 +    PROTOCOL_VERSION: PROTOCOL_VERSION,
    1.57 +    PBKDF2_ROUNDS: PBKDF2_ROUNDS,
    1.58 +    STRETCHED_PW_LENGTH_BYTES: STRETCHED_PW_LENGTH_BYTES,
    1.59 +    HKDF_SALT: HKDF_SALT,
    1.60 +    HKDF_LENGTH: HKDF_LENGTH,
    1.61 +    HMAC_ALGORITHM: HMAC_ALGORITHM,
    1.62 +    HMAC_LENGTH: HMAC_LENGTH,
    1.63 +  },
    1.64 +
    1.65 +  /**
    1.66 +   * KW function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
    1.67 +   *
    1.68 +   * keyWord derivation for use as a salt.
    1.69 +   *
    1.70 +   *
    1.71 +   *   @param {String} context  String for use in generating salt
    1.72 +   *
    1.73 +   *   @return {bitArray} the salt
    1.74 +   *
    1.75 +   * Note that PROTOCOL_VERSION does not refer in any way to the version of the
    1.76 +   * Firefox Accounts API.
    1.77 +   */
    1.78 +  keyWord: function(context) {
    1.79 +    return CommonUtils.stringToBytes(PROTOCOL_VERSION + context);
    1.80 +  },
    1.81 +
    1.82 +  /**
    1.83 +   * KWE function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
    1.84 +   *
    1.85 +   * keyWord extended with a name and an email.
    1.86 +   *
    1.87 +   *   @param {String} name The name of the salt
    1.88 +   *   @param {String} email The email of the user.
    1.89 +   *
    1.90 +   *   @return {bitArray} the salt combination with the namespace
    1.91 +   *
    1.92 +   * Note that PROTOCOL_VERSION does not refer in any way to the version of the
    1.93 +   * Firefox Accounts API.
    1.94 +   */
    1.95 +  keyWordExtended: function(name, email) {
    1.96 +    return CommonUtils.stringToBytes(PROTOCOL_VERSION + name + ':' + email);
    1.97 +  },
    1.98 +
    1.99 +  setup: function(emailInput, passwordInput, options={}) {
   1.100 +    let deferred = Promise.defer();
   1.101 +    log.debug("setup credentials for " + emailInput);
   1.102 +
   1.103 +    let hkdfSalt = options.hkdfSalt || HKDF_SALT;
   1.104 +    let hkdfLength = options.hkdfLength || HKDF_LENGTH;
   1.105 +    let hmacLength = options.hmacLength || HMAC_LENGTH;
   1.106 +    let hmacAlgorithm = options.hmacAlgorithm || HMAC_ALGORITHM;
   1.107 +    let stretchedPWLength = options.stretchedPassLength || STRETCHED_PW_LENGTH_BYTES;
   1.108 +    let pbkdf2Rounds = options.pbkdf2Rounds || PBKDF2_ROUNDS;
   1.109 +
   1.110 +    let result = {
   1.111 +      emailUTF8: emailInput,
   1.112 +      passwordUTF8: passwordInput,
   1.113 +    };
   1.114 +
   1.115 +    let password = CommonUtils.encodeUTF8(passwordInput);
   1.116 +    let salt = this.keyWordExtended("quickStretch", emailInput);
   1.117 +
   1.118 +    let runnable = () => {
   1.119 +      let start = Date.now();
   1.120 +      let quickStretchedPW = CryptoUtils.pbkdf2Generate(
   1.121 +          password, salt, pbkdf2Rounds, stretchedPWLength, hmacAlgorithm, hmacLength);
   1.122 +
   1.123 +      result.quickStretchedPW = quickStretchedPW;
   1.124 +
   1.125 +      result.authPW =
   1.126 +        CryptoUtils.hkdf(quickStretchedPW, hkdfSalt, this.keyWord("authPW"), hkdfLength);
   1.127 +
   1.128 +      result.unwrapBKey =
   1.129 +        CryptoUtils.hkdf(quickStretchedPW, hkdfSalt, this.keyWord("unwrapBkey"), hkdfLength);
   1.130 +
   1.131 +      log.debug("Credentials set up after " + (Date.now() - start) + " ms");
   1.132 +      deferred.resolve(result);
   1.133 +    }
   1.134 +
   1.135 +    Services.tm.currentThread.dispatch(runnable,
   1.136 +        Ci.nsIThread.DISPATCH_NORMAL);
   1.137 +    log.debug("Dispatched thread for credentials setup crypto work");
   1.138 +
   1.139 +    return deferred.promise;
   1.140 +  }
   1.141 +});
   1.142 +

mercurial