diff options
Diffstat (limited to 'keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java')
-rw-r--r-- | keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java | 332 |
1 files changed, 0 insertions, 332 deletions
diff --git a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java b/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java deleted file mode 100644 index eeb48ec..0000000 --- a/keystore-cts/java/com/google/security/wycheproof/testcases/JsonMacTest.java +++ /dev/null @@ -1,332 +0,0 @@ -/** - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * <p>http://www.apache.org/licenses/LICENSE-2.0 - * - * <p>Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.security.wycheproof; - -import static org.junit.Assert.assertEquals; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Locale; -import javax.crypto.Mac; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** This test uses test vectors in JSON format to test MAC primitives. */ -@RunWith(JUnit4.class) -public class JsonMacTest { - - /** Convenience method to get a byte array from an JsonObject */ - protected static byte[] getBytes(JsonObject obj, String name) throws Exception { - return JsonUtil.asByteArray(obj.get(name)); - } - - protected static boolean arrayEquals(byte[] a, byte[] b) { - if (a.length != b.length) { - return false; - } - byte res = 0; - for (int i = 0; i < a.length; i++) { - res |= (byte) (a[i] ^ b[i]); - } - return res == 0; - } - - /** - * Computes a MAC. - * - * @param algorithm the algorithm. - * @param key the key bytes - * @param msg the message to MAC. - * @param tagSize the expected size of the tag in bits. - * @return the tag - * @throws GeneralSecurityException if the algorithm or the parameter sizes are not supported or - * if the initialization failed. For example one case are GMACs with a tag size othe than 128 - * bits, since the JCE interface does not seem to support such a specification. - */ - protected static byte[] computeMac(String algorithm, byte[] key, byte[] msg, int tagSize) - throws GeneralSecurityException { - Mac mac = Mac.getInstance(algorithm); - algorithm = algorithm.toUpperCase(Locale.ENGLISH); - if (algorithm.startsWith("HMAC")) { - SecretKeySpec keySpec = new SecretKeySpec(key, algorithm); - // TODO(bleichen): Is there a provider independent truncation? - // The class javax.xml.crypto.dsig.spec.HMACParameterSpec would allow to - // truncate HMAC tags as follows: - // <pre> - // HMACParameterSpec params = new HMACParameterSpec(tagSize); - // mac.init(keySpec, params); - // mac.update(msg); - // return mac.doFinal(); - // </pre> - // But this class is often not supported. Hence the computation here, just computes a - // full length tag and truncates it. The drawback of having to truncate tags is that - // the caller has to compare truncated tags during verification. - mac.init(keySpec); - mac.update(msg); - byte[] tag = mac.doFinal(); - return Arrays.copyOf(tag, tagSize / 8); - } else { - throw new NoSuchAlgorithmException(algorithm); - } - } - - /** - * Tests a randomized MAC (i.e. a message authetication that takes an additional IV as parameter) - * against test vectors. - * - * @param filename the JSON file with the test vectors. - */ - public void testMac(String filename) throws Exception { - // Checking preconditions. - JsonObject test = JsonUtil.getTestVectors(filename); - String algorithm = test.get("algorithm").getAsString(); - try { - Mac.getInstance(algorithm); - } catch (NoSuchAlgorithmException ex) { - System.out.println("Algorithm is not supported. Skipping test for " + algorithm); - return; - } - - int numTests = test.get("numberOfTests").getAsInt(); - int cntTests = 0; - int passedTests = 0; - int errors = 0; - for (JsonElement g : test.getAsJsonArray("testGroups")) { - JsonObject group = g.getAsJsonObject(); - int tagSize = group.get("tagSize").getAsInt(); - for (JsonElement t : group.getAsJsonArray("tests")) { - cntTests++; - JsonObject testcase = t.getAsJsonObject(); - int tcid = testcase.get("tcId").getAsInt(); - String tc = "tcId: " + tcid + " " + testcase.get("comment").getAsString(); - byte[] key = getBytes(testcase, "key"); - byte[] msg = getBytes(testcase, "msg"); - byte[] expectedTag = getBytes(testcase, "tag"); - // Result is one of "valid", "invalid", "acceptable". - // "valid" are test vectors with matching plaintext, ciphertext and tag. - // "invalid" are test vectors with invalid parameters or invalid ciphertext and tag. - // "acceptable" are test vectors with weak parameters or legacy formats. - String result = testcase.get("result").getAsString(); - - byte[] computedTag = null; - try { - computedTag = computeMac(algorithm, key, msg, tagSize); - } catch (GeneralSecurityException ex) { - // Some libraries restrict key size or tag size. Hence valid MACs might be - // rejected. - continue; - } catch (IllegalArgumentException ex) { - // Thrown by javax.crypto.spec.SecretKeySpec (e.g. when the key is empty). - continue; - } - - boolean eq = arrayEquals(expectedTag, computedTag); - if (result.equals("invalid")) { - if (eq) { - // Some test vectors use invalid parameters that should be rejected. - // E.g. an implementation must not allow AES-GMAC with an IV of length 0, - // since this leaks the authentication key. - System.out.println("Computed mac for test case " + tc); - errors++; - } - } else { - if (eq) { - passedTests++; - } else { - System.out.println( - "Incorrect tag for " - + tc - + " expected:" - + TestUtil.bytesToHex(expectedTag) - + " computed:" - + TestUtil.bytesToHex(computedTag)); - errors++; - } - } - } - } - System.out.println("passed Tests for " + algorithm + ":" + passedTests); - assertEquals(0, errors); - assertEquals(numTests, cntTests); - } - - /** - * Returns an initialized instance of a randomized MAC. - * - * @param algorithm the algorithm. - * @param key the key bytes - * @param iv the bytes of the initialization vector - * @param tagSize the expected size of the tag in bits. - * @return an initialized instance of a MAC. - * @throws GeneralSecurityException if the algorithm or the parameter sizes are not supported or - * if the initialization failed. For example one case are GMACs with a tag size othe than 128 - * bits, since the JCE interface does not seem to support such a specification. - */ - protected static Mac getInitializedMacWithIv(String algorithm, byte[] key, byte[] iv, int tagSize) - throws GeneralSecurityException { - Mac mac = Mac.getInstance(algorithm); - algorithm = algorithm.toUpperCase(Locale.ENGLISH); - if (algorithm.equals("AES-GMAC")) { - SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); - if (tagSize != 128) { - throw new InvalidAlgorithmParameterException("only 128-bit tag is supported"); - } - IvParameterSpec params = new IvParameterSpec(iv); - // TODO(bleichen): I'm unaware of a method that allows to specify the tag size in JCE. - // E.g. the following parameter specification does not work (at least not in BC): - // GCMParameterSpec params = new GCMParameterSpec(tagSize, iv); - mac.init(keySpec, params); - return mac; - } else { - throw new NoSuchAlgorithmException(algorithm); - } - } - - /** - * Tests a randomized MAC (i.e. a message authetication that takes an additional IV as - * parameter) against test vectors. - * - * @param filename the JSON file with the test vectors. - * @param algorithm the JCE name of the algorithm to test. - */ - public void testMacWithIv(String filename, String algorithm) throws Exception { - // Checking preconditions. - try { - Mac.getInstance(algorithm); - } catch (NoSuchAlgorithmException ex) { - System.out.println("Algorithm is not supported. Skipping test for " + algorithm); - return; - } - - JsonObject test = JsonUtil.getTestVectors(filename); - int numTests = test.get("numberOfTests").getAsInt(); - int cntTests = 0; - int passedTests = 0; - int errors = 0; - for (JsonElement g : test.getAsJsonArray("testGroups")) { - JsonObject group = g.getAsJsonObject(); - int tagSize = group.get("tagSize").getAsInt(); - for (JsonElement t : group.getAsJsonArray("tests")) { - cntTests++; - JsonObject testcase = t.getAsJsonObject(); - int tcid = testcase.get("tcId").getAsInt(); - String tc = "tcId: " + tcid + " " + testcase.get("comment").getAsString(); - byte[] key = getBytes(testcase, "key"); - byte[] iv = getBytes(testcase, "iv"); - byte[] msg = getBytes(testcase, "msg"); - byte[] expectedTag = getBytes(testcase, "tag"); - // Result is one of "valid", "invalid", "acceptable". - // "valid" are test vectors with matching plaintext, ciphertext and tag. - // "invalid" are test vectors with invalid parameters or invalid ciphertext and tag. - // "acceptable" are test vectors with weak parameters or legacy formats. - String result = testcase.get("result").getAsString(); - - Mac mac; - try { - mac = getInitializedMacWithIv(algorithm, key, iv, tagSize); - } catch (GeneralSecurityException ex) { - // Some libraries restrict key size, iv size and tag size. - // Because of the initialization of the Mac might fail. - continue; - } catch (IllegalArgumentException ex) { - // Thrown by javax.crypto.spec.SecretKeySpec (e.g. when the key is empty). - continue; - } - - byte[] computedTag = mac.doFinal(msg); - boolean eq = arrayEquals(expectedTag, computedTag); - if (result.equals("invalid")) { - if (eq) { - // Some test vectors use invalid parameters that should be rejected. - // E.g. an implementation must not allow AES-GMAC with an IV of length 0, - // since this leaks the authentication key. - System.out.println("Computed mac for test case " + tc); - errors++; - } - } else { - if (eq) { - passedTests++; - } else { - System.out.println( - "Incorrect tag for " - + tc - + " expected:" - + TestUtil.bytesToHex(expectedTag) - + " computed:" - + TestUtil.bytesToHex(computedTag)); - errors++; - } - } - } - } - System.out.println("passed Tests for " + algorithm + ":" + passedTests); - assertEquals(0, errors); - assertEquals(numTests, cntTests); - } - - @Test - public void testHmacSha1() throws Exception { - testMac("hmac_sha1_test.json"); - } - - @Test - public void testHmacSha224() throws Exception { - testMac("hmac_sha224_test.json"); - } - - @Test - public void testHmacSha256() throws Exception { - testMac("hmac_sha256_test.json"); - } - - @Test - public void testHmacSha384() throws Exception { - testMac("hmac_sha384_test.json"); - } - - @Test - public void testHmacSha512() throws Exception { - testMac("hmac_sha512_test.json"); - } - - @Test - public void testHmacSha3_224() throws Exception { - testMac("hmac_sha3_224_test.json"); - } - - @Test - public void testHmacSha3_256() throws Exception { - testMac("hmac_sha3_256_test.json"); - } - - @Test - public void testHmacSha3_384() throws Exception { - testMac("hmac_sha3_384_test.json"); - } - - @Test - public void testHmacSha3_512() throws Exception { - testMac("hmac_sha3_512_test.json"); - } - - @Test - public void testAesGmac() throws Exception { - testMacWithIv("gmac_test.json", "AES-GMAC"); - } -} |