| // 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 com.google.crypto.tink.testing.TestUtil.assertExceptionContains; |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| import static org.junit.Assert.fail; |
| |
| import com.google.crypto.tink.aead.AeadConfig; |
| import com.google.crypto.tink.aead.AeadKeyTemplates; |
| import com.google.crypto.tink.config.TinkConfig; |
| import com.google.crypto.tink.mac.MacConfig; |
| import com.google.crypto.tink.mac.MacKeyTemplates; |
| import com.google.crypto.tink.proto.AesEaxKey; |
| import com.google.crypto.tink.proto.AesGcmKey; |
| import com.google.crypto.tink.proto.AesGcmKeyFormat; |
| import com.google.crypto.tink.proto.Ed25519KeyFormat; |
| import com.google.crypto.tink.proto.Ed25519PrivateKey; |
| import com.google.crypto.tink.proto.Ed25519PublicKey; |
| import com.google.crypto.tink.proto.HashType; |
| import com.google.crypto.tink.proto.HmacKey; |
| import com.google.crypto.tink.proto.KeyData; |
| import com.google.crypto.tink.proto.KeyData.KeyMaterialType; |
| import com.google.crypto.tink.proto.KeyStatusType; |
| import com.google.crypto.tink.proto.KeyTemplate; |
| import com.google.crypto.tink.proto.Keyset; |
| import com.google.crypto.tink.proto.OutputPrefixType; |
| import com.google.crypto.tink.signature.SignatureKeyTemplates; |
| import com.google.crypto.tink.subtle.AesEaxJce; |
| import com.google.crypto.tink.subtle.AesGcmJce; |
| import com.google.crypto.tink.subtle.EncryptThenAuthenticate; |
| import com.google.crypto.tink.subtle.PrfMac; |
| import com.google.crypto.tink.subtle.Random; |
| import com.google.crypto.tink.testing.TestUtil.DummyAead; |
| import com.google.protobuf.ByteString; |
| import com.google.protobuf.ExtensionRegistryLite; |
| import com.google.protobuf.InvalidProtocolBufferException; |
| import com.google.protobuf.MessageLite; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.GeneralSecurityException; |
| import java.util.List; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for Registry. */ |
| @RunWith(JUnit4.class) |
| public class RegistryTest { |
| private static class CustomAeadKeyManager implements KeyManager<Aead> { |
| public CustomAeadKeyManager(String typeUrl) { |
| this.typeUrl = typeUrl; |
| } |
| |
| private final String typeUrl; |
| |
| @Override |
| public Aead getPrimitive(ByteString proto) throws GeneralSecurityException { |
| return new DummyAead(); |
| } |
| |
| @Override |
| public Aead getPrimitive(MessageLite proto) throws GeneralSecurityException { |
| return new DummyAead(); |
| } |
| |
| @Override |
| public MessageLite newKey(ByteString template) throws GeneralSecurityException { |
| throw new GeneralSecurityException("Not Implemented"); |
| } |
| |
| @Override |
| public MessageLite newKey(MessageLite template) throws GeneralSecurityException { |
| throw new GeneralSecurityException("Not Implemented"); |
| } |
| |
| @Override |
| public KeyData newKeyData(ByteString serialized) throws GeneralSecurityException { |
| throw new GeneralSecurityException("Not Implemented"); |
| } |
| |
| @Override |
| public boolean doesSupport(String typeUrl) { |
| return typeUrl.equals(this.typeUrl); |
| } |
| |
| @Override |
| public String getKeyType() { |
| return this.typeUrl; |
| } |
| |
| @Override |
| public int getVersion() { |
| return 0; |
| } |
| |
| @Override |
| public Class<Aead> getPrimitiveClass() { |
| return Aead.class; |
| } |
| } |
| |
| @Before |
| public void setUp() throws GeneralSecurityException { |
| Registry.reset(); |
| TinkConfig.register(); |
| } |
| |
| private void testGetKeyManager_shouldWork(String typeUrl, String className) throws Exception { |
| assertThat(Registry.getKeyManager(typeUrl).getClass().toString()).contains(className); |
| } |
| |
| @Test |
| public void testGetKeyManager_legacy_shouldWork() throws Exception { |
| testGetKeyManager_shouldWork(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL, "KeyManagerImpl"); |
| testGetKeyManager_shouldWork(AeadConfig.AES_EAX_TYPE_URL, "KeyManagerImpl"); |
| testGetKeyManager_shouldWork(MacConfig.HMAC_TYPE_URL, "KeyManagerImpl"); |
| } |
| |
| @Test |
| public void testGetKeyManager_shouldWorkAesEax() throws Exception { |
| assertThat( |
| Registry.getKeyManager(AeadConfig.AES_EAX_TYPE_URL, Aead.class).getClass().toString()) |
| .contains("KeyManagerImpl"); |
| } |
| |
| @Test |
| public void testGetKeyManager_shouldWorkHmac() throws Exception { |
| assertThat(Registry.getKeyManager(MacConfig.HMAC_TYPE_URL, Mac.class).getClass().toString()) |
| .contains("KeyManagerImpl"); |
| } |
| |
| @Test |
| public void testGetKeyManager_legacy_wrongType_shouldThrowException() throws Exception { |
| KeyManager<Aead> wrongType = Registry.getKeyManager(MacConfig.HMAC_TYPE_URL); |
| KeyTemplate template = MacKeyTemplates.HMAC_SHA256_128BITTAG; |
| HmacKey hmacKey = (HmacKey) Registry.newKey(template); |
| |
| try { |
| Aead unused = wrongType.getPrimitive(hmacKey); |
| fail("Expected ClassCastException"); |
| } catch (ClassCastException e) { |
| assertExceptionContains(e, "com.google.crypto.tink.Aead"); |
| assertExceptionContains(e, "com.google.crypto.tink.subtle.PrfMac"); |
| } |
| } |
| |
| @Test |
| public void testGetKeyManager_wrongType_shouldThrowException() throws Exception { |
| try { |
| Registry.getKeyManager(MacConfig.HMAC_TYPE_URL, Aead.class); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "com.google.crypto.tink.Mac"); |
| assertExceptionContains(e, "com.google.crypto.tink.Aead not supported"); |
| } |
| } |
| |
| @Test |
| public void testGetKeyManager_legacy_badTypeUrl_shouldThrowException() throws Exception { |
| String badTypeUrl = "bad type URL"; |
| |
| try { |
| Registry.getKeyManager(badTypeUrl); |
| fail("Expected GeneralSecurityException."); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "No key manager found"); |
| assertExceptionContains(e, badTypeUrl); |
| } |
| } |
| |
| @Test |
| public void testGetKeyManager_badTypeUrl_shouldThrowException() throws Exception { |
| String badTypeUrl = "bad type URL"; |
| |
| try { |
| Registry.getKeyManager(badTypeUrl, Aead.class); |
| fail("Expected GeneralSecurityException."); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "No key manager found"); |
| assertExceptionContains(e, badTypeUrl); |
| } |
| } |
| |
| @Test |
| public void testGetUntypedKeyManager_shouldWorkHmac() throws Exception { |
| assertThat(Registry.getUntypedKeyManager(MacConfig.HMAC_TYPE_URL).getClass().toString()) |
| .contains("KeyManagerImpl"); |
| } |
| |
| @Test |
| public void testRegisterKeyManager_keyManagerIsNull_shouldThrowException() throws Exception { |
| try { |
| Registry.registerKeyManager(null); |
| fail("Expected IllegalArgumentException."); |
| } catch (IllegalArgumentException e) { |
| assertThat(e.toString()).contains("must be non-null"); |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyManager_MoreRestrictedNewKeyAllowed_shouldWork() throws Exception { |
| String typeUrl = "someTypeUrl"; |
| Registry.registerKeyManager(new CustomAeadKeyManager(typeUrl)); |
| Registry.registerKeyManager(new CustomAeadKeyManager(typeUrl), false); |
| } |
| |
| @Test |
| public void testRegisterKeyManager_SameNewKeyAllowed_shouldWork() throws Exception { |
| String typeUrl = "someOtherTypeUrl"; |
| Registry.registerKeyManager(new CustomAeadKeyManager(typeUrl)); |
| Registry.registerKeyManager(new CustomAeadKeyManager(typeUrl), true); |
| } |
| |
| @Test |
| public void testRegisterKeyManager_LessRestrictedNewKeyAllowed_shouldThrowException() |
| throws Exception { |
| String typeUrl = "yetAnotherTypeUrl"; |
| Registry.registerKeyManager(new CustomAeadKeyManager(typeUrl), false); |
| |
| try { |
| Registry.registerKeyManager(new CustomAeadKeyManager(typeUrl), true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyManager_keyManagerFromAnotherClass_shouldThrowException() |
| throws Exception { |
| // This should not overwrite the existing manager. |
| try { |
| Registry.registerKeyManager(new CustomAeadKeyManager(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL)); |
| fail("Expected GeneralSecurityException."); |
| } catch (GeneralSecurityException e) { |
| assertThat(e.toString()).contains("already registered"); |
| } |
| |
| KeyManager<Aead> manager = Registry.getKeyManager(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL); |
| assertThat(manager.getClass().toString()).contains("KeyManagerImpl"); |
| } |
| |
| @Test |
| public void testRegisterKeyManager_deprecated_keyManagerIsNull_shouldThrowException() |
| throws Exception { |
| try { |
| Registry.registerKeyManager(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL, null); |
| fail("Expected IllegalArgumentException."); |
| } catch (IllegalArgumentException e) { |
| assertThat(e.toString()).contains("must be non-null"); |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyManager_deprecated_WithKeyTypeNotSupported_shouldThrowException() |
| throws Exception { |
| String typeUrl = "yetSomeOtherTypeUrl"; |
| String differentTypeUrl = "differentTypeUrl"; |
| try { |
| Registry.registerKeyManager(differentTypeUrl, new CustomAeadKeyManager(typeUrl)); |
| fail("Should throw an exception."); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, |
| "Manager does not support key type " + differentTypeUrl); |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyManager_deprecated_MoreRestrictedNewKeyAllowed_shouldWork() |
| throws Exception { |
| String typeUrl = "typeUrl"; |
| Registry.registerKeyManager(typeUrl, new CustomAeadKeyManager(typeUrl)); |
| |
| try { |
| Registry.registerKeyManager(typeUrl, new CustomAeadKeyManager(typeUrl), false); |
| } catch (GeneralSecurityException e) { |
| fail("repeated registrations of the same key manager should work"); |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyManager_deprecated_LessRestrictedNewKeyAllowed_shouldThrowException() |
| throws Exception { |
| String typeUrl = "totallyDifferentTypeUrl"; |
| Registry.registerKeyManager(typeUrl, new CustomAeadKeyManager(typeUrl), false); |
| |
| try { |
| Registry.registerKeyManager(typeUrl, new CustomAeadKeyManager(typeUrl), true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyManager_deprecated_keyManagerFromAnotherClass_shouldThrowException() |
| throws Exception { |
| // This should not overwrite the existing manager. |
| try { |
| Registry.registerKeyManager(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL, |
| new CustomAeadKeyManager(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL)); |
| fail("Expected GeneralSecurityException."); |
| } catch (GeneralSecurityException e) { |
| assertThat(e.toString()).contains("already registered"); |
| } |
| |
| KeyManager<Aead> manager = Registry.getKeyManager(AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL); |
| assertThat(manager.getClass().toString()).contains("KeyManagerImpl"); |
| } |
| |
| @Test |
| public void testGetPublicKeyData_shouldWork() throws Exception { |
| KeyData privateKeyData = Registry.newKeyData(SignatureKeyTemplates.ECDSA_P256); |
| KeyData publicKeyData = Registry.getPublicKeyData(privateKeyData.getTypeUrl(), |
| privateKeyData.getValue()); |
| PublicKeyVerify verifier = Registry.<PublicKeyVerify>getPrimitive(publicKeyData); |
| PublicKeySign signer = Registry.<PublicKeySign>getPrimitive(privateKeyData); |
| byte[] message = "Nice test message".getBytes(UTF_8); |
| verifier.verify(signer.sign(message), message); |
| } |
| |
| @Test |
| public void testGetPublicKeyData_shouldThrow() throws Exception { |
| KeyData keyData = Registry.newKeyData(MacKeyTemplates.HMAC_SHA256_128BITTAG); |
| try { |
| Registry.getPublicKeyData(keyData.getTypeUrl(), keyData.getValue()); |
| fail("Expected GeneralSecurityException."); |
| } catch (GeneralSecurityException e) { |
| assertThat(e.toString()).contains("not a PrivateKeyManager"); |
| } |
| } |
| |
| @Test |
| public void testGetPrimitive_legacy_AesGcm_shouldWork() throws Exception { |
| KeyTemplate template = AeadKeyTemplates.AES128_EAX; |
| AesEaxKey aesEaxKey = (AesEaxKey) Registry.newKey(template); |
| KeyData aesEaxKeyData = Registry.newKeyData(template); |
| Aead aead = Registry.getPrimitive(aesEaxKeyData); |
| |
| assertThat(aesEaxKey.getKeyValue().size()).isEqualTo(16); |
| assertThat(aesEaxKeyData.getTypeUrl()).isEqualTo(AeadConfig.AES_EAX_TYPE_URL); |
| // This might break when we add native implementations. |
| assertThat(aead.getClass()).isEqualTo(AesEaxJce.class); |
| } |
| |
| @Test |
| public void testGetPrimitive_AesGcm_shouldWork() throws Exception { |
| KeyTemplate template = AeadKeyTemplates.AES128_EAX; |
| AesEaxKey aesEaxKey = (AesEaxKey) Registry.newKey(template); |
| KeyData aesEaxKeyData = Registry.newKeyData(template); |
| Aead aead = Registry.getPrimitive(aesEaxKeyData, Aead.class); |
| |
| assertThat(aesEaxKey.getKeyValue().size()).isEqualTo(16); |
| assertThat(aesEaxKeyData.getTypeUrl()).isEqualTo(AeadConfig.AES_EAX_TYPE_URL); |
| // This might break when we add native implementations. |
| assertThat(aead.getClass()).isEqualTo(AesEaxJce.class); |
| } |
| |
| @Test |
| public void testGetPrimitive_legacy_Hmac_shouldWork() throws Exception { |
| KeyTemplate template = MacKeyTemplates.HMAC_SHA256_128BITTAG; |
| HmacKey hmacKey = (HmacKey) Registry.newKey(template); |
| KeyData hmacKeyData = Registry.newKeyData(template); |
| Mac mac = Registry.getPrimitive(hmacKeyData); |
| |
| assertThat(hmacKey.getKeyValue().size()).isEqualTo(32); |
| assertThat(hmacKey.getParams().getTagSize()).isEqualTo(16); |
| assertThat(hmacKey.getParams().getHash()).isEqualTo(HashType.SHA256); |
| assertThat(hmacKeyData.getTypeUrl()).isEqualTo(MacConfig.HMAC_TYPE_URL); |
| // This might break when we add native implementations. |
| assertThat(mac.getClass()).isEqualTo(PrfMac.class); |
| } |
| |
| @Test |
| public void testGetPrimitive_Hmac_shouldWork() throws Exception { |
| KeyTemplate template = MacKeyTemplates.HMAC_SHA256_128BITTAG; |
| HmacKey hmacKey = (HmacKey) Registry.newKey(template); |
| KeyData hmacKeyData = Registry.newKeyData(template); |
| Mac mac = Registry.getPrimitive(hmacKeyData, Mac.class); |
| |
| assertThat(hmacKey.getKeyValue().size()).isEqualTo(32); |
| assertThat(hmacKey.getParams().getTagSize()).isEqualTo(16); |
| assertThat(hmacKey.getParams().getHash()).isEqualTo(HashType.SHA256); |
| assertThat(hmacKeyData.getTypeUrl()).isEqualTo(MacConfig.HMAC_TYPE_URL); |
| // This might break when we add native implementations. |
| assertThat(mac.getClass()).isEqualTo(PrfMac.class); |
| } |
| |
| @Test |
| public void testGetPrimitives_legacy_shouldWork() throws Exception { |
| // Create a keyset, and get a PrimitiveSet. |
| KeyTemplate template1 = AeadKeyTemplates.AES128_EAX; |
| KeyTemplate template2 = AeadKeyTemplates.AES128_CTR_HMAC_SHA256; |
| KeyData key1 = Registry.newKeyData(template1); |
| KeyData key2 = Registry.newKeyData(template1); |
| KeyData key3 = Registry.newKeyData(template2); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key2) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key3) |
| .setKeyId(3) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(2) |
| .build()); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, Aead.class); |
| |
| assertThat(aeadSet.getPrimary().getPrimitive().getClass()).isEqualTo(AesEaxJce.class); |
| } |
| |
| @Test |
| public void testGetPrimitives_shouldWork() throws Exception { |
| // Create a keyset, and get a PrimitiveSet. |
| KeyTemplate template1 = AeadKeyTemplates.AES128_EAX; |
| KeyTemplate template2 = AeadKeyTemplates.AES128_CTR_HMAC_SHA256; |
| KeyData key1 = Registry.newKeyData(template1); |
| KeyData key2 = Registry.newKeyData(template1); |
| KeyData key3 = Registry.newKeyData(template2); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key2) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key3) |
| .setKeyId(3) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(2) |
| .build()); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, Aead.class); |
| |
| assertThat(aeadSet.getPrimary().getPrimitive().getClass()).isEqualTo(AesEaxJce.class); |
| } |
| |
| @Test |
| public void testGetPrimitives_WithSomeNonEnabledKeys_shouldWork() throws Exception { |
| // Try a keyset with some keys non-ENABLED. |
| KeyTemplate template1 = AeadKeyTemplates.AES128_EAX; |
| KeyTemplate template2 = AeadKeyTemplates.AES128_CTR_HMAC_SHA256; |
| KeyData key1 = Registry.newKeyData(template1); |
| KeyData key2 = Registry.newKeyData(template1); |
| KeyData key3 = Registry.newKeyData(template2); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.DESTROYED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key2) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.DISABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key3) |
| .setKeyId(3) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(3) |
| .build()); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, Aead.class); |
| |
| assertThat(aeadSet.getPrimary().getPrimitive().getClass()) |
| .isEqualTo(EncryptThenAuthenticate.class); |
| } |
| |
| @Test |
| public void testGetPrimitives_legacy_CustomManager_shouldWork() throws Exception { |
| // Create a keyset. |
| KeyTemplate template1 = AeadKeyTemplates.AES128_EAX; |
| KeyTemplate template2 = AeadKeyTemplates.AES128_CTR_HMAC_SHA256; |
| KeyData key1 = Registry.newKeyData(template1); |
| KeyData key2 = Registry.newKeyData(template2); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key2) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(2) |
| .build()); |
| |
| // Get a PrimitiveSet using a custom key manager for key1. |
| KeyManager<Aead> customManager = new CustomAeadKeyManager(AeadConfig.AES_EAX_TYPE_URL); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, customManager); |
| List<PrimitiveSet.Entry<Aead>> aead1List = |
| aeadSet.getPrimitive(keysetHandle.getKeyset().getKey(0)); |
| List<PrimitiveSet.Entry<Aead>> aead2List = |
| aeadSet.getPrimitive(keysetHandle.getKeyset().getKey(1)); |
| |
| assertThat(aead1List).hasSize(1); |
| assertThat(aead1List.get(0).getPrimitive().getClass()).isEqualTo(DummyAead.class); |
| assertThat(aead2List).hasSize(1); |
| assertThat(aead2List.get(0).getPrimitive().getClass()).isEqualTo(EncryptThenAuthenticate.class); |
| } |
| |
| @Test |
| public void testGetPrimitives_CustomManager_shouldWork() throws Exception { |
| // Create a keyset. |
| KeyTemplate template1 = AeadKeyTemplates.AES128_EAX; |
| KeyTemplate template2 = AeadKeyTemplates.AES128_CTR_HMAC_SHA256; |
| KeyData key1 = Registry.newKeyData(template1); |
| KeyData key2 = Registry.newKeyData(template2); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key2) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(2) |
| .build()); |
| |
| // Get a PrimitiveSet using a custom key manager for key1. |
| KeyManager<Aead> customManager = new CustomAeadKeyManager(AeadConfig.AES_EAX_TYPE_URL); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, customManager, Aead.class); |
| List<PrimitiveSet.Entry<Aead>> aead1List = |
| aeadSet.getPrimitive(keysetHandle.getKeyset().getKey(0)); |
| List<PrimitiveSet.Entry<Aead>> aead2List = |
| aeadSet.getPrimitive(keysetHandle.getKeyset().getKey(1)); |
| |
| assertThat(aead1List.size()).isEqualTo(1); |
| assertThat(aead1List.get(0).getPrimitive().getClass()).isEqualTo(DummyAead.class); |
| assertThat(aead2List.size()).isEqualTo(1); |
| assertThat(aead2List.get(0).getPrimitive().getClass()).isEqualTo(EncryptThenAuthenticate.class); |
| } |
| |
| @Test |
| public void testGetPrimitives_EmptyKeyset_shouldThrowException() throws Exception { |
| // Empty keyset. |
| try { |
| Registry.getPrimitives(KeysetHandle.fromKeyset(Keyset.getDefaultInstance()), Aead.class); |
| fail("Invalid keyset. Expect GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "empty keyset"); |
| } |
| } |
| |
| @Test |
| public void testGetPrimitives_KeysetWithNoPrimaryKey_shouldThrowException() throws Exception { |
| // Create a keyset without a primary key. |
| KeyData key1 = Registry.newKeyData(MacKeyTemplates.HMAC_SHA256_128BITTAG); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .build()); |
| |
| // No primary key. |
| try { |
| Registry.getPrimitives(keysetHandle, Aead.class); |
| fail("Invalid keyset. Expect GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "keyset doesn't contain a valid primary key"); |
| } |
| } |
| |
| @Test |
| public void testGetPrimitives_KeysetWithDisabledPrimaryKey_shouldThrowException() |
| throws Exception { |
| // Create a keyset with a disabled primary key. |
| KeyData key1 = Registry.newKeyData(MacKeyTemplates.HMAC_SHA256_128BITTAG); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.DISABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(1) |
| .build()); |
| |
| try { |
| Registry.getPrimitives(keysetHandle, Mac.class); |
| fail("Invalid keyset. Expect GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "keyset doesn't contain a valid primary key"); |
| } |
| } |
| |
| @Test |
| public void testGetPrimitives_KeysetWithMultiplePrimaryKeys_shouldThrowException() |
| throws Exception { |
| // Multiple primary keys. |
| KeyData key1 = Registry.newKeyData(MacKeyTemplates.HMAC_SHA256_128BITTAG); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(1) |
| .build()); |
| |
| try { |
| Registry.getPrimitives(keysetHandle, Mac.class); |
| fail("Invalid keyset. Expect GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "keyset contains multiple primary keys"); |
| } |
| } |
| |
| @Test |
| public void testGetPrimitives_KeysetWithKeyForWrongPrimitive_shouldThrowException() |
| throws Exception { |
| KeyData key1 = Registry.newKeyData(AeadKeyTemplates.AES128_EAX); |
| // This MAC key should cause an exception. |
| KeyData key2 = Registry.newKeyData(MacKeyTemplates.HMAC_SHA256_128BITTAG); |
| KeyData key3 = Registry.newKeyData(AeadKeyTemplates.AES128_EAX); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key1) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key2) |
| .setKeyId(2) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key3) |
| .setKeyId(3) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(3) |
| .build()); |
| try { |
| Registry.getPrimitives(keysetHandle, Aead.class); |
| fail("Non Aead keys. Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "com.google.crypto.tink.Mac"); |
| assertExceptionContains(e, "com.google.crypto.tink.Aead not supported"); |
| } |
| } |
| |
| /** Implementation of a KeyTypeManager for testing. */ |
| private static class TestKeyTypeManager extends KeyTypeManager<AesGcmKey> { |
| public TestKeyTypeManager() { |
| super( |
| AesGcmKey.class, |
| new PrimitiveFactory<Aead, AesGcmKey>(Aead.class) { |
| @Override |
| public Aead getPrimitive(AesGcmKey key) throws GeneralSecurityException { |
| return new AesGcmJce(key.getKeyValue().toByteArray()); |
| } |
| }, |
| new PrimitiveFactory<FakeAead, AesGcmKey>(FakeAead.class) { |
| @Override |
| public FakeAead getPrimitive(AesGcmKey key) { |
| return new FakeAead(); |
| } |
| }); |
| } |
| |
| @Override |
| public String getKeyType() { |
| return "type.googleapis.com/google.crypto.tink.AesGcmKey"; |
| } |
| |
| @Override |
| public int getVersion() { |
| return 1; |
| } |
| |
| @Override |
| public KeyMaterialType keyMaterialType() { |
| return KeyMaterialType.SYMMETRIC; |
| } |
| |
| @Override |
| public void validateKey(AesGcmKey keyProto) throws GeneralSecurityException { |
| // Throw by hand so we can verify the exception comes from here. |
| if (keyProto.getKeyValue().size() != 16) { |
| throw new GeneralSecurityException("validateKey(AesGcmKey) failed"); |
| } |
| } |
| |
| @Override |
| public AesGcmKey parseKey(ByteString byteString) throws InvalidProtocolBufferException { |
| return AesGcmKey.parseFrom(byteString, ExtensionRegistryLite.getEmptyRegistry()); |
| } |
| |
| @Override |
| public KeyFactory<AesGcmKeyFormat, AesGcmKey> keyFactory() { |
| return new KeyFactory<AesGcmKeyFormat, AesGcmKey>(AesGcmKeyFormat.class) { |
| @Override |
| public void validateKeyFormat(AesGcmKeyFormat format) throws GeneralSecurityException { |
| // Throw by hand so we can verify the exception comes from here. |
| if (format.getKeySize() != 16) { |
| throw new GeneralSecurityException("validateKeyFormat(AesGcmKeyFormat) failed"); |
| } |
| } |
| |
| @Override |
| public AesGcmKeyFormat parseKeyFormat(ByteString byteString) |
| throws InvalidProtocolBufferException { |
| return AesGcmKeyFormat.parseFrom(byteString, ExtensionRegistryLite.getEmptyRegistry()); |
| } |
| |
| @Override |
| public AesGcmKey createKey(AesGcmKeyFormat format) throws GeneralSecurityException { |
| return AesGcmKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom(Random.randBytes(format.getKeySize()))) |
| .setVersion(getVersion()) |
| .build(); |
| } |
| |
| @Override |
| public AesGcmKey deriveKey(AesGcmKeyFormat format, InputStream stream) |
| throws GeneralSecurityException { |
| byte[] pseudorandomness = new byte[format.getKeySize()]; |
| try { |
| stream.read(pseudorandomness); |
| } catch (IOException e) { |
| throw new AssertionError("Unexpected IOException", e); |
| } |
| return AesGcmKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom(pseudorandomness)) |
| .setVersion(getVersion()) |
| .build(); |
| } |
| }; |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_getKeyManagerAead_works() throws Exception { |
| Registry.reset(); |
| TestKeyTypeManager testKeyTypeManager = new TestKeyTypeManager(); |
| Registry.registerKeyManager(testKeyTypeManager, true); |
| KeyManager<Aead> km = Registry.getKeyManager(testKeyTypeManager.getKeyType(), Aead.class); |
| assertThat(km.getKeyType()).isEqualTo(testKeyTypeManager.getKeyType()); |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_getKeyManagerFakeAead_works() throws Exception { |
| Registry.reset(); |
| TestKeyTypeManager testKeyTypeManager = new TestKeyTypeManager(); |
| Registry.registerKeyManager(testKeyTypeManager, true); |
| KeyManager<FakeAead> km = |
| Registry.getKeyManager(testKeyTypeManager.getKeyType(), FakeAead.class); |
| assertThat(km.getKeyType()).isEqualTo(testKeyTypeManager.getKeyType()); |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_getKeyManagerMac_throws() throws Exception { |
| Registry.reset(); |
| TestKeyTypeManager testKeyTypeManager = new TestKeyTypeManager(); |
| Registry.registerKeyManager(testKeyTypeManager, true); |
| try { |
| Registry.getKeyManager(testKeyTypeManager.getKeyType(), Mac.class); |
| fail(); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "com.google.crypto.tink.Mac"); |
| assertExceptionContains(e, "com.google.crypto.tink.Aead"); |
| assertExceptionContains(e, "com.google.crypto.tink.RegistryTest.FakeAead"); |
| } |
| } |
| |
| // Checks that calling getUntypedKeyManager will return the keymanager for the *first* implemented |
| // class in the constructor. |
| @Test |
| public void testRegisterKeyTypeManager_getUntypedKeyManager_returnsAead() throws Exception { |
| Registry.reset(); |
| TestKeyTypeManager testKeyTypeManager = new TestKeyTypeManager(); |
| Registry.registerKeyManager(testKeyTypeManager, true); |
| KeyManager<?> km = Registry.getUntypedKeyManager(testKeyTypeManager.getKeyType()); |
| assertThat(km.getPrimitiveClass()).isEqualTo(Aead.class); |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_MoreRestrictedNewKeyAllowed_shouldWork() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| Registry.registerKeyManager(new TestKeyTypeManager(), false); |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_SameNewKeyAllowed_shouldWork() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| Registry.registerKeyManager(new TestKeyTypeManager(), false); |
| Registry.registerKeyManager(new TestKeyTypeManager(), false); |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_LessRestrictedNewKeyAllowed_throws() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), false); |
| try { |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_DifferentClass_throws() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| try { |
| // Note: due to the {} this is a subclass of TestKeyTypeManager. |
| Registry.registerKeyManager(new TestKeyTypeManager() {}, true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_AfterKeyManager_throws() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new CustomAeadKeyManager(new TestKeyTypeManager().getKeyType())); |
| try { |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterKeyTypeManager_BeforeKeyManager_throws() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| try { |
| Registry.registerKeyManager(new CustomAeadKeyManager(new TestKeyTypeManager().getKeyType())); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void parseKeyData_succeeds() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| AesGcmKey key = |
| AesGcmKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom("0123456789abcdef".getBytes(UTF_8))) |
| .build(); |
| KeyData keyData = |
| KeyData.newBuilder() |
| .setTypeUrl(new TestKeyTypeManager().getKeyType()) |
| .setValue(key.toByteString()) |
| .build(); |
| assertThat(Registry.parseKeyData(keyData)).isEqualTo(key); |
| } |
| |
| @Test |
| public void testDeriveKey_succeeds() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| AesGcmKeyFormat format = AesGcmKeyFormat.newBuilder().setKeySize(16).build(); |
| KeyTemplate template = KeyTemplate.newBuilder() |
| .setValue(format.toByteString()) |
| .setTypeUrl(new TestKeyTypeManager().getKeyType()) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build(); |
| |
| byte[] keyMaterial = Random.randBytes(100); |
| KeyData keyData = Registry.deriveKey(template, new ByteArrayInputStream(keyMaterial)); |
| assertThat(keyData.getKeyMaterialType()).isEqualTo(new TestKeyTypeManager().keyMaterialType()); |
| assertThat(keyData.getTypeUrl()).isEqualTo(new TestKeyTypeManager().getKeyType()); |
| AesGcmKey key = |
| AesGcmKey.parseFrom(keyData.getValue(), ExtensionRegistryLite.getEmptyRegistry()); |
| for (int i = 0; i < 16; ++i) { |
| assertThat(key.getKeyValue().byteAt(i)).isEqualTo(keyMaterial[i]); |
| } |
| } |
| |
| // Tests that validate is called. |
| @Test |
| public void testDeriveKey_wrongKeySize_validateThrows() throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestKeyTypeManager(), true); |
| AesGcmKeyFormat format = AesGcmKeyFormat.newBuilder().setKeySize(32).build(); |
| KeyTemplate template = KeyTemplate.newBuilder() |
| .setValue(format.toByteString()) |
| .setTypeUrl(new TestKeyTypeManager().getKeyType()) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build(); |
| ByteArrayInputStream emptyInput = new ByteArrayInputStream(new byte[0]); |
| try { |
| Registry.deriveKey(template, emptyInput); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "validateKeyFormat"); |
| } |
| } |
| |
| @Test |
| public void testDeriveKey_inexistantKeyMananger_throws() throws Exception { |
| Registry.reset(); |
| KeyTemplate template = |
| KeyTemplate.newBuilder() |
| .setValue(AesGcmKeyFormat.getDefaultInstance().toByteString()) |
| .setTypeUrl(new TestKeyTypeManager().getKeyType()) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build(); |
| ByteArrayInputStream emptyInput = new ByteArrayInputStream(new byte[0]); |
| try { |
| Registry.deriveKey(template, emptyInput); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "No keymanager registered"); |
| } |
| } |
| |
| private static class PublicPrimitiveA {} |
| |
| private static class PublicPrimitiveB {} |
| |
| private static class TestPublicKeyTypeManager extends KeyTypeManager<Ed25519PublicKey> { |
| |
| public TestPublicKeyTypeManager() { |
| super( |
| Ed25519PublicKey.class, |
| new PrimitiveFactory<PublicPrimitiveA, Ed25519PublicKey>(PublicPrimitiveA.class) { |
| @Override |
| public PublicPrimitiveA getPrimitive(Ed25519PublicKey key) { |
| return new PublicPrimitiveA(); |
| } |
| }, |
| new PrimitiveFactory<PublicPrimitiveB, Ed25519PublicKey>(PublicPrimitiveB.class) { |
| @Override |
| public PublicPrimitiveB getPrimitive(Ed25519PublicKey key) { |
| return new PublicPrimitiveB(); |
| } |
| }); |
| } |
| |
| @Override |
| public String getKeyType() { |
| return "type.googleapis.com/google.crypto.tink.Ed25519PublicKey"; |
| } |
| |
| @Override |
| public int getVersion() { |
| return 1; |
| } |
| |
| @Override |
| public KeyMaterialType keyMaterialType() { |
| return KeyMaterialType.ASYMMETRIC_PUBLIC; |
| } |
| |
| @Override |
| public void validateKey(Ed25519PublicKey keyProto) throws GeneralSecurityException { |
| if (keyProto.getKeyValue().size() != 32) { |
| throw new GeneralSecurityException("validateKey(Ed25519PublicKey) failed"); |
| } |
| } |
| |
| @Override |
| public Ed25519PublicKey parseKey(ByteString byteString) throws InvalidProtocolBufferException { |
| return Ed25519PublicKey.parseFrom(byteString, ExtensionRegistryLite.getEmptyRegistry()); |
| } |
| } |
| |
| private static class PrivatePrimitiveA {} |
| |
| private static class PrivatePrimitiveB {} |
| |
| private static class TestPrivateKeyTypeManager |
| extends PrivateKeyTypeManager<Ed25519PrivateKey, Ed25519PublicKey> { |
| public TestPrivateKeyTypeManager() { |
| super( |
| Ed25519PrivateKey.class, |
| Ed25519PublicKey.class, |
| new PrimitiveFactory<PrivatePrimitiveA, Ed25519PrivateKey>(PrivatePrimitiveA.class) { |
| @Override |
| public PrivatePrimitiveA getPrimitive(Ed25519PrivateKey key) { |
| return new PrivatePrimitiveA(); |
| } |
| }, |
| new PrimitiveFactory<PrivatePrimitiveB, Ed25519PrivateKey>(PrivatePrimitiveB.class) { |
| @Override |
| public PrivatePrimitiveB getPrimitive(Ed25519PrivateKey key) { |
| return new PrivatePrimitiveB(); |
| } |
| }); |
| } |
| |
| @Override |
| public String getKeyType() { |
| return "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey"; |
| } |
| |
| @Override |
| public int getVersion() { |
| return 1; |
| } |
| |
| @Override |
| public KeyMaterialType keyMaterialType() { |
| return KeyMaterialType.ASYMMETRIC_PRIVATE; |
| } |
| |
| @Override |
| public void validateKey(Ed25519PrivateKey keyProto) throws GeneralSecurityException { |
| // Throw by hand so we can verify the exception comes from here. |
| if (keyProto.getKeyValue().size() != 32) { |
| throw new GeneralSecurityException("validateKey(Ed25519PrivateKey) failed"); |
| } |
| } |
| |
| @Override |
| public Ed25519PrivateKey parseKey(ByteString byteString) throws InvalidProtocolBufferException { |
| return Ed25519PrivateKey.parseFrom(byteString, ExtensionRegistryLite.getEmptyRegistry()); |
| } |
| |
| @Override |
| public Ed25519PublicKey getPublicKey(Ed25519PrivateKey privateKey) { |
| return privateKey.getPublicKey(); |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers() throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getPrivateKeyManagerPrimitiveA_works() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyManager<PrivatePrimitiveA> km = |
| Registry.getKeyManager( |
| new TestPrivateKeyTypeManager().getKeyType(), PrivatePrimitiveA.class); |
| assertThat(km.getKeyType()).isEqualTo(new TestPrivateKeyTypeManager().getKeyType()); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getPrivateKeyManagerPrimitiveB_works() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyManager<PrivatePrimitiveB> km = |
| Registry.getKeyManager( |
| new TestPrivateKeyTypeManager().getKeyType(), PrivatePrimitiveB.class); |
| assertThat(km.getKeyType()).isEqualTo(new TestPrivateKeyTypeManager().getKeyType()); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getPrivateKeyManagerPublicA_works() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyManager<PublicPrimitiveA> km = |
| Registry.getKeyManager(new TestPublicKeyTypeManager().getKeyType(), PublicPrimitiveA.class); |
| assertThat(km.getKeyType()).isEqualTo(new TestPublicKeyTypeManager().getKeyType()); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getPrivateKeyManagerPublicB_works() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyManager<PublicPrimitiveB> km = |
| Registry.getKeyManager(new TestPublicKeyTypeManager().getKeyType(), PublicPrimitiveB.class); |
| assertThat(km.getKeyType()).isEqualTo(new TestPublicKeyTypeManager().getKeyType()); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getPrivateKeyManagerWrongPrimitive_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| Registry.getKeyManager(new TestPrivateKeyTypeManager().getKeyType(), Mac.class); |
| fail(); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "com.google.crypto.tink.Mac"); |
| assertExceptionContains(e, "PrivatePrimitiveA"); |
| assertExceptionContains(e, "PrivatePrimitiveB"); |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getPublicKeyManagerWrongPrimitive_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| Registry.getKeyManager(new TestPublicKeyTypeManager().getKeyType(), Mac.class); |
| fail(); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "com.google.crypto.tink.Mac"); |
| assertExceptionContains(e, "PublicPrimitiveA"); |
| assertExceptionContains(e, "PublicPrimitiveB"); |
| } |
| } |
| |
| // Checks that calling getUntypedKeyManager will return the keymanager for the *first* implemented |
| // class in the constructor. |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getUntypedPrivateKeyManager_returnsPrimitiveA() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyManager<?> km = Registry.getUntypedKeyManager(new TestPrivateKeyTypeManager().getKeyType()); |
| assertThat(km.getPrimitiveClass()).isEqualTo(PrivatePrimitiveA.class); |
| } |
| |
| // Checks that calling getUntypedKeyManager will return the keymanager for the *first* implemented |
| // class in the constructor. |
| @Test |
| public void testRegisterAssymmetricKeyManagers_getUntypedPublicKeyManager_returnsPrimitiveA() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyManager<?> km = Registry.getUntypedKeyManager(new TestPublicKeyTypeManager().getKeyType()); |
| assertThat(km.getPrimitiveClass()).isEqualTo(PublicPrimitiveA.class); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_MoreRestrictedNewKeyAllowed_shouldWork() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), false); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_SameNewKeyAllowed_shouldWork() throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), false); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), false); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_LessRestrictedNewKeyAllowed_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), false); |
| try { |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_PublicKeyManagerCanBeRegisteredAlone() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestPublicKeyTypeManager(), false); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| Registry.registerKeyManager(new TestPublicKeyTypeManager(), false); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_PublicKeyManagerReRegister_getPublicKeyData() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerKeyManager(new TestPublicKeyTypeManager(), false); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| Registry.registerKeyManager(new TestPublicKeyTypeManager(), false); |
| |
| // Check that getPublicKeyData works now. |
| Ed25519PrivateKey privateKey = |
| Ed25519PrivateKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom(Random.randBytes(32))) |
| .setPublicKey( |
| Ed25519PublicKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom(Random.randBytes(32)))) |
| .build(); |
| KeyData publicKeyData = |
| Registry.getPublicKeyData( |
| new TestPrivateKeyTypeManager().getKeyType(), privateKey.toByteString()); |
| assertThat(publicKeyData.getTypeUrl()).isEqualTo(new TestPublicKeyTypeManager().getKeyType()); |
| Ed25519PublicKey publicKey = |
| Ed25519PublicKey.parseFrom( |
| publicKeyData.getValue(), ExtensionRegistryLite.getEmptyRegistry()); |
| assertThat(publicKey.getKeyValue()).isEqualTo(privateKey.getPublicKey().getKeyValue()); |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_DifferentClassPrivateKey_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| // Note: due to the {} this is a subclass of TestPrivateKeyTypeManager. |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager() {}, new TestPublicKeyTypeManager(), true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_DifferentClassPublicKey_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| // Note: due to the {} this is a subclass of TestPublicKeyTypeManager. |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager() {}, true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_thenNormalRegister_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| // Note: due to the {} this is a subclass. |
| Registry.registerKeyManager(new TestPrivateKeyTypeManager() {}, true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_thenNormalRegisterForPublic_throws() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| // Note: due to the {} this is a subclass. |
| Registry.registerKeyManager(new TestPublicKeyTypeManager() {}, true); |
| fail("Expected GeneralSecurityException"); |
| } catch (GeneralSecurityException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testRegisterAssymmetricKeyManagers_ThrowsWithDifferentPublicKeyManager() |
| throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| try { |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), |
| new TestPublicKeyTypeManager() { |
| @Override |
| public String getKeyType() { |
| return "bla"; |
| } |
| }, |
| true); |
| fail(); |
| } catch (GeneralSecurityException e) { |
| // Expected. |
| assertExceptionContains(e, "public key manager corresponding to"); |
| } |
| } |
| |
| @Test |
| public void testAsymmetricKeyManagers_deriveKey_withoutKeyFactory() throws Exception { |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| new TestPrivateKeyTypeManager(), new TestPublicKeyTypeManager(), true); |
| KeyTemplate template = |
| KeyTemplate.newBuilder() |
| .setValue(Ed25519KeyFormat.getDefaultInstance().toByteString()) |
| .setTypeUrl(new TestPrivateKeyTypeManager().getKeyType()) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build(); |
| |
| try { |
| Registry.deriveKey(template, new ByteArrayInputStream(new byte[0])); |
| fail(); |
| } catch (UnsupportedOperationException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testAsymmetricKeyManagers_deriveKey() throws Exception { |
| TestPrivateKeyTypeManager testPrivateKeyTypeManagerWithDeriveKey = |
| new TestPrivateKeyTypeManager() { |
| @Override |
| public KeyFactory<Ed25519KeyFormat, Ed25519PrivateKey> keyFactory() { |
| return new KeyFactory<Ed25519KeyFormat, Ed25519PrivateKey>(Ed25519KeyFormat.class) { |
| @Override |
| public void validateKeyFormat(Ed25519KeyFormat format) |
| throws GeneralSecurityException {} |
| |
| @Override |
| public Ed25519KeyFormat parseKeyFormat(ByteString byteString) |
| throws InvalidProtocolBufferException { |
| return Ed25519KeyFormat.parseFrom( |
| byteString, ExtensionRegistryLite.getEmptyRegistry()); |
| } |
| |
| @Override |
| public Ed25519PrivateKey createKey(Ed25519KeyFormat format) |
| throws GeneralSecurityException { |
| return Ed25519PrivateKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom("created", UTF_8)) |
| .build(); |
| } |
| |
| @Override |
| public Ed25519PrivateKey deriveKey(Ed25519KeyFormat format, InputStream inputStream) |
| throws GeneralSecurityException { |
| return Ed25519PrivateKey.newBuilder() |
| .setKeyValue(ByteString.copyFrom("derived", UTF_8)) |
| .build(); |
| } |
| }; |
| } |
| }; |
| |
| Registry.reset(); |
| Registry.registerAsymmetricKeyManagers( |
| testPrivateKeyTypeManagerWithDeriveKey, new TestPublicKeyTypeManager(), true); |
| KeyTemplate template = KeyTemplate.newBuilder() |
| .setValue(Ed25519KeyFormat.getDefaultInstance().toByteString()) |
| .setTypeUrl(testPrivateKeyTypeManagerWithDeriveKey.getKeyType()) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build(); |
| |
| KeyData keyData = Registry.deriveKey(template, new ByteArrayInputStream(new byte[0])); |
| Ed25519PrivateKey key = |
| Ed25519PrivateKey.parseFrom(keyData.getValue(), ExtensionRegistryLite.getEmptyRegistry()); |
| assertThat(key.getKeyValue()).isEqualTo(ByteString.copyFrom("derived", UTF_8)); |
| } |
| |
| private static class Catalogue1 implements Catalogue<Aead> { |
| @Override |
| public KeyManager<Aead> getKeyManager(String typeUrl, String primitiveName, int minVersion) { |
| return null; |
| } |
| |
| @Override |
| public PrimitiveWrapper<Aead> getPrimitiveWrapper() { |
| return null; |
| } |
| } |
| |
| private static class Catalogue2 implements Catalogue<Aead> { |
| @Override |
| public KeyManager<Aead> getKeyManager(String typeUrl, String primitiveName, int minVersion) { |
| return null; |
| } |
| |
| @Override |
| public PrimitiveWrapper<Aead> getPrimitiveWrapper() { |
| return null; |
| } |
| } |
| |
| private static class Catalogue3 implements Catalogue<Aead> { |
| @Override |
| public KeyManager<Aead> getKeyManager(String typeUrl, String primitiveName, int minVersion) { |
| return null; |
| } |
| |
| @Override |
| public PrimitiveWrapper<Aead> getPrimitiveWrapper() { |
| return null; |
| } |
| } |
| |
| @Test |
| public void testAddCatalogue_MultiThreads_shouldWork() throws Exception { |
| final boolean[] threwException = new boolean[3]; |
| Thread thread1 = |
| new Thread( |
| new Runnable() { |
| @Override |
| public void run() { |
| try { |
| Registry.addCatalogue("catalogue", new Catalogue1()); |
| threwException[0] = false; |
| } catch (GeneralSecurityException e) { |
| threwException[0] = true; |
| } |
| } |
| }); |
| Thread thread2 = |
| new Thread( |
| new Runnable() { |
| @Override |
| public void run() { |
| try { |
| Registry.addCatalogue("catalogue", new Catalogue2()); |
| threwException[1] = false; |
| } catch (GeneralSecurityException e) { |
| threwException[1] = true; |
| } |
| } |
| }); |
| Thread thread3 = |
| new Thread( |
| new Runnable() { |
| @Override |
| public void run() { |
| try { |
| Registry.addCatalogue("catalogue", new Catalogue3()); |
| threwException[2] = false; |
| } catch (GeneralSecurityException e) { |
| threwException[2] = true; |
| } |
| } |
| }); |
| |
| // Start the threads. |
| thread1.start(); |
| thread2.start(); |
| thread3.start(); |
| |
| // Wait until all threads finished. |
| thread1.join(); |
| thread2.join(); |
| thread3.join(); |
| |
| // Count threads that threw exception. |
| int count = 0; |
| for (int i = 0; i < 3; i++) { |
| if (threwException[i]) { |
| count++; |
| } |
| } |
| |
| assertThat(count).isEqualTo(2); |
| } |
| // TODO(przydatek): Add more tests for creation of PrimitiveSets. |
| |
| @Test |
| public void testWrap_wrapperRegistered() throws Exception { |
| KeyData key = Registry.newKeyData(AeadKeyTemplates.AES128_EAX); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(1) |
| .build()); |
| |
| // Get a PrimitiveSet using a custom key manager for key1. |
| KeyManager<Aead> customManager = new CustomAeadKeyManager(AeadConfig.AES_EAX_TYPE_URL); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, customManager, Aead.class); |
| Registry.wrap(aeadSet); |
| } |
| |
| @Test |
| public void testWrap_noWrapperRegistered_throws() throws Exception { |
| KeyData key = Registry.newKeyData(AeadKeyTemplates.AES128_EAX); |
| Registry.reset(); |
| KeysetHandle keysetHandle = |
| KeysetHandle.fromKeyset( |
| Keyset.newBuilder() |
| .addKey( |
| Keyset.Key.newBuilder() |
| .setKeyData(key) |
| .setKeyId(1) |
| .setStatus(KeyStatusType.ENABLED) |
| .setOutputPrefixType(OutputPrefixType.TINK) |
| .build()) |
| .setPrimaryKeyId(1) |
| .build()); |
| |
| // Get a PrimitiveSet using a custom key manager for key1. |
| KeyManager<Aead> customManager = new CustomAeadKeyManager(AeadConfig.AES_EAX_TYPE_URL); |
| PrimitiveSet<Aead> aeadSet = Registry.getPrimitives(keysetHandle, customManager, Aead.class); |
| try { |
| Registry.wrap(aeadSet); |
| fail("Expected GeneralSecurityException."); |
| } catch (GeneralSecurityException e) { |
| assertExceptionContains(e, "No wrapper found"); |
| assertExceptionContains(e, "Aead"); |
| } |
| } |
| |
| private static class FakeAead {} |
| } |