services/fxaccounts/tests/xpcshell/test_credentials.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/fxaccounts/tests/xpcshell/test_credentials.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,116 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +Cu.import("resource://gre/modules/Credentials.jsm");
     1.8 +Cu.import("resource://gre/modules/Promise.jsm");
     1.9 +Cu.import("resource://services-common/utils.js");
    1.10 +Cu.import("resource://services-crypto/utils.js");
    1.11 +
    1.12 +let {hexToBytes: h2b,
    1.13 +     hexAsString: h2s,
    1.14 +     stringAsHex: s2h,
    1.15 +     bytesAsHex: b2h} = CommonUtils;
    1.16 +
    1.17 +// Test vectors for the "onepw" protocol:
    1.18 +// https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#wiki-test-vectors
    1.19 +let vectors = {
    1.20 +  "client stretch-KDF": {
    1.21 +    email:
    1.22 +      h("616e6472c3a94065 78616d706c652e6f 7267"),
    1.23 +    password:
    1.24 +      h("70c3a4737377c3b6 7264"),
    1.25 +    quickStretchedPW:
    1.26 +      h("e4e8889bd8bd61ad 6de6b95c059d56e7 b50dacdaf62bd846 44af7e2add84345d"),
    1.27 +    authPW:
    1.28 +      h("247b675ffb4c4631 0bc87e26d712153a be5e1c90ef00a478 4594f97ef54f2375"),
    1.29 +    authSalt:
    1.30 +      h("00f0000000000000 0000000000000000 0000000000000000 0000000000000000"),
    1.31 +  },
    1.32 +};
    1.33 +
    1.34 +// A simple test suite with no utf8 encoding madness.
    1.35 +add_task(function test_onepw_setup_credentials() {
    1.36 +  let email = "francine@example.org";
    1.37 +  let password = CommonUtils.encodeUTF8("i like pie");
    1.38 +
    1.39 +  let pbkdf2 = CryptoUtils.pbkdf2Generate;
    1.40 +  let hkdf = CryptoUtils.hkdf;
    1.41 +
    1.42 +  // quickStretch the email
    1.43 +  let saltyEmail = Credentials.keyWordExtended("quickStretch", email);
    1.44 +
    1.45 +  do_check_eq(b2h(saltyEmail), "6964656e746974792e6d6f7a696c6c612e636f6d2f7069636c2f76312f717569636b537472657463683a6672616e63696e65406578616d706c652e6f7267");
    1.46 +
    1.47 +  let pbkdf2Rounds = 1000;
    1.48 +  let pbkdf2Len = 32;
    1.49 +
    1.50 +  let quickStretchedPW = pbkdf2(password, saltyEmail, pbkdf2Rounds, pbkdf2Len, Ci.nsICryptoHMAC.SHA256, 32);
    1.51 +  let quickStretchedActual = "6b88094c1c73bbf133223f300d101ed70837af48d9d2c1b6e7d38804b20cdde4";
    1.52 +  do_check_eq(b2h(quickStretchedPW), quickStretchedActual);
    1.53 +
    1.54 +  // obtain hkdf info
    1.55 +  let authKeyInfo = Credentials.keyWord('authPW');
    1.56 +  do_check_eq(b2h(authKeyInfo), "6964656e746974792e6d6f7a696c6c612e636f6d2f7069636c2f76312f617574685057");
    1.57 +
    1.58 +  // derive auth password
    1.59 +  let hkdfSalt = h2b("00");
    1.60 +  let hkdfLen = 32;
    1.61 +  let authPW = hkdf(quickStretchedPW, hkdfSalt, authKeyInfo, hkdfLen);
    1.62 +
    1.63 +  do_check_eq(b2h(authPW), "4b8dec7f48e7852658163601ff766124c312f9392af6c3d4e1a247eb439be342");
    1.64 +
    1.65 +  // derive unwrap key
    1.66 +  let unwrapKeyInfo = Credentials.keyWord('unwrapBkey');
    1.67 +  let unwrapKey = hkdf(quickStretchedPW, hkdfSalt, unwrapKeyInfo, hkdfLen);
    1.68 +
    1.69 +  do_check_eq(b2h(unwrapKey), "8ff58975be391338e4ec5d7138b5ed7b65c7d1bfd1f3a4f93e05aa47d5b72be9");
    1.70 +});
    1.71 +
    1.72 +add_task(function test_client_stretch_kdf() {
    1.73 +  let pbkdf2 = CryptoUtils.pbkdf2Generate;
    1.74 +  let hkdf = CryptoUtils.hkdf;
    1.75 +  let expected = vectors["client stretch-KDF"];
    1.76 +
    1.77 +  let emailUTF8 = h2s(expected.email);
    1.78 +  let passwordUTF8 = h2s(expected.password);
    1.79 +
    1.80 +  // Intermediate value from sjcl implementation in fxa-js-client
    1.81 +  // The key thing is the c3a9 sequence in "andré"
    1.82 +  let salt = Credentials.keyWordExtended("quickStretch", emailUTF8);
    1.83 +  do_check_eq(b2h(salt), "6964656e746974792e6d6f7a696c6c612e636f6d2f7069636c2f76312f717569636b537472657463683a616e6472c3a9406578616d706c652e6f7267");
    1.84 +
    1.85 +  let options = {
    1.86 +    stretchedPassLength: 32,
    1.87 +    pbkdf2Rounds: 1000,
    1.88 +    hmacAlgorithm: Ci.nsICryptoHMAC.SHA256,
    1.89 +    hmacLength: 32,
    1.90 +    hkdfSalt: h2b("00"),
    1.91 +    hkdfLength: 32,
    1.92 +  };
    1.93 +
    1.94 +  let results = yield Credentials.setup(emailUTF8, passwordUTF8, options);
    1.95 +
    1.96 +  do_check_eq(emailUTF8, results.emailUTF8,
    1.97 +      "emailUTF8 is wrong");
    1.98 +
    1.99 +  do_check_eq(passwordUTF8, results.passwordUTF8,
   1.100 +      "passwordUTF8 is wrong");
   1.101 +
   1.102 +  do_check_eq(expected.quickStretchedPW, b2h(results.quickStretchedPW),
   1.103 +      "quickStretchedPW is wrong");
   1.104 +
   1.105 +  do_check_eq(expected.authPW, b2h(results.authPW),
   1.106 +      "authPW is wrong");
   1.107 +});
   1.108 +
   1.109 +// End of tests
   1.110 +// Utility functions follow
   1.111 +
   1.112 +function run_test() {
   1.113 +  run_next_test();
   1.114 +}
   1.115 +
   1.116 +// turn formatted test vectors into normal hex strings
   1.117 +function h(hexStr) {
   1.118 +  return hexStr.replace(/\s+/g, "");
   1.119 +}

mercurial