Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | Cu.import("resource://gre/modules/Credentials.jsm"); |
michael@0 | 5 | Cu.import("resource://gre/modules/Promise.jsm"); |
michael@0 | 6 | Cu.import("resource://services-common/utils.js"); |
michael@0 | 7 | Cu.import("resource://services-crypto/utils.js"); |
michael@0 | 8 | |
michael@0 | 9 | let {hexToBytes: h2b, |
michael@0 | 10 | hexAsString: h2s, |
michael@0 | 11 | stringAsHex: s2h, |
michael@0 | 12 | bytesAsHex: b2h} = CommonUtils; |
michael@0 | 13 | |
michael@0 | 14 | // Test vectors for the "onepw" protocol: |
michael@0 | 15 | // https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#wiki-test-vectors |
michael@0 | 16 | let vectors = { |
michael@0 | 17 | "client stretch-KDF": { |
michael@0 | 18 | email: |
michael@0 | 19 | h("616e6472c3a94065 78616d706c652e6f 7267"), |
michael@0 | 20 | password: |
michael@0 | 21 | h("70c3a4737377c3b6 7264"), |
michael@0 | 22 | quickStretchedPW: |
michael@0 | 23 | h("e4e8889bd8bd61ad 6de6b95c059d56e7 b50dacdaf62bd846 44af7e2add84345d"), |
michael@0 | 24 | authPW: |
michael@0 | 25 | h("247b675ffb4c4631 0bc87e26d712153a be5e1c90ef00a478 4594f97ef54f2375"), |
michael@0 | 26 | authSalt: |
michael@0 | 27 | h("00f0000000000000 0000000000000000 0000000000000000 0000000000000000"), |
michael@0 | 28 | }, |
michael@0 | 29 | }; |
michael@0 | 30 | |
michael@0 | 31 | // A simple test suite with no utf8 encoding madness. |
michael@0 | 32 | add_task(function test_onepw_setup_credentials() { |
michael@0 | 33 | let email = "francine@example.org"; |
michael@0 | 34 | let password = CommonUtils.encodeUTF8("i like pie"); |
michael@0 | 35 | |
michael@0 | 36 | let pbkdf2 = CryptoUtils.pbkdf2Generate; |
michael@0 | 37 | let hkdf = CryptoUtils.hkdf; |
michael@0 | 38 | |
michael@0 | 39 | // quickStretch the email |
michael@0 | 40 | let saltyEmail = Credentials.keyWordExtended("quickStretch", email); |
michael@0 | 41 | |
michael@0 | 42 | do_check_eq(b2h(saltyEmail), "6964656e746974792e6d6f7a696c6c612e636f6d2f7069636c2f76312f717569636b537472657463683a6672616e63696e65406578616d706c652e6f7267"); |
michael@0 | 43 | |
michael@0 | 44 | let pbkdf2Rounds = 1000; |
michael@0 | 45 | let pbkdf2Len = 32; |
michael@0 | 46 | |
michael@0 | 47 | let quickStretchedPW = pbkdf2(password, saltyEmail, pbkdf2Rounds, pbkdf2Len, Ci.nsICryptoHMAC.SHA256, 32); |
michael@0 | 48 | let quickStretchedActual = "6b88094c1c73bbf133223f300d101ed70837af48d9d2c1b6e7d38804b20cdde4"; |
michael@0 | 49 | do_check_eq(b2h(quickStretchedPW), quickStretchedActual); |
michael@0 | 50 | |
michael@0 | 51 | // obtain hkdf info |
michael@0 | 52 | let authKeyInfo = Credentials.keyWord('authPW'); |
michael@0 | 53 | do_check_eq(b2h(authKeyInfo), "6964656e746974792e6d6f7a696c6c612e636f6d2f7069636c2f76312f617574685057"); |
michael@0 | 54 | |
michael@0 | 55 | // derive auth password |
michael@0 | 56 | let hkdfSalt = h2b("00"); |
michael@0 | 57 | let hkdfLen = 32; |
michael@0 | 58 | let authPW = hkdf(quickStretchedPW, hkdfSalt, authKeyInfo, hkdfLen); |
michael@0 | 59 | |
michael@0 | 60 | do_check_eq(b2h(authPW), "4b8dec7f48e7852658163601ff766124c312f9392af6c3d4e1a247eb439be342"); |
michael@0 | 61 | |
michael@0 | 62 | // derive unwrap key |
michael@0 | 63 | let unwrapKeyInfo = Credentials.keyWord('unwrapBkey'); |
michael@0 | 64 | let unwrapKey = hkdf(quickStretchedPW, hkdfSalt, unwrapKeyInfo, hkdfLen); |
michael@0 | 65 | |
michael@0 | 66 | do_check_eq(b2h(unwrapKey), "8ff58975be391338e4ec5d7138b5ed7b65c7d1bfd1f3a4f93e05aa47d5b72be9"); |
michael@0 | 67 | }); |
michael@0 | 68 | |
michael@0 | 69 | add_task(function test_client_stretch_kdf() { |
michael@0 | 70 | let pbkdf2 = CryptoUtils.pbkdf2Generate; |
michael@0 | 71 | let hkdf = CryptoUtils.hkdf; |
michael@0 | 72 | let expected = vectors["client stretch-KDF"]; |
michael@0 | 73 | |
michael@0 | 74 | let emailUTF8 = h2s(expected.email); |
michael@0 | 75 | let passwordUTF8 = h2s(expected.password); |
michael@0 | 76 | |
michael@0 | 77 | // Intermediate value from sjcl implementation in fxa-js-client |
michael@0 | 78 | // The key thing is the c3a9 sequence in "andré" |
michael@0 | 79 | let salt = Credentials.keyWordExtended("quickStretch", emailUTF8); |
michael@0 | 80 | do_check_eq(b2h(salt), "6964656e746974792e6d6f7a696c6c612e636f6d2f7069636c2f76312f717569636b537472657463683a616e6472c3a9406578616d706c652e6f7267"); |
michael@0 | 81 | |
michael@0 | 82 | let options = { |
michael@0 | 83 | stretchedPassLength: 32, |
michael@0 | 84 | pbkdf2Rounds: 1000, |
michael@0 | 85 | hmacAlgorithm: Ci.nsICryptoHMAC.SHA256, |
michael@0 | 86 | hmacLength: 32, |
michael@0 | 87 | hkdfSalt: h2b("00"), |
michael@0 | 88 | hkdfLength: 32, |
michael@0 | 89 | }; |
michael@0 | 90 | |
michael@0 | 91 | let results = yield Credentials.setup(emailUTF8, passwordUTF8, options); |
michael@0 | 92 | |
michael@0 | 93 | do_check_eq(emailUTF8, results.emailUTF8, |
michael@0 | 94 | "emailUTF8 is wrong"); |
michael@0 | 95 | |
michael@0 | 96 | do_check_eq(passwordUTF8, results.passwordUTF8, |
michael@0 | 97 | "passwordUTF8 is wrong"); |
michael@0 | 98 | |
michael@0 | 99 | do_check_eq(expected.quickStretchedPW, b2h(results.quickStretchedPW), |
michael@0 | 100 | "quickStretchedPW is wrong"); |
michael@0 | 101 | |
michael@0 | 102 | do_check_eq(expected.authPW, b2h(results.authPW), |
michael@0 | 103 | "authPW is wrong"); |
michael@0 | 104 | }); |
michael@0 | 105 | |
michael@0 | 106 | // End of tests |
michael@0 | 107 | // Utility functions follow |
michael@0 | 108 | |
michael@0 | 109 | function run_test() { |
michael@0 | 110 | run_next_test(); |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | // turn formatted test vectors into normal hex strings |
michael@0 | 114 | function h(hexStr) { |
michael@0 | 115 | return hexStr.replace(/\s+/g, ""); |
michael@0 | 116 | } |