// Copyright 2017 Google Inc. // // 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 // // http://www.apache.org/licenses/LICENSE-2.0 // // 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.crypto.tink; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import com.google.crypto.tink.aead.PredefinedAeadParameters; import com.google.crypto.tink.config.TinkConfig; import com.google.crypto.tink.mac.PredefinedMacParameters; import com.google.crypto.tink.proto.Keyset; import com.google.crypto.tink.subtle.Hex; import com.google.crypto.tink.subtle.Random; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.security.GeneralSecurityException; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Tests for JsonKeysetReader. */ @RunWith(JUnit4.class) public class JsonKeysetReaderTest { private static final Charset UTF_8 = Charset.forName("UTF-8"); private static String createJsonKeysetWithId(String id) { return "{" + ("\"primaryKeyId\": " + id + ",") + "\"key\": [{" + "\"keyData\": {" + "\"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacKey\"," + "\"keyMaterialType\": \"SYMMETRIC\"," + "\"value\": \"EgQIAxAQGiBYhMkitTWFVefTIBg6kpvac+bwFOGSkENGmU+1EYgocg==\"" + "}," + "\"outputPrefixType\": \"TINK\"," + ("\"keyId\": " + id + ",") + "\"status\": \"ENABLED\"" + "}]}"; } private static final String JSON_KEYSET = createJsonKeysetWithId("547623039"); private static final String URL_SAFE_JSON_KEYSET = "{" + "\"primaryKeyId\": 547623039," + "\"key\": [{" + "\"keyData\": {" + "\"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacKey\"," + "\"keyMaterialType\": \"SYMMETRIC\"," + "\"value\": \"EgQIAxAQGiBYhMkitTWFVefTIBg6kpvac-bwFOGSkENGmU-1EYgocg\"" + "}," + "\"outputPrefixType\": \"TINK\"," + "\"keyId\": 547623039," + "\"status\": \"ENABLED\"" + "}]}"; @BeforeClass public static void setUp() throws GeneralSecurityException { TinkConfig.register(); } private void assertKeysetHandle(KeysetHandle handle1, KeysetHandle handle2) throws Exception { Mac mac1 = handle1.getPrimitive(RegistryConfiguration.get(), Mac.class); Mac mac2 = handle2.getPrimitive(RegistryConfiguration.get(), Mac.class); byte[] message = Random.randBytes(20); assertThat(handle2.getKeyset()).isEqualTo(handle1.getKeyset()); mac2.verifyMac(mac1.computeMac(message), message); } @Test public void testRead_singleKey_shouldWork() throws Exception { KeysetHandle handle1 = KeysetHandle.generateNew(PredefinedMacParameters.HMAC_SHA256_128BITTAG); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CleartextKeysetHandle.write(handle1, JsonKeysetWriter.withOutputStream(outputStream)); KeysetHandle handle2 = CleartextKeysetHandle.read( JsonKeysetReader.withInputStream(new ByteArrayInputStream(outputStream.toByteArray()))); assertKeysetHandle(handle1, handle2); } @Test public void testRead_multipleKeys_shouldWork() throws Exception { KeysetHandle handle1 = KeysetHandle.newBuilder() .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_128BITTAG") .withRandomId() .makePrimary()) .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_128BITTAG") .withRandomId()) .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_128BITTAG") .withRandomId()) .build(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CleartextKeysetHandle.write(handle1, JsonKeysetWriter.withOutputStream(outputStream)); KeysetHandle handle2 = CleartextKeysetHandle.read( JsonKeysetReader.withInputStream(new ByteArrayInputStream(outputStream.toByteArray()))); assertKeysetHandle(handle1, handle2); } @Test public void readTestKeysetVerifyTestTag() throws Exception { KeysetHandle handle = CleartextKeysetHandle.read(JsonKeysetReader.withString(JSON_KEYSET)); byte[] data = "data".getBytes(UTF_8); Mac mac = handle.getPrimitive(RegistryConfiguration.get(), Mac.class); byte[] tag = Hex.decode("0120a4107f3549e4fb3137415a63f5c8a0524f8ca7"); mac.verifyMac(tag, data); } @Test public void readEncryptedTestKeysetVerifyTestTag() throws Exception { // This is the same test vector as in KeysetHandleTest. // An AEAD key, with which we encrypted the mac keyset below. byte[] serializedKeysetEncryptionKeyset = Hex.decode( "08b891f5a20412580a4c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e6372797" + "0746f2e74696e6b2e4165734561784b65791216120208101a10e5d7d0cdd649e81e7952260689b2" + "e1971801100118b891f5a2042001"); KeysetHandle keysetEncryptionHandle = TinkProtoKeysetFormat.parseKeyset( serializedKeysetEncryptionKeyset, InsecureSecretKeyAccess.get()); Aead keysetEncryptionAead = keysetEncryptionHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); byte[] associatedData = Hex.decode("abcdef330012"); String encryptedKeyset = "{\"encryptedKeyset\":" + "\"AURdSLhZcFEgMBptDyi4/D8hL3h+Iz7ICgLrdeVRH26Fi3uSeewFoFA5cV5wfNueme3/BBR60yJ4hGpQ" + "p+/248ZIgfuWyfmAGZ4dmYnYC1qd/IWkZZfVr3aOsx4j4kFZHkkvA+XIZUh/INbdPsMUNJy9cmu6s8osdH" + "zu0XzP2ltWUowbr0fLQJwy92eAvU6gv91k6Tc=\"," + "\"keysetInfo\":{\"primaryKeyId\":547623039,\"keyInfo\":[{\"typeUrl\":" + "\"type.googleapis.com/google.crypto.tink.HmacKey\",\"status\":\"ENABLED\"," + "\"keyId\":547623039,\"outputPrefixType\":\"TINK\"}]}}"; KeysetHandle handle = KeysetHandle.readWithAssociatedData( JsonKeysetReader.withString(encryptedKeyset), keysetEncryptionAead, associatedData); byte[] data = "data".getBytes(UTF_8); Mac mac = handle.getPrimitive(RegistryConfiguration.get(), Mac.class); byte[] tag = Hex.decode("0120a4107f3549e4fb3137415a63f5c8a0524f8ca7"); mac.verifyMac(tag, data); } @Test public void testRead_urlSafeKeyset_shouldWork() throws Exception { KeysetHandle handle1 = CleartextKeysetHandle.read(JsonKeysetReader.withString(JSON_KEYSET)); KeysetHandle handle2 = CleartextKeysetHandle.read( JsonKeysetReader.withString(URL_SAFE_JSON_KEYSET).withUrlSafeBase64()); assertKeysetHandle(handle1, handle2); } @Test public void testRead_missingKey_shouldThrowException() throws Exception { JsonObject json = JsonParser.parseString(JSON_KEYSET).getAsJsonObject(); json.remove("key"); // remove key IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withJsonObject(json).read()); assertThat(e.toString()).contains("invalid keyset"); } private void testReadInvalidKeyShouldThrowException(String name) throws Exception { JsonObject json = JsonParser.parseString(JSON_KEYSET).getAsJsonObject(); JsonArray keys = json.get("key").getAsJsonArray(); JsonObject key = keys.get(0).getAsJsonObject(); key.remove(name); keys.set(0, key); json.add("key", keys); try { JsonKeysetReader.withJsonObject(json).read(); fail("Expected IOException"); } catch (IOException e) { assertThat(e.toString()).contains("invalid key"); } } @Test public void testRead_invalidKey_shouldThrowException() throws Exception { testReadInvalidKeyShouldThrowException("keyData"); testReadInvalidKeyShouldThrowException("status"); testReadInvalidKeyShouldThrowException("keyId"); testReadInvalidKeyShouldThrowException("outputPrefixType"); } private void testRead_invalidKeyData_shouldThrowException(String name) throws Exception { JsonObject json = JsonParser.parseString(JSON_KEYSET).getAsJsonObject(); JsonArray keys = json.get("key").getAsJsonArray(); JsonObject key = keys.get(0).getAsJsonObject(); JsonObject keyData = key.get("keyData").getAsJsonObject(); keyData.remove(name); key.add("keyData", keyData); keys.set(0, key); json.add("key", keys); try { JsonKeysetReader.withJsonObject(json).read(); fail("Expected IOException"); } catch (IOException e) { assertThat(e.toString()).contains("invalid keyData"); } } @Test public void testRead_invalidKeyData_shouldThrowException() throws Exception { testRead_invalidKeyData_shouldThrowException("typeUrl"); testRead_invalidKeyData_shouldThrowException("value"); testRead_invalidKeyData_shouldThrowException("keyMaterialType"); } @Test public void testRead_invalidKeyMaterialType_shouldThrowException() throws Exception { JsonObject json = JsonParser.parseString(JSON_KEYSET).getAsJsonObject(); JsonArray keys = json.get("key").getAsJsonArray(); JsonObject key = keys.get(0).getAsJsonObject(); JsonObject keyData = key.get("keyData").getAsJsonObject(); keyData.addProperty("keyMaterialType", "invalid"); key.add("keyData", keyData); keys.set(0, key); json.add("key", keys); IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withJsonObject(json).read()); assertThat(e.toString()).contains("unknown key material type"); } @Test public void testRead_invalidStatus_shouldThrowException() throws Exception { JsonObject json = JsonParser.parseString(JSON_KEYSET).getAsJsonObject(); JsonArray keys = json.get("key").getAsJsonArray(); JsonObject key = keys.get(0).getAsJsonObject(); key.addProperty("status", "invalid"); keys.set(0, key); json.add("key", keys); IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withJsonObject(json).read()); assertThat(e.toString()).contains("unknown status"); } @Test public void testRead_invalidOutputPrefixType_shouldThrowException() throws Exception { JsonObject json = JsonParser.parseString(JSON_KEYSET).getAsJsonObject(); JsonArray keys = json.get("key").getAsJsonArray(); JsonObject key = keys.get(0).getAsJsonObject(); key.addProperty("outputPrefixType", "invalid"); keys.set(0, key); json.add("key", keys); IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withJsonObject(json).read()); assertThat(e.toString()).contains("unknown output prefix type"); } @Test public void testRead_jsonKeysetWriter_shouldWork() throws Exception { KeysetHandle handle1 = KeysetHandle.generateNew(PredefinedMacParameters.HMAC_SHA256_128BITTAG); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CleartextKeysetHandle.write(handle1, JsonKeysetWriter.withOutputStream(outputStream)); KeysetHandle handle2 = CleartextKeysetHandle.read(JsonKeysetReader.withBytes(outputStream.toByteArray())); assertKeysetHandle(handle1, handle2); } @Test public void testRead_staticMethods_validKeyset_shouldWork() throws Exception { KeysetHandle handle1 = CleartextKeysetHandle.read(JsonKeysetReader.withString(JSON_KEYSET)); KeysetHandle handle2 = CleartextKeysetHandle.read( JsonKeysetReader.withInputStream( new ByteArrayInputStream(JSON_KEYSET.getBytes(UTF_8)))); KeysetHandle handle3 = CleartextKeysetHandle.read(JsonKeysetReader.withBytes(JSON_KEYSET.getBytes(UTF_8))); KeysetHandle handle4 = CleartextKeysetHandle.read( JsonKeysetReader.withJsonObject(JsonParser.parseString(JSON_KEYSET).getAsJsonObject())); assertKeysetHandle(handle1, handle2); assertKeysetHandle(handle1, handle3); assertKeysetHandle(handle1, handle4); } @Test public void testReadEncrypted_singleKey_shouldWork() throws Exception { Aead masterKey = KeysetHandle.generateNew(PredefinedAeadParameters.AES128_EAX) .getPrimitive(RegistryConfiguration.get(), Aead.class); KeysetHandle handle1 = KeysetHandle.generateNew(PredefinedMacParameters.HMAC_SHA256_128BITTAG); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); handle1.write(JsonKeysetWriter.withOutputStream(outputStream), masterKey); KeysetHandle handle2 = KeysetHandle.read( JsonKeysetReader.withInputStream(new ByteArrayInputStream(outputStream.toByteArray())), masterKey); assertKeysetHandle(handle1, handle2); } @Test public void testReadEncrypted_multipleKeys_shouldWork() throws Exception { Aead keysetEncryptionAead = KeysetHandle.generateNew(KeyTemplates.get("AES128_EAX")) .getPrimitive(RegistryConfiguration.get(), Aead.class); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); KeysetHandle handle1 = KeysetHandle.newBuilder() .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_128BITTAG") .withRandomId()) .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_128BITTAG_RAW") .withRandomId() .makePrimary()) .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_256BITTAG") .withRandomId()) .addEntry( KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_256BITTAG_RAW") .withRandomId() .setStatus(KeyStatus.DESTROYED)) .addEntry( KeysetHandle.generateEntryFromParametersName("AES256_CMAC") .withRandomId() .setStatus(KeyStatus.DISABLED)) .build(); handle1.write(JsonKeysetWriter.withOutputStream(outputStream), keysetEncryptionAead); KeysetHandle handle2 = KeysetHandle.read( JsonKeysetReader.withInputStream(new ByteArrayInputStream(outputStream.toByteArray())), keysetEncryptionAead); assertKeysetHandle(handle1, handle2); } @Test public void testReadEncrypted_missingKeysetInfo_shouldSucceed() throws Exception { Aead keysetEncryptionAead = KeysetHandle.generateNew(KeyTemplates.get("AES128_EAX")) .getPrimitive(RegistryConfiguration.get(), Aead.class); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); KeysetHandle handle1 = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_128BITTAG")); // Generate a valid encrypted keyset in JSON format, and delete "keysetInfo". handle1.write(JsonKeysetWriter.withOutputStream(outputStream), keysetEncryptionAead); JsonObject jsonEncryptedKeyset = JsonParser.parseString(new String(outputStream.toByteArray(), UTF_8)).getAsJsonObject(); jsonEncryptedKeyset.remove("keysetInfo"); String jsonEncryptedKeysetWithoutKeysetInfo = jsonEncryptedKeyset.toString(); KeysetHandle handle2 = KeysetHandle.read( JsonKeysetReader.withString(jsonEncryptedKeysetWithoutKeysetInfo), keysetEncryptionAead); assertKeysetHandle(handle1, handle2); } @Test public void testReadEncrypted_missingEncryptedKeyset_shouldThrowException() throws Exception { Aead masterKey = KeysetHandle.generateNew(PredefinedAeadParameters.AES128_EAX) .getPrimitive(RegistryConfiguration.get(), Aead.class); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); KeysetHandle handle = KeysetHandle.generateNew(PredefinedMacParameters.HMAC_SHA256_128BITTAG); handle.write(JsonKeysetWriter.withOutputStream(outputStream), masterKey); JsonObject json = JsonParser.parseString(new String(outputStream.toByteArray(), UTF_8)).getAsJsonObject(); json.remove("encryptedKeyset"); // remove key IOException e = assertThrows( IOException.class, () -> JsonKeysetReader.withJsonObject(json).readEncrypted()); assertThat(e.toString()).contains("invalid encrypted keyset"); } @Test public void testReadEncrypted_jsonKeysetWriter_shouldWork() throws Exception { Aead masterKey = KeysetHandle.generateNew(PredefinedAeadParameters.AES128_EAX) .getPrimitive(RegistryConfiguration.get(), Aead.class); KeysetHandle handle1 = KeysetHandle.generateNew(PredefinedMacParameters.HMAC_SHA256_128BITTAG); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); handle1.write(JsonKeysetWriter.withOutputStream(outputStream), masterKey); KeysetHandle handle2 = KeysetHandle.read(JsonKeysetReader.withBytes(outputStream.toByteArray()), masterKey); assertKeysetHandle(handle1, handle2); } @Test public void readKeyset_negativeKeyId_works() throws Exception { String jsonKeysetString = createJsonKeysetWithId("-21"); Keyset keyset = JsonKeysetReader.withString(jsonKeysetString).read(); assertThat(keyset.getPrimaryKeyId()).isEqualTo(-21); } @Test public void readKeyset_convertsUnsignedUint32IntoSignedInt32() throws Exception { String jsonKeysetString = createJsonKeysetWithId("4294967275"); // 2^32 - 21 Keyset keyset = JsonKeysetReader.withString(jsonKeysetString).read(); assertThat(keyset.getPrimaryKeyId()).isEqualTo(-21); } @Test public void readKeyset_acceptsMaxUint32() throws Exception { String jsonKeysetString = createJsonKeysetWithId("4294967295"); // 2^32 - 1 = 0xffffffff Keyset keyset = JsonKeysetReader.withString(jsonKeysetString).read(); assertThat(keyset.getPrimaryKeyId()).isEqualTo(-1); } @Test public void readKeyset_acceptsMinInt32() throws Exception { String jsonKeysetString = createJsonKeysetWithId("-2147483648"); // - 2^31 Keyset keyset = JsonKeysetReader.withString(jsonKeysetString).read(); assertThat(keyset.getPrimaryKeyId()).isEqualTo(-2147483648); } @Test public void readKeyset_rejectsKeyIdLargerThanUint32() throws Exception { String jsonKeysetString = createJsonKeysetWithId("4294967296"); // 2^32 assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void readKeyset_rejectsKeyIdLargerThanUint64() throws Exception { String jsonKeysetString = createJsonKeysetWithId("18446744073709551658"); // 2^64 + 42 assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void readKeyset_rejectsKeyIdSmallerThanInt32() throws Exception { String jsonKeysetString = createJsonKeysetWithId("-2147483649"); // - 2^31 - 1 assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void testReadKeyset_keyIdWithComment_throws() throws Exception { String jsonKeysetString = createJsonKeysetWithId("123 /* comment on key ID */"); assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void testReadKeyset_withDuplicatedMapKey_throws() throws Exception { String jsonKeysetString = "{" + "\"primaryKeyId\": 123," + "\"key\": [{" + "\"keyData\": {" + "\"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacKey\"," + "\"keyMaterialType\": \"SYMMETRIC\"," + "\"keyMaterialType\": \"SYMMETRIC\"," + "\"value\": \"EgQIAxAQGiBYhMkitTWFVefTIBg6kpvac+bwFOGSkENGmU+1EYgocg==\"" + "}," + "\"outputPrefixType\": \"TINK\"," + "\"keyId\": 123," + "\"status\": \"ENABLED\"" + "}]}"; assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void testReadKeyset_withInvalidCharacterInTypeUrl_throws() throws Exception { String jsonKeysetString = "{" + "\"primaryKeyId\": 123," + "\"key\": [{" + "\"keyData\": {" + "\"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacKey\\uD834\"," + "\"keyMaterialType\": \"SYMMETRIC\"," + "\"value\": \"EgQIAxAQGiBYhMkitTWFVefTIBg6kpvac+bwFOGSkENGmU+1EYgocg==\"" + "}," + "\"outputPrefixType\": \"TINK\"," + "\"keyId\": 123," + "\"status\": \"ENABLED\"" + "}]}"; assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void testReadKeyset_withoutQuotes_throws() throws Exception { String jsonKeysetString = "{" + "primaryKeyId: 123," + "key:[{" + "keyData:{" + "typeUrl:\"type.googleapis.com/google.crypto.tink.HmacKey\"," + "keyMaterialType: SYMMETRIC," + "value: \"EgQIAxAQGiBYhMkitTWFVefTIBg6kpvac+bwFOGSkENGmU+1EYgocg==\"" + "}," + "outputPrefixType:TINK," + "keyId:123," + "status:ENABLED" + "}]}"; assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeysetString).read()); } @Test public void testRead_validJsonKeyset_doesNotThrow() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; assertThat(JsonKeysetReader.withString(jsonKeyset).read()).isNotNull(); } @Test public void testRead_primaryKeyIdIsAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": \"42818733\"," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("invalid key id"); } @Test public void testRead_primaryKeyIdIsNotAnIntegerOrAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": true," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("invalid key id"); } @Test public void testRead_keyIsNotAnArray_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": " + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("key must be an array"); } @Test public void testRead_keyEntryIsNotAnObject_throws() throws Exception { String jsonKeyset = "{\"primaryKeyId\":42818733,\"key\":[true]}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e) .hasMessageThat() .contains("java.lang.IllegalStateException: Not a JSON Object: true"); } @Test public void testRead_keyDataIsNotAnObject_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("keyData must be an object"); } @Test public void testRead_outputPrefixTypeIsNotAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": 1," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("unknown output prefix type: 1"); } @Test public void testRead_keyIdIsAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": \"42818733\"," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("invalid key id"); } @Test public void testRead_keyIdIsNotAnIntegerOrAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": true," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("invalid key id"); } @Test public void testRead_statusIsNotAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": true" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("unknown status: true"); } @Test public void testRead_typeUrlIsNotAString_works() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": 123," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; Keyset keyset = JsonKeysetReader.withString(jsonKeyset).read(); assertThat(keyset.getKey(0).getKeyData().getTypeUrl()).isEqualTo("123"); } @Test public void testRead_valueIsNotAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": \"SYMMETRIC\"," + " \"value\": 123" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; Keyset keyset = JsonKeysetReader.withString(jsonKeyset).read(); assertThat(keyset.getKey(0).getKeyData().getValue().size()).isEqualTo(2); } @Test public void testRead_keyMaterialTypeIsNotAString_throws() throws Exception { String jsonKeyset = "{" + " \"primaryKeyId\": 42818733," + " \"key\": [" + " {" + " \"keyData\": {" + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\"," + " \"keyMaterialType\": 123," + " \"value\": \"GhCC74uJ+2f4qlpaHwR4ylNQ\"" + " }," + " \"outputPrefixType\": \"TINK\"," + " \"keyId\": 42818733," + " \"status\": \"ENABLED\"" + " }]" + "}"; IOException e = assertThrows(IOException.class, () -> JsonKeysetReader.withString(jsonKeyset).read()); assertThat(e).hasMessageThat().contains("unknown key material type: 123"); } }