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 });