tor-browser

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

keys.sys.mjs (4198B)


      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 import { CommonUtils } from "resource://services-common/utils.sys.mjs";
      6 
      7 import { Log } from "resource://gre/modules/Log.sys.mjs";
      8 
      9 import { Weave } from "resource://services-sync/main.sys.mjs";
     10 
     11 /**
     12 * Represents a pair of keys.
     13 *
     14 * Each key stored in a key bundle is 256 bits. One key is used for symmetric
     15 * encryption. The other is used for HMAC.
     16 *
     17 * A KeyBundle by itself is just an anonymous pair of keys. Other types
     18 * deriving from this one add semantics, such as associated collections or
     19 * generating a key bundle via HKDF from another key.
     20 */
     21 function KeyBundle() {
     22  this._encrypt = null;
     23  this._encryptB64 = null;
     24  this._hmac = null;
     25  this._hmacB64 = null;
     26 }
     27 KeyBundle.prototype = {
     28  _encrypt: null,
     29  _encryptB64: null,
     30  _hmac: null,
     31  _hmacB64: null,
     32 
     33  equals: function equals(bundle) {
     34    return (
     35      bundle &&
     36      bundle.hmacKey == this.hmacKey &&
     37      bundle.encryptionKey == this.encryptionKey
     38    );
     39  },
     40 
     41  /*
     42   * Accessors for the two keys.
     43   */
     44  get encryptionKey() {
     45    return this._encrypt;
     46  },
     47 
     48  set encryptionKey(value) {
     49    if (!value || typeof value != "string") {
     50      throw new Error("Encryption key can only be set to string values.");
     51    }
     52 
     53    if (value.length < 16) {
     54      throw new Error("Encryption key must be at least 128 bits long.");
     55    }
     56 
     57    this._encrypt = value;
     58    this._encryptB64 = btoa(value);
     59  },
     60 
     61  get encryptionKeyB64() {
     62    return this._encryptB64;
     63  },
     64 
     65  get hmacKey() {
     66    return this._hmac;
     67  },
     68 
     69  set hmacKey(value) {
     70    if (!value || typeof value != "string") {
     71      throw new Error("HMAC key can only be set to string values.");
     72    }
     73 
     74    if (value.length < 16) {
     75      throw new Error("HMAC key must be at least 128 bits long.");
     76    }
     77 
     78    this._hmac = value;
     79    this._hmacB64 = btoa(value);
     80  },
     81 
     82  get hmacKeyB64() {
     83    return this._hmacB64;
     84  },
     85 
     86  /**
     87   * Populate this key pair with 2 new, randomly generated keys.
     88   */
     89  async generateRandom() {
     90    // Compute both at that same time
     91    let [generatedHMAC, generatedEncr] = await Promise.all([
     92      Weave.Crypto.generateRandomKey(),
     93      Weave.Crypto.generateRandomKey(),
     94    ]);
     95    this.keyPairB64 = [generatedEncr, generatedHMAC];
     96  },
     97 };
     98 
     99 /**
    100 * Represents a KeyBundle associated with a collection.
    101 *
    102 * This is just a KeyBundle with a collection attached.
    103 */
    104 export function BulkKeyBundle(collection) {
    105  let log = Log.repository.getLogger("Sync.BulkKeyBundle");
    106  log.info("BulkKeyBundle being created for " + collection);
    107  KeyBundle.call(this);
    108 
    109  this._collection = collection;
    110 }
    111 
    112 BulkKeyBundle.fromHexKey = function (hexKey) {
    113  let key = CommonUtils.hexToBytes(hexKey);
    114  let bundle = new BulkKeyBundle();
    115  // [encryptionKey, hmacKey]
    116  bundle.keyPair = [key.slice(0, 32), key.slice(32, 64)];
    117  return bundle;
    118 };
    119 
    120 BulkKeyBundle.fromJWK = function (jwk) {
    121  if (!jwk || !jwk.k || jwk.kty !== "oct") {
    122    throw new Error("Invalid JWK provided to BulkKeyBundle.fromJWK");
    123  }
    124  return BulkKeyBundle.fromHexKey(CommonUtils.base64urlToHex(jwk.k));
    125 };
    126 
    127 BulkKeyBundle.prototype = {
    128  get collection() {
    129    return this._collection;
    130  },
    131 
    132  /**
    133   * Obtain the key pair in this key bundle.
    134   *
    135   * The returned keys are represented as raw byte strings.
    136   */
    137  get keyPair() {
    138    return [this.encryptionKey, this.hmacKey];
    139  },
    140 
    141  set keyPair(value) {
    142    if (!Array.isArray(value) || value.length != 2) {
    143      throw new Error("BulkKeyBundle.keyPair value must be array of 2 keys.");
    144    }
    145 
    146    this.encryptionKey = value[0];
    147    this.hmacKey = value[1];
    148  },
    149 
    150  get keyPairB64() {
    151    return [this.encryptionKeyB64, this.hmacKeyB64];
    152  },
    153 
    154  set keyPairB64(value) {
    155    if (!Array.isArray(value) || value.length != 2) {
    156      throw new Error(
    157        "BulkKeyBundle.keyPairB64 value must be an array of 2 keys."
    158      );
    159    }
    160 
    161    this.encryptionKey = CommonUtils.safeAtoB(value[0]);
    162    this.hmacKey = CommonUtils.safeAtoB(value[1]);
    163  },
    164 };
    165 
    166 Object.setPrototypeOf(BulkKeyBundle.prototype, KeyBundle.prototype);