package freenet.crypt; import junit.framework.TestCase; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import java.security.Security; import java.util.Random; import freenet.support.TestProperty; import freenet.support.TimeUtil; public class HMACTest extends TestCase { Random random; // RFC4868 2.7.2.1 SHA256 Authentication Test Vector static byte[] plaintext = "Hi There".getBytes(); static byte[] knownKey = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); static byte[] knownSHA256 = Hex.decode("198a607eb44bfbc69903a0f1cf2bbdc5ba0aa3f3d9ae3c1c7a3b1696a0b68cf7"); protected void setUp() throws Exception { super.setUp(); Security.addProvider(new BouncyCastleProvider()); random = new Random(0xAAAAAAAA); } public void testAllCipherNames() { for (HMAC hmac : HMAC.values()) { HMAC.mac(hmac, new byte[hmac.digestSize], plaintext); } } public void testSHA256SignVerify() { byte[] key = new byte[32]; random.nextBytes(key); byte[] hmac = HMAC.macWithSHA256(key, plaintext); assertNotNull(hmac); assertTrue(HMAC.verifyWithSHA256(key, plaintext, hmac)); } public void testWrongKeySize() { byte[] keyTooLong = new byte[31]; byte[] keyTooShort = new byte[29]; random.nextBytes(keyTooLong); random.nextBytes(keyTooShort); try { HMAC.macWithSHA256(keyTooLong, plaintext); fail(); } catch (IllegalArgumentException e) { // This is expected } try { HMAC.macWithSHA256(keyTooShort, plaintext); fail(); } catch (IllegalArgumentException e) { // This is expected } } public void testKnownVectors() { byte[] hmac = HMAC.macWithSHA256(knownKey, plaintext); assertEquals(Hex.toHexString(hmac), Hex.toHexString(knownSHA256)); } // ant -Dtest.skip=false -Dtest.class=freenet.crypt.HMACTest -Dtest.benchmark=true unit public void testBenchmark() { if (!TestProperty.BENCHMARK) { return; } int count = 0; System.out.println("We're getting ready to benchmark HMACs"); Random r = new Random(0xBBBBBBBB); for (int len = 8; len <= 32768; len *= 4) { byte [] plaintext = new byte[len]; r.nextBytes(plaintext); System.out.println("plaintext len "+len); int ITERATIONS = 10000000/len; long t1 = System.currentTimeMillis(); for (int i = 0; i < ITERATIONS; i++) { byte[] r1 = HMAC_legacy.macWithSHA256(knownKey, plaintext, 32); for (int j = 0; j < r1.length; j++) { count += r1[j]; } } long legacyLength = System.currentTimeMillis() - t1; t1 = System.currentTimeMillis(); for (int i = 0; i < ITERATIONS; i++) { byte[] r1 = HMAC.macWithSHA256(knownKey, plaintext); for (int j = 0; j < r1.length; j++) { count += r1[j]; } } long currentLength = System.currentTimeMillis() - t1; t1 = System.currentTimeMillis(); for (int i = 0; i < ITERATIONS; i++) { byte[] r1 = new byte[32]; HMac hmac = new HMac(new SHA256Digest()); KeyParameter kp = new KeyParameter(knownKey); hmac.init(kp); hmac.update(plaintext, 0, plaintext.length); hmac.doFinal(r1, 0); for (int j = 0; j < r1.length; j++) { count += r1[j]; } } long BCLength = System.currentTimeMillis() - t1; System.out.println("Legacy HMAC took " + TimeUtil.formatTime(legacyLength, 6, true)); System.out.println("Current HMAC took " + TimeUtil.formatTime(currentLength, 6, true)); System.out.println("BC HMAC took " + TimeUtil.formatTime(BCLength, 6, true)); } } }