mobile/android/base/tests/testNativeCrypto.java

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:d5c1a1242087
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 package org.mozilla.gecko.tests;
6
7 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertArrayEquals;
8 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
9 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
10 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
11
12 import java.io.UnsupportedEncodingException;
13 import java.security.GeneralSecurityException;
14 import java.security.MessageDigest;
15 import java.security.NoSuchAlgorithmException;
16
17 import org.mozilla.gecko.background.nativecode.NativeCrypto;
18 import org.mozilla.gecko.sync.Utils;
19 import org.mozilla.gecko.tests.helpers.GeckoHelper;
20
21 import android.os.SystemClock;
22
23 /**
24 * Tests the Java wrapper over native implementations of crypto code. Test vectors from:
25 * * PBKDF2SHA256:
26 * - <https://github.com/ircmaxell/PHP-PasswordLib/blob/master/test/Data/Vectors/pbkdf2-draft-josefsson-sha256.test-vectors>
27 - <https://gitorious.org/scrypt/nettle-scrypt/blobs/37c0d5288e991604fe33dba2f1724986a8dddf56/testsuite/pbkdf2-test.c>
28 * SHA-1:
29 - <http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c>
30 */
31 public class testNativeCrypto extends UITest {
32 private final static String LOGTAG = "testNativeCrypto";
33
34 /**
35 * Robocop supports only a single test function per test class. Therefore, we
36 * have a single top-level test function that dispatches to sub-tests,
37 * accepting that we might fail part way through the cycle. Proper JUnit 3
38 * testing can't land soon enough!
39 *
40 * @throws Exception
41 */
42 public void test() throws Exception {
43 // This test could complete very quickly. If it completes too soon, the
44 // minidumps directory may not be created before the process is
45 // taken down, causing bug 722166. But we can't run the test and then block
46 // for Gecko:Ready, since it may have arrived before we block. So we wait.
47 // Again, JUnit 3 can't land soon enough!
48 GeckoHelper.blockForReady();
49
50 _testPBKDF2SHA256A();
51 _testPBKDF2SHA256B();
52 _testPBKDF2SHA256C();
53 _testPBKDF2SHA256scryptA();
54 _testPBKDF2SHA256scryptB();
55 _testPBKDF2SHA256InvalidLenArg();
56
57 _testSHA1();
58 _testSHA1AgainstMessageDigest();
59 }
60
61 public void _testPBKDF2SHA256A() throws UnsupportedEncodingException, GeneralSecurityException {
62 final String p = "password";
63 final String s = "salt";
64 final int dkLen = 32;
65
66 checkPBKDF2SHA256(p, s, 1, dkLen, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b");
67 checkPBKDF2SHA256(p, s, 4096, dkLen, "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a");
68 }
69
70 public void _testPBKDF2SHA256B() throws UnsupportedEncodingException, GeneralSecurityException {
71 final String p = "passwordPASSWORDpassword";
72 final String s = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
73 final int dkLen = 40;
74
75 checkPBKDF2SHA256(p, s, 4096, dkLen, "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9");
76 }
77
78 public void _testPBKDF2SHA256scryptA() throws UnsupportedEncodingException, GeneralSecurityException {
79 final String p = "passwd";
80 final String s = "salt";
81 final int dkLen = 64;
82
83 checkPBKDF2SHA256(p, s, 1, dkLen, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783");
84 }
85
86 public void _testPBKDF2SHA256scryptB() throws UnsupportedEncodingException, GeneralSecurityException {
87 final String p = "Password";
88 final String s = "NaCl";
89 final int dkLen = 64;
90
91 checkPBKDF2SHA256(p, s, 80000, dkLen, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d");
92 }
93
94 public void _testPBKDF2SHA256C() throws UnsupportedEncodingException, GeneralSecurityException {
95 final String p = "pass\0word";
96 final String s = "sa\0lt";
97 final int dkLen = 16;
98
99 checkPBKDF2SHA256(p, s, 4096, dkLen, "89b69d0516f829893c696226650a8687");
100 }
101
102 public void _testPBKDF2SHA256InvalidLenArg() throws UnsupportedEncodingException, GeneralSecurityException {
103 final String p = "password";
104 final String s = "salt";
105 final int c = 1;
106 final int dkLen = -1; // Should always be positive.
107
108 try {
109 final byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
110 fFail("Expected sha256 to throw with negative dkLen argument.");
111 } catch (IllegalArgumentException e) { } // Expected.
112 }
113
114 private void _testSHA1() throws UnsupportedEncodingException {
115 final String[] inputs = new String[] {
116 "abc",
117 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
118 "" // To be filled in below.
119 };
120 final String baseStr = "01234567";
121 final int repetitions = 80;
122 final StringBuilder builder = new StringBuilder(baseStr.length() * repetitions);
123 for (int i = 0; i < 80; ++i) {
124 builder.append(baseStr);
125 }
126 inputs[2] = builder.toString();
127
128 final String[] expecteds = new String[] {
129 "a9993e364706816aba3e25717850c26c9cd0d89d",
130 "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
131 "dea356a2cddd90c7a7ecedc5ebb563934f460452"
132 };
133
134 for (int i = 0; i < inputs.length; ++i) {
135 final byte[] input = inputs[i].getBytes("US-ASCII");
136 final String expected = expecteds[i];
137
138 final byte[] actual = NativeCrypto.sha1(input);
139 fAssertNotNull("Hashed value is non-null", actual);
140 assertExpectedBytes(expected, actual);
141 }
142 }
143
144 /**
145 * Test to ensure the output of our SHA1 algo is the same as MessageDigest's. This is important
146 * because we intend to replace MessageDigest in FHR with this SHA-1 algo (bug 959652).
147 */
148 private void _testSHA1AgainstMessageDigest() throws UnsupportedEncodingException,
149 NoSuchAlgorithmException {
150 final String[] inputs = {
151 "password",
152 "saranghae",
153 "aoeusnthaoeusnthaoeusnth \0 12345098765432109876_!"
154 };
155
156 final MessageDigest digest = MessageDigest.getInstance("SHA-1");
157 for (final String input : inputs) {
158 final byte[] inputBytes = input.getBytes("US-ASCII");
159
160 final byte[] mdBytes = digest.digest(inputBytes);
161 final byte[] ourBytes = NativeCrypto.sha1(inputBytes);
162 fAssertArrayEquals("MessageDigest hash is the same as NativeCrypto SHA-1 hash", mdBytes, ourBytes);
163 }
164 }
165
166 private void checkPBKDF2SHA256(String p, String s, int c, int dkLen, final String expectedStr)
167 throws GeneralSecurityException, UnsupportedEncodingException {
168 final long start = SystemClock.elapsedRealtime();
169
170 final byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
171 fAssertNotNull("Hash result is non-null", key);
172
173 final long end = SystemClock.elapsedRealtime();
174 dumpLog(LOGTAG, "SHA-256 " + c + " took " + (end - start) + "ms");
175
176 if (expectedStr == null) {
177 return;
178 }
179
180 fAssertEquals("Hash result is the appropriate length", dkLen,
181 Utils.hex2Byte(expectedStr).length);
182 assertExpectedBytes(expectedStr, key);
183 }
184
185 private void assertExpectedBytes(final String expectedStr, byte[] key) {
186 fAssertEquals("Expected string matches hash result", expectedStr, Utils.byte2Hex(key));
187 final byte[] expected = Utils.hex2Byte(expectedStr);
188
189 fAssertEquals("Expected byte array length matches key length", expected.length, key.length);
190 fAssertArrayEquals("Expected byte array matches key byte array", expected, key);
191 }
192 }

mercurial