michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: package org.mozilla.gecko.background.nativecode.test; michael@0: michael@0: import java.io.UnsupportedEncodingException; michael@0: import java.security.GeneralSecurityException; michael@0: import java.security.MessageDigest; michael@0: import java.security.NoSuchAlgorithmException; michael@0: import java.util.Arrays; michael@0: michael@0: import junit.framework.TestCase; michael@0: michael@0: import org.mozilla.gecko.background.nativecode.NativeCrypto; michael@0: import org.mozilla.gecko.sync.Utils; michael@0: michael@0: /* michael@0: * Tests the Java wrapper over native implementations of crypto code. Test vectors from: michael@0: * * PBKDF2SHA256: michael@0: * - michael@0: * - michael@0: * * SHA-1: michael@0: * - michael@0: */ michael@0: public class TestNativeCrypto extends TestCase { michael@0: michael@0: public final void testPBKDF2SHA256A() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: String p = "password"; michael@0: String s = "salt"; michael@0: int dkLen = 32; michael@0: michael@0: checkPBKDF2SHA256(p, s, 1, dkLen, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"); michael@0: checkPBKDF2SHA256(p, s, 4096, dkLen, "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"); michael@0: } michael@0: michael@0: public final void testPBKDF2SHA256B() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: String p = "passwordPASSWORDpassword"; michael@0: String s = "saltSALTsaltSALTsaltSALTsaltSALTsalt"; michael@0: int dkLen = 40; michael@0: michael@0: checkPBKDF2SHA256(p, s, 4096, dkLen, "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"); michael@0: } michael@0: michael@0: public final void testPBKDF2SHA256scryptA() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: String p = "passwd"; michael@0: String s = "salt"; michael@0: int dkLen = 64; michael@0: michael@0: checkPBKDF2SHA256(p, s, 1, dkLen, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"); michael@0: } michael@0: michael@0: public final void testPBKDF2SHA256scryptB() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: String p = "Password"; michael@0: String s = "NaCl"; michael@0: int dkLen = 64; michael@0: michael@0: checkPBKDF2SHA256(p, s, 80000, dkLen, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d"); michael@0: } michael@0: michael@0: public final void testPBKDF2SHA256C() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: String p = "pass\0word"; michael@0: String s = "sa\0lt"; michael@0: int dkLen = 16; michael@0: michael@0: checkPBKDF2SHA256(p, s, 4096, dkLen, "89b69d0516f829893c696226650a8687"); michael@0: } michael@0: michael@0: /* michael@0: // This test takes two or three minutes to run, so we don't. michael@0: public final void testPBKDF2SHA256D() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: String p = "password"; michael@0: String s = "salt"; michael@0: int dkLen = 32; michael@0: michael@0: checkPBKDF2SHA256(p, s, 16777216, dkLen, "cf81c66fe8cfc04d1f31ecb65dab4089f7f179e89b3b0bcb17ad10e3ac6eba46"); michael@0: } michael@0: */ michael@0: michael@0: public final void testTimePBKDF2SHA256() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: checkPBKDF2SHA256("password", "salt", 80000, 32, null); michael@0: } michael@0: michael@0: public final void testPBKDF2SHA256InvalidLenArg() throws UnsupportedEncodingException, GeneralSecurityException { michael@0: final String p = "password"; michael@0: final String s = "salt"; michael@0: final int c = 1; michael@0: final int dkLen = -1; // Should always be positive. michael@0: michael@0: try { michael@0: NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen); michael@0: fail("Expected sha256 to throw with negative dkLen argument."); michael@0: } catch (IllegalArgumentException e) { } // Expected. michael@0: } michael@0: michael@0: public final void testSHA1() throws UnsupportedEncodingException { michael@0: final String[] inputs = new String[] { michael@0: "abc", michael@0: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", michael@0: "" // To be filled in below. michael@0: }; michael@0: final String baseStr = "01234567"; michael@0: final int repetitions = 80; michael@0: final StringBuilder builder = new StringBuilder(baseStr.length() * repetitions); michael@0: for (int i = 0; i < 80; ++i) { michael@0: builder.append(baseStr); michael@0: } michael@0: inputs[2] = builder.toString(); michael@0: michael@0: final String[] expecteds = new String[] { michael@0: "a9993e364706816aba3e25717850c26c9cd0d89d", michael@0: "84983e441c3bd26ebaae4aa1f95129e5e54670f1", michael@0: "dea356a2cddd90c7a7ecedc5ebb563934f460452" michael@0: }; michael@0: michael@0: for (int i = 0; i < inputs.length; ++i) { michael@0: final byte[] input = inputs[i].getBytes("US-ASCII"); michael@0: final String expected = expecteds[i]; michael@0: michael@0: final byte[] actual = NativeCrypto.sha1(input); michael@0: assertNotNull("Hashed value is non-null", actual); michael@0: assertExpectedBytes(expected, actual); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Test to ensure the output of our SHA1 algo is the same as MessageDigest's. This is important michael@0: * because we intend to replace MessageDigest in FHR with this SHA-1 algo (bug 959652). michael@0: */ michael@0: public final void testSHA1AgainstMessageDigest() throws UnsupportedEncodingException, michael@0: NoSuchAlgorithmException { michael@0: final String[] inputs = { michael@0: "password", michael@0: "saranghae", michael@0: "aoeusnthaoeusnthaoeusnth \0 12345098765432109876_!" michael@0: }; michael@0: michael@0: final MessageDigest digest = MessageDigest.getInstance("SHA-1"); michael@0: for (final String input : inputs) { michael@0: final byte[] inputBytes = input.getBytes("US-ASCII"); michael@0: michael@0: final byte[] mdBytes = digest.digest(inputBytes); michael@0: final byte[] ourBytes = NativeCrypto.sha1(inputBytes); michael@0: assertTrue("MessageDigest hash is the same as NativeCrypto SHA-1 hash", michael@0: Arrays.equals(ourBytes, mdBytes)); michael@0: } michael@0: } michael@0: michael@0: private void checkPBKDF2SHA256(String p, String s, int c, int dkLen, michael@0: final String expectedStr) michael@0: throws GeneralSecurityException, UnsupportedEncodingException { michael@0: long start = System.currentTimeMillis(); michael@0: byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen); michael@0: assertNotNull(key); michael@0: michael@0: long end = System.currentTimeMillis(); michael@0: michael@0: System.err.println("SHA-256 " + c + " took " + (end - start) + "ms"); michael@0: if (expectedStr == null) { michael@0: return; michael@0: } michael@0: michael@0: assertEquals(dkLen, Utils.hex2Byte(expectedStr).length); michael@0: assertExpectedBytes(expectedStr, key); michael@0: } michael@0: michael@0: private void assertExpectedBytes(final String expectedStr, byte[] key) { michael@0: assertEquals(expectedStr, Utils.byte2Hex(key)); michael@0: byte[] expected = Utils.hex2Byte(expectedStr); michael@0: michael@0: assertEquals(expected.length, key.length); michael@0: for (int i = 0; i < key.length; i++) { michael@0: assertEquals(expected[i], key[i]); michael@0: } michael@0: } michael@0: }