tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Credentials.sys.mjs (4073B)


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