API Docs for: 1.0.8
Show:

File: client/lib/credentials.js

  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
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. define(['./request', 'sjcl', './hkdf', './pbkdf2'], function (Request, sjcl, hkdf, pbkdf2) {
  5. 'use strict';
  6.  
  7. // Key wrapping and stretching configuration.
  8. var NAMESPACE = 'identity.mozilla.com/picl/v1/';
  9. var PBKDF2_ROUNDS = 1000;
  10. var STRETCHED_PASS_LENGTH_BYTES = 32 * 8;
  11.  
  12. var HKDF_SALT = sjcl.codec.hex.toBits('00');
  13. var HKDF_LENGTH = 32;
  14.  
  15. /**
  16. * Key Wrapping with a name
  17. *
  18. * @method kw
  19. * @static
  20. * @param {String} name The name of the salt
  21. * @return {bitArray} the salt combination with the namespace
  22. */
  23. function kw(name) {
  24. return sjcl.codec.utf8String.toBits(NAMESPACE + name);
  25. }
  26.  
  27. /**
  28. * Key Wrapping with a name and an email
  29. *
  30. * @method kwe
  31. * @static
  32. * @param {String} name The name of the salt
  33. * @param {String} email The email of the user.
  34. * @return {bitArray} the salt combination with the namespace
  35. */
  36. function kwe(name, email) {
  37. return sjcl.codec.utf8String.toBits(NAMESPACE + name + ':' + email);
  38. }
  39.  
  40. /**
  41. * @class credentials
  42. * @constructor
  43. */
  44. return {
  45. /**
  46. * Setup credentials
  47. *
  48. * @method setup
  49. * @param {String} emailInput
  50. * @param {String} passwordInput
  51. * @return {Promise} A promise that will be fulfilled with `result` of generated credentials
  52. */
  53. setup: function (emailInput, passwordInput) {
  54. var result = {};
  55. var email = kwe('quickStretch', emailInput);
  56. var password = sjcl.codec.utf8String.toBits(passwordInput);
  57.  
  58. result.emailUTF8 = emailInput;
  59. result.passwordUTF8 = passwordInput;
  60.  
  61. return pbkdf2.derive(password, email, PBKDF2_ROUNDS, STRETCHED_PASS_LENGTH_BYTES)
  62. .then(
  63. function (quickStretchedPW) {
  64. result.quickStretchedPW = quickStretchedPW;
  65.  
  66. return hkdf(quickStretchedPW, kw('authPW'), HKDF_SALT, HKDF_LENGTH)
  67. .then(
  68. function (authPW) {
  69. result.authPW = authPW;
  70.  
  71. return hkdf(quickStretchedPW, kw('unwrapBkey'), HKDF_SALT, HKDF_LENGTH);
  72. }
  73. );
  74. }
  75. )
  76. .then(
  77. function (unwrapBKey) {
  78. result.unwrapBKey = unwrapBKey;
  79. return result;
  80. }
  81. );
  82. },
  83. /**
  84. * Wrap
  85. *
  86. * @method wrap
  87. * @param {bitArray} bitArray1
  88. * @param {bitArray} bitArray2
  89. * @return {bitArray} wrap result of the two bitArrays
  90. */
  91. xor: function (bitArray1, bitArray2) {
  92. var result = [];
  93.  
  94. for (var i = 0; i < bitArray1.length; i++) {
  95. result[i] = bitArray1[i] ^ bitArray2[i];
  96. }
  97.  
  98. return result;
  99. },
  100. /**
  101. * Unbundle the WrapKB
  102. * @param {String} key Bundle Key in hex
  103. * @param {String} bundle Key bundle in hex
  104. * @returns {*}
  105. */
  106. unbundleKeyFetchResponse: function (key, bundle) {
  107. var self = this;
  108. var bitBundle = sjcl.codec.hex.toBits(bundle);
  109.  
  110. return this.deriveBundleKeys(key, 'account/keys')
  111. .then(
  112. function (keys) {
  113. var ciphertext = sjcl.bitArray.bitSlice(bitBundle, 0, 8 * 64);
  114. var expectedHmac = sjcl.bitArray.bitSlice(bitBundle, 8 * -32);
  115. var hmac = new sjcl.misc.hmac(keys.hmacKey, sjcl.hash.sha256);
  116. hmac.update(ciphertext);
  117.  
  118. if (!sjcl.bitArray.equal(hmac.digest(), expectedHmac)) {
  119. throw new Error('Bad HMac');
  120. }
  121.  
  122. var keyAWrapB = self.xor(sjcl.bitArray.bitSlice(bitBundle, 0, 8 * 64), keys.xorKey);
  123.  
  124. return {
  125. kA: sjcl.codec.hex.fromBits(sjcl.bitArray.bitSlice(keyAWrapB, 0, 8 * 32)),
  126. wrapKB: sjcl.codec.hex.fromBits(sjcl.bitArray.bitSlice(keyAWrapB, 8 * 32))
  127. };
  128. }
  129. );
  130. },
  131. /**
  132. * Derive the HMAC and XOR keys required to encrypt a given size of payload.
  133. * @param {String} key Hex Bundle Key
  134. * @param {String} keyInfo Bundle Key Info
  135. * @returns {Object} hmacKey, xorKey
  136. */
  137. deriveBundleKeys: function(key, keyInfo) {
  138. var bitKeyInfo = kw(keyInfo);
  139. var salt = sjcl.codec.hex.toBits('');
  140. key = sjcl.codec.hex.toBits(key);
  141.  
  142. return hkdf(key, bitKeyInfo, salt, 3 * 32)
  143. .then(
  144. function (keyMaterial) {
  145.  
  146. return {
  147. hmacKey: sjcl.bitArray.bitSlice(keyMaterial, 0, 8 * 32),
  148. xorKey: sjcl.bitArray.bitSlice(keyMaterial, 8 * 32)
  149. };
  150. }
  151. );
  152. }
  153. };
  154.  
  155. });
  156.