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 +}