diff --git a/java/src/main/java/com/google/crypto/tink/KeyTypeManager.java b/java/src/main/java/com/google/crypto/tink/KeyTypeManager.java index 934ca845168f58438fe25313e902095062b76d92..17c28748dfc821872ee2fdebfcf40634450b5a95 100644 --- a/java/src/main/java/com/google/crypto/tink/KeyTypeManager.java +++ b/java/src/main/java/com/google/crypto/tink/KeyTypeManager.java @@ -173,7 +173,7 @@ public abstract class KeyTypeManager<KeyProtoT extends MessageLite> { * be able to generate keys. In particular, in this case it needs to have some KeyFormat protocol * buffer which can be validated, parsed, and from which a key can be generated. */ - protected abstract static class KeyFactory<KeyFormatProtoT extends MessageLite, KeyT> { + public abstract static class KeyFactory<KeyFormatProtoT extends MessageLite, KeyT> { private final Class<KeyFormatProtoT> clazz; public KeyFactory(Class<KeyFormatProtoT> clazz) { this.clazz = clazz; diff --git a/java/src/main/java/com/google/crypto/tink/aead/AeadConfig.java b/java/src/main/java/com/google/crypto/tink/aead/AeadConfig.java index 44200496ea0a6232d8910d1b3c041072596c99e0..58e3450b00baeef72100bdd046129262d1b58cf1 100644 --- a/java/src/main/java/com/google/crypto/tink/aead/AeadConfig.java +++ b/java/src/main/java/com/google/crypto/tink/aead/AeadConfig.java @@ -35,7 +35,7 @@ import java.security.GeneralSecurityException; */ public final class AeadConfig { public static final String AES_CTR_HMAC_AEAD_TYPE_URL = AesCtrHmacAeadKeyManager.TYPE_URL; - public static final String AES_GCM_TYPE_URL = AesGcmKeyManager.TYPE_URL; + public static final String AES_GCM_TYPE_URL = new AesGcmKeyManager().getKeyType(); public static final String AES_EAX_TYPE_URL = AesEaxKeyManager.TYPE_URL; public static final String KMS_AEAD_TYPE_URL = KmsAeadKeyManager.TYPE_URL; public static final String KMS_ENVELOPE_AEAD_TYPE_URL = KmsEnvelopeAeadKeyManager.TYPE_URL; @@ -98,7 +98,7 @@ public final class AeadConfig { MacConfig.register(); Registry.registerKeyManager(new AesCtrHmacAeadKeyManager()); Registry.registerKeyManager(new AesEaxKeyManager()); - Registry.registerKeyManager(new AesGcmKeyManager()); + Registry.registerKeyManager(new AesGcmKeyManager(), true); Registry.registerKeyManager(new ChaCha20Poly1305KeyManager()); Registry.registerKeyManager(new KmsAeadKeyManager()); Registry.registerKeyManager(new KmsEnvelopeAeadKeyManager()); diff --git a/java/src/main/java/com/google/crypto/tink/aead/AeadKeyTemplates.java b/java/src/main/java/com/google/crypto/tink/aead/AeadKeyTemplates.java index d9aeb0171bbff81c857d640fd4181178a97d8c67..abb79c10f5c2d16c3f4cd5fce1c101e45d38d8eb 100644 --- a/java/src/main/java/com/google/crypto/tink/aead/AeadKeyTemplates.java +++ b/java/src/main/java/com/google/crypto/tink/aead/AeadKeyTemplates.java @@ -160,7 +160,7 @@ public final class AeadKeyTemplates { .build(); return KeyTemplate.newBuilder() .setValue(format.toByteString()) - .setTypeUrl(AesGcmKeyManager.TYPE_URL) + .setTypeUrl(new AesGcmKeyManager().getKeyType()) .setOutputPrefixType(OutputPrefixType.TINK) .build(); } diff --git a/java/src/main/java/com/google/crypto/tink/aead/AesGcmKeyManager.java b/java/src/main/java/com/google/crypto/tink/aead/AesGcmKeyManager.java index c7aa4f3ebc5c3d2853836b0b120f541ca1d1d75a..0374bea77a315fdd491061a479118f42803bdf95 100644 --- a/java/src/main/java/com/google/crypto/tink/aead/AesGcmKeyManager.java +++ b/java/src/main/java/com/google/crypto/tink/aead/AesGcmKeyManager.java @@ -17,7 +17,7 @@ package com.google.crypto.tink.aead; import com.google.crypto.tink.Aead; -import com.google.crypto.tink.KeyManagerBase; +import com.google.crypto.tink.KeyTypeManager; import com.google.crypto.tink.proto.AesGcmKey; import com.google.crypto.tink.proto.AesGcmKeyFormat; import com.google.crypto.tink.proto.KeyData.KeyMaterialType; @@ -32,27 +32,23 @@ import java.security.GeneralSecurityException; * This key manager generates new {@code AesGcmKey} keys and produces new instances of {@code * AesGcmJce}. */ -class AesGcmKeyManager extends KeyManagerBase<Aead, AesGcmKey, AesGcmKeyFormat> { +class AesGcmKeyManager extends KeyTypeManager<AesGcmKey> { public AesGcmKeyManager() { - super(Aead.class, AesGcmKey.class, AesGcmKeyFormat.class, TYPE_URL); + super( + AesGcmKey.class, + new PrimitiveFactory<Aead, AesGcmKey>(Aead.class) { + @Override + public Aead getPrimitive(AesGcmKey key) throws GeneralSecurityException { + return new AesGcmJce(key.getKeyValue().toByteArray()); + } + }); } private static final int VERSION = 0; - public static final String TYPE_URL = "type.googleapis.com/google.crypto.tink.AesGcmKey"; - - /** @param key {@code AesGcmKey} proto */ - @Override - protected Aead getPrimitiveFromKey(AesGcmKey key) throws GeneralSecurityException { - return new AesGcmJce(key.getKeyValue().toByteArray()); - } - @Override - protected AesGcmKey newKeyFromFormat(AesGcmKeyFormat format) throws GeneralSecurityException { - return AesGcmKey.newBuilder() - .setKeyValue(ByteString.copyFrom(Random.randBytes(format.getKeySize()))) - .setVersion(VERSION) - .build(); + public String getKeyType() { + return "type.googleapis.com/google.crypto.tink.AesGcmKey"; } @Override @@ -61,30 +57,42 @@ class AesGcmKeyManager extends KeyManagerBase<Aead, AesGcmKey, AesGcmKeyFormat> } @Override - protected KeyMaterialType keyMaterialType() { + public KeyMaterialType keyMaterialType() { return KeyMaterialType.SYMMETRIC; } @Override - protected AesGcmKey parseKeyProto(ByteString byteString) - throws InvalidProtocolBufferException { - return AesGcmKey.parseFrom(byteString); + public void validateKey(AesGcmKey key) throws GeneralSecurityException { + Validators.validateVersion(key.getVersion(), getVersion()); + Validators.validateAesKeySize(key.getKeyValue().size()); } @Override - protected AesGcmKeyFormat parseKeyFormatProto(ByteString byteString) - throws InvalidProtocolBufferException { - return AesGcmKeyFormat.parseFrom(byteString); + public AesGcmKey parseKey(ByteString byteString) throws InvalidProtocolBufferException { + return AesGcmKey.parseFrom(byteString); } @Override - protected void validateKey(AesGcmKey key) throws GeneralSecurityException { - Validators.validateVersion(key.getVersion(), VERSION); - Validators.validateAesKeySize(key.getKeyValue().size()); - } + public KeyFactory<AesGcmKeyFormat, AesGcmKey> keyFactory() { + return new KeyFactory<AesGcmKeyFormat, AesGcmKey>(AesGcmKeyFormat.class) { + @Override + public void validateKeyFormat(AesGcmKeyFormat format) throws GeneralSecurityException { + Validators.validateAesKeySize(format.getKeySize()); + } - @Override - protected void validateKeyFormat(AesGcmKeyFormat format) throws GeneralSecurityException { - Validators.validateAesKeySize(format.getKeySize()); + @Override + public AesGcmKeyFormat parseKeyFormat(ByteString byteString) + throws InvalidProtocolBufferException { + return AesGcmKeyFormat.parseFrom(byteString); + } + + @Override + public AesGcmKey createKey(AesGcmKeyFormat format) throws GeneralSecurityException { + return AesGcmKey.newBuilder() + .setKeyValue(ByteString.copyFrom(Random.randBytes(format.getKeySize()))) + .setVersion(VERSION) + .build(); + } + }; } } diff --git a/java/src/test/java/com/google/crypto/tink/aead/AeadKeyTemplatesTest.java b/java/src/test/java/com/google/crypto/tink/aead/AeadKeyTemplatesTest.java index 8cc63831f0f850611142899439151bd517bccd41..b1813a8fe7981d76415719424c1dc940898cda52 100644 --- a/java/src/test/java/com/google/crypto/tink/aead/AeadKeyTemplatesTest.java +++ b/java/src/test/java/com/google/crypto/tink/aead/AeadKeyTemplatesTest.java @@ -37,7 +37,7 @@ public class AeadKeyTemplatesTest { @Test public void testAES128_GCM() throws Exception { KeyTemplate template = AeadKeyTemplates.AES128_GCM; - assertEquals(AesGcmKeyManager.TYPE_URL, template.getTypeUrl()); + assertEquals(new AesGcmKeyManager().getKeyType(), template.getTypeUrl()); assertEquals(OutputPrefixType.TINK, template.getOutputPrefixType()); AesGcmKeyFormat format = AesGcmKeyFormat.parseFrom(template.getValue()); assertEquals(16, format.getKeySize()); @@ -46,7 +46,7 @@ public class AeadKeyTemplatesTest { @Test public void testAES256_GCM() throws Exception { KeyTemplate template = AeadKeyTemplates.AES256_GCM; - assertEquals(AesGcmKeyManager.TYPE_URL, template.getTypeUrl()); + assertEquals(new AesGcmKeyManager().getKeyType(), template.getTypeUrl()); assertEquals(OutputPrefixType.TINK, template.getOutputPrefixType()); AesGcmKeyFormat format = AesGcmKeyFormat.parseFrom(template.getValue()); assertEquals(32, format.getKeySize()); @@ -58,7 +58,7 @@ public class AeadKeyTemplatesTest { // to test that the function correctly puts them in the resulting template. int keySize = 42; KeyTemplate template = AeadKeyTemplates.createAesGcmKeyTemplate(keySize); - assertEquals(AesGcmKeyManager.TYPE_URL, template.getTypeUrl()); + assertEquals(new AesGcmKeyManager().getKeyType(), template.getTypeUrl()); assertEquals(OutputPrefixType.TINK, template.getOutputPrefixType()); AesGcmKeyFormat format = AesGcmKeyFormat.parseFrom(template.getValue()); diff --git a/java/src/test/java/com/google/crypto/tink/aead/AesGcmKeyManagerTest.java b/java/src/test/java/com/google/crypto/tink/aead/AesGcmKeyManagerTest.java index 407a0d27bc9858a3d985a023690a1ae2f01b8908..42212436ea982c365b492fbe73fb5fd4e32a6060 100644 --- a/java/src/test/java/com/google/crypto/tink/aead/AesGcmKeyManagerTest.java +++ b/java/src/test/java/com/google/crypto/tink/aead/AesGcmKeyManagerTest.java @@ -16,27 +16,20 @@ package com.google.crypto.tink.aead; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import com.google.crypto.tink.Aead; -import com.google.crypto.tink.CryptoFormat; -import com.google.crypto.tink.KeysetHandle; import com.google.crypto.tink.TestUtil; import com.google.crypto.tink.proto.AesGcmKey; import com.google.crypto.tink.proto.AesGcmKeyFormat; -import com.google.crypto.tink.proto.KeyData; -import com.google.crypto.tink.proto.KeyStatusType; -import com.google.crypto.tink.proto.KeyTemplate; -import com.google.crypto.tink.proto.OutputPrefixType; import com.google.crypto.tink.subtle.Bytes; -import com.google.crypto.tink.subtle.Random; import com.google.protobuf.ByteString; import java.security.GeneralSecurityException; import java.util.Set; import java.util.TreeSet; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -44,62 +37,97 @@ import org.junit.runners.JUnit4; /** Test for AesGcmJce and its key manager. */ @RunWith(JUnit4.class) public class AesGcmKeyManagerTest { - @BeforeClass - public static void setUp() throws GeneralSecurityException { - AeadConfig.register(); + @Test + public void validateKeyFormat_empty() throws Exception { + try { + new AesGcmKeyManager().keyFactory().validateKeyFormat(AesGcmKeyFormat.getDefaultInstance()); + fail(); + } catch (GeneralSecurityException e) { + // expected. + } } @Test - public void testNewKeyMultipleTimes() throws Exception { - AesGcmKeyFormat gcmKeyFormat = - AesGcmKeyFormat.newBuilder() - .setKeySize(16) - .build(); - ByteString serialized = ByteString.copyFrom(gcmKeyFormat.toByteArray()); - KeyTemplate keyTemplate = - KeyTemplate.newBuilder().setTypeUrl(AesGcmKeyManager.TYPE_URL).setValue(serialized).build(); - AesGcmKeyManager keyManager = new AesGcmKeyManager(); - Set<String> keys = new TreeSet<String>(); - // Calls newKey multiple times and make sure that they generate different keys. - int numTests = 27; - for (int i = 0; i < numTests / 3; i++) { - AesGcmKey key = (AesGcmKey) keyManager.newKey(gcmKeyFormat); - keys.add(TestUtil.hexEncode(key.getKeyValue().toByteArray())); - assertEquals(16, key.getKeyValue().toByteArray().length); - - key = (AesGcmKey) keyManager.newKey(serialized); - keys.add(TestUtil.hexEncode(key.getKeyValue().toByteArray())); - assertEquals(16, key.getKeyValue().toByteArray().length); - - KeyData keyData = keyManager.newKeyData(keyTemplate.getValue()); - key = AesGcmKey.parseFrom(keyData.getValue()); - keys.add(TestUtil.hexEncode(key.getKeyValue().toByteArray())); - assertEquals(16, key.getKeyValue().toByteArray().length); - } - assertEquals(numTests, keys.size()); + public void validateKeyFormat_valid() throws Exception { + AesGcmKeyManager manager = new AesGcmKeyManager(); + manager.keyFactory().validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(16).build()); + manager.keyFactory().validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(32).build()); } @Test - public void testNewKeyWithCorruptedFormat() throws Exception { - ByteString serialized = ByteString.copyFrom(new byte[128]); - KeyTemplate keyTemplate = - KeyTemplate.newBuilder().setTypeUrl(AesGcmKeyManager.TYPE_URL).setValue(serialized).build(); - AesGcmKeyManager keyManager = new AesGcmKeyManager(); + public void validateKeyFormat_invalid() throws Exception { + AesGcmKeyManager.KeyFactory<AesGcmKeyFormat, AesGcmKey> factory = + new AesGcmKeyManager().keyFactory(); + try { + factory.validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(1).build()); + fail(); + } catch (GeneralSecurityException e) { + // expected. + } + try { + factory.validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(15).build()); + fail(); + } catch (GeneralSecurityException e) { + // expected. + } + try { + factory.validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(17).build()); + fail(); + } catch (GeneralSecurityException e) { + // expected. + } + try { + factory.validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(31).build()); + fail(); + } catch (GeneralSecurityException e) { + // expected. + } try { - keyManager.newKey(serialized); - fail("Corrupted format, should have thrown exception"); - } catch (GeneralSecurityException expected) { - // Expected + factory.validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(33).build()); + fail(); + } catch (GeneralSecurityException e) { + // expected. } try { - keyManager.newKeyData(keyTemplate.getValue()); - fail("Corrupted format, should have thrown exception"); - } catch (GeneralSecurityException expected) { - // Expected + factory.validateKeyFormat(AesGcmKeyFormat.newBuilder().setKeySize(64).build()); + fail(); + } catch (GeneralSecurityException e) { + // expected. } } - private static final int AES_KEY_SIZE = 16; + @Test + public void createKey_16Bytes() throws Exception { + AesGcmKey key = + new AesGcmKeyManager() + .keyFactory() + .createKey(AesGcmKeyFormat.newBuilder().setKeySize(16).build()); + assertThat(key.getKeyValue()).hasSize(16); + } + + @Test + public void createKey_32Bytes() throws Exception { + AesGcmKey key = + new AesGcmKeyManager() + .keyFactory() + .createKey(AesGcmKeyFormat.newBuilder().setKeySize(32).build()); + assertThat(key.getKeyValue()).hasSize(32); + } + + @Test + public void createKey_multipleTimes() throws Exception { + AesGcmKeyFormat gcmKeyFormat = AesGcmKeyFormat.newBuilder().setKeySize(16).build(); + + AesGcmKeyManager keyManager = new AesGcmKeyManager(); + Set<String> keys = new TreeSet<>(); + // Calls newKey multiple times and make sure that they generate different keys. + int numTests = 50; + for (int i = 0; i < numTests; i++) { + AesGcmKey key = keyManager.keyFactory().createKey(gcmKeyFormat); + keys.add(TestUtil.hexEncode(key.getKeyValue().toByteArray())); + } + assertEquals(numTests, keys.size()); + } private static class NistTestVector { String name; @@ -297,7 +325,8 @@ public class AesGcmKeyManagerTest { // We support only 12-byte IV and 16-byte tag. continue; } - Aead aead = getRawAesGcm(t.keyValue); + AesGcmKey key = AesGcmKey.newBuilder().setKeyValue(ByteString.copyFrom(t.keyValue)).build(); + Aead aead = new AesGcmKeyManager().getPrimitive(key, Aead.class); try { byte[] ciphertext = Bytes.concat(t.iv, t.ciphertext, t.tag); byte[] plaintext = aead.decrypt(ciphertext, t.aad); @@ -308,49 +337,17 @@ public class AesGcmKeyManagerTest { } } - private Aead getRawAesGcm(byte[] keyValue) throws Exception { - KeysetHandle keysetHandle = - TestUtil.createKeysetHandle( - TestUtil.createKeyset( - TestUtil.createKey( - TestUtil.createAesGcmKeyData(keyValue), - 42, - KeyStatusType.ENABLED, - OutputPrefixType.RAW))); - return keysetHandle.getPrimitive(Aead.class); - } - - @Test - public void testBasic() throws Exception { - byte[] keyValue = Random.randBytes(AES_KEY_SIZE); - KeysetHandle keysetHandle = - TestUtil.createKeysetHandle( - TestUtil.createKeyset( - TestUtil.createKey( - TestUtil.createAesGcmKeyData(keyValue), - 42, - KeyStatusType.ENABLED, - OutputPrefixType.TINK))); - TestUtil.runBasicAeadTests(keysetHandle.getPrimitive(Aead.class)); - } - @Test public void testCiphertextSize() throws Exception { - byte[] keyValue = Random.randBytes(AES_KEY_SIZE); - KeysetHandle keysetHandle = - TestUtil.createKeysetHandle( - TestUtil.createKeyset( - TestUtil.createKey( - TestUtil.createAesGcmKeyData(keyValue), - 42, - KeyStatusType.ENABLED, - OutputPrefixType.TINK))); - Aead aead = keysetHandle.getPrimitive(Aead.class); + AesGcmKey key = + new AesGcmKeyManager() + .keyFactory() + .createKey(AesGcmKeyFormat.newBuilder().setKeySize(32).build()); + Aead aead = new AesGcmKeyManager().getPrimitive(key, Aead.class); byte[] plaintext = "plaintext".getBytes("UTF-8"); byte[] associatedData = "associatedData".getBytes("UTF-8"); byte[] ciphertext = aead.encrypt(plaintext, associatedData); - assertEquals( - CryptoFormat.NON_RAW_PREFIX_SIZE + 12 /* IV_SIZE */ + plaintext.length + 16 /* TAG_SIZE */, - ciphertext.length); + assertThat(ciphertext.length) + .isEqualTo(12 /* IV_SIZE */ + plaintext.length + 16 /* TAG_SIZE */); } }