summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/MailCryptoUtils.jsm
blob: 6c378e67030efd830bdcd056c85a40371fa29a14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const EXPORTED_SYMBOLS = ["MailCryptoUtils"];

var MailCryptoUtils = {
  /**
   * Converts a binary string into a Uint8Array.
   *
   * @param {BinaryString} str - The string to convert.
   * @returns {Uint8Array}.
   */
  binaryStringToTypedArray(str) {
    let arr = new Uint8Array(str.length);
    for (let i = 0; i < str.length; i++) {
      arr[i] = str.charCodeAt(i);
    }
    return arr;
  },

  /**
   * The HMAC-MD5 transform works like:
   *
   * MD5(K XOR opad, MD5(K XOR ipad, m))
   *
   * where
   *  K is an n byte key
   *  ipad is the byte 0x36 repeated 64 times
   *  opad is the byte 0x5c repeated 64 times
   *  m is the message being processed

   * @param {Uint8Array} key
   * @param {Uint8Array} data
   * @returns {Uint8Array}
   */
  hmacMd5(key, data) {
    let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
      Ci.nsICryptoHash
    );
    let digest;

    // If key is longer than 64 bytes, reset it to MD5(key).
    if (key.length > 64) {
      hasher.init(Ci.nsICryptoHash.MD5);
      hasher.update(key, key.length);
      digest = hasher.finish(false);
      key = this.binaryStringToTypedArray(digest);
    }

    // Generate innerPad and outerPad.
    let innerPad = new Uint8Array(64);
    let outerPad = new Uint8Array(64);
    for (let i = 0; i < 64; i++) {
      let base = key[i] || 0;
      innerPad[i] = base ^ 0x36;
      outerPad[i] = base ^ 0x5c;
    }

    // Perform inner MD5.
    hasher.init(Ci.nsICryptoHash.MD5);
    hasher.update(innerPad, 64);
    hasher.update(data, data.length);
    digest = hasher.finish(false);

    let result = this.binaryStringToTypedArray(digest);

    // Perform outer MD5.
    hasher.init(Ci.nsICryptoHash.MD5);
    hasher.update(outerPad, 64);
    hasher.update(result, result.length);
    digest = hasher.finish(false);

    return this.binaryStringToTypedArray(digest);
  },
};