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