1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.aead; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.crypto.tink.internal.Util.isPrefix; 21 import static org.junit.Assert.assertThrows; 22 23 import com.google.crypto.tink.Aead; 24 import com.google.crypto.tink.KeysetHandle; 25 import com.google.crypto.tink.KmsClients; 26 import com.google.crypto.tink.RegistryConfiguration; 27 import com.google.crypto.tink.TinkProtoKeysetFormat; 28 import com.google.crypto.tink.internal.KeyManagerRegistry; 29 import com.google.crypto.tink.subtle.Random; 30 import com.google.crypto.tink.testing.FakeKmsClient; 31 import com.google.crypto.tink.testing.TestUtil; 32 import java.security.GeneralSecurityException; 33 import java.util.Arrays; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 /** Tests for KmsAeadKeyManager. */ 40 @RunWith(JUnit4.class) 41 public class KmsAeadKeyManagerTest { 42 @Before setUp()43 public void setUp() throws Exception { 44 KmsClients.add(new FakeKmsClient()); 45 AeadConfig.register(); 46 } 47 48 @Test testKeyManagerRegistered()49 public void testKeyManagerRegistered() throws Exception { 50 assertThat( 51 KeyManagerRegistry.globalInstance() 52 .getKeyManager("type.googleapis.com/google.crypto.tink.KmsAeadKey", Aead.class)) 53 .isNotNull(); 54 } 55 56 @Test testKmsAead_success()57 public void testKmsAead_success() throws Exception { 58 String keyUri = FakeKmsClient.createFakeKeyUri(); 59 KeysetHandle keysetHandle = 60 KeysetHandle.generateNew(KmsAeadKeyManager.createKeyTemplate(keyUri)); 61 TestUtil.runBasicAeadTests(keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class)); 62 } 63 64 @Test createAeadFromLegacyKmsAeadKey_works()65 public void createAeadFromLegacyKmsAeadKey_works() throws Exception { 66 String keyUri = FakeKmsClient.createFakeKeyUri(); 67 LegacyKmsAeadParameters parameters = LegacyKmsAeadParameters.create(keyUri); 68 LegacyKmsAeadKey key = LegacyKmsAeadKey.create(parameters); 69 KeysetHandle keysetHandle = 70 KeysetHandle.newBuilder() 71 .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary()) 72 .build(); 73 74 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 75 TestUtil.runBasicAeadTests(aead); 76 77 Aead clientAead = new FakeKmsClient().getAead(keyUri); 78 byte[] plaintext = Random.randBytes(20); 79 byte[] associatedData = Random.randBytes(20); 80 byte[] ciphertext = aead.encrypt(plaintext, associatedData); 81 byte[] decrypted = clientAead.decrypt(ciphertext, associatedData); 82 assertThat(decrypted).isEqualTo(plaintext); 83 } 84 85 @Test createAeadFromLegacyKmsAeadKeyWithTinkPrefix_works()86 public void createAeadFromLegacyKmsAeadKeyWithTinkPrefix_works() throws Exception { 87 String keyUri = FakeKmsClient.createFakeKeyUri(); 88 LegacyKmsAeadParameters parameters = 89 LegacyKmsAeadParameters.create(keyUri, LegacyKmsAeadParameters.Variant.TINK); 90 LegacyKmsAeadKey key = LegacyKmsAeadKey.create(parameters, 0x11223344); 91 KeysetHandle keysetHandle = 92 KeysetHandle.newBuilder() 93 .addEntry(KeysetHandle.importKey(key).withFixedId(0x11223344).makePrimary()) 94 .build(); 95 96 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 97 TestUtil.runBasicAeadTests(aead); 98 99 byte[] plaintext = Random.randBytes(20); 100 byte[] associatedData = Random.randBytes(20); 101 byte[] ciphertext = aead.encrypt(plaintext, associatedData); 102 assertThat( 103 isPrefix( 104 new byte[] {(byte) 0x01, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44}, 105 ciphertext)) 106 .isTrue(); 107 108 Aead clientAead = new FakeKmsClient().getAead(keyUri); 109 // test that clientAead can decrypt ciphertext if the 5 byte prefix is removed. 110 byte[] ciphertextWithoutPrefix = Arrays.copyOfRange(ciphertext, 5, ciphertext.length); 111 byte[] decrypted = clientAead.decrypt(ciphertextWithoutPrefix, associatedData); 112 assertThat(decrypted).isEqualTo(plaintext); 113 } 114 115 @Test createAeadInvalidUri_throws()116 public void createAeadInvalidUri_throws() throws Exception { 117 LegacyKmsAeadParameters parameters = LegacyKmsAeadParameters.create("wrong uri"); 118 LegacyKmsAeadKey key = LegacyKmsAeadKey.create(parameters); 119 KeysetHandle keysetHandle = 120 KeysetHandle.newBuilder() 121 .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary()) 122 .build(); 123 124 assertThrows( 125 GeneralSecurityException.class, 126 () -> keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class)); 127 } 128 129 @Test createKeyTemplateGenerateNewGetPrimitive_isSameAs_clientGetAead()130 public void createKeyTemplateGenerateNewGetPrimitive_isSameAs_clientGetAead() 131 throws Exception { 132 String keyUri = FakeKmsClient.createFakeKeyUri(); 133 134 // Create Aead primitive using createKeyTemplate, generateNew, and getPrimitive. 135 // This requires that a KmsClient that supports keyUri is registered. 136 KeysetHandle keysetHandle = 137 KeysetHandle.generateNew(KmsAeadKeyManager.createKeyTemplate(keyUri)); 138 Aead aead1 = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 139 140 // Create Aead using FakeKmsClient.getAead. 141 // No KmsClient needs to be registered. 142 Aead aead2 = new FakeKmsClient().getAead(keyUri); 143 144 // Test that aead1 and aead2 are the same. 145 byte[] plaintext = Random.randBytes(20); 146 byte[] associatedData = Random.randBytes(20); 147 byte[] ciphertext = aead1.encrypt(plaintext, associatedData); 148 byte[] decrypted = aead2.decrypt(ciphertext, associatedData); 149 assertThat(decrypted).isEqualTo(plaintext); 150 } 151 152 @Test createKeyTemplate()153 public void createKeyTemplate() throws Exception { 154 String keyUri = "some example KEK URI"; 155 assertThat(KmsAeadKeyManager.createKeyTemplate(keyUri).toParameters()) 156 .isEqualTo(LegacyKmsAeadParameters.create(keyUri)); 157 } 158 159 @Test generateNewFromParams_works()160 public void generateNewFromParams_works() throws Exception { 161 LegacyKmsAeadParameters parameters = LegacyKmsAeadParameters.create("some example KEK URI"); 162 KeysetHandle keysetHandle1 = KeysetHandle.generateNew(parameters); 163 KeysetHandle keysetHandle2 = KeysetHandle.generateNew(parameters); 164 // For LegacyKmsAeadParameters we expect both keysets to be the same -- however, the ID of the 165 // keys may differ. 166 assertThat(keysetHandle1.getAt(0).getKey().equalsKey(keysetHandle2.getAt(0).getKey())).isTrue(); 167 } 168 169 @Test serializeAndParse_works()170 public void serializeAndParse_works() throws Exception { 171 LegacyKmsAeadParameters parameters = LegacyKmsAeadParameters.create("some example KEK URI"); 172 KeysetHandle keysetHandle1 = KeysetHandle.generateNew(parameters); 173 byte[] serialized = TinkProtoKeysetFormat.serializeKeysetWithoutSecret(keysetHandle1); 174 KeysetHandle keysetHandle2 = TinkProtoKeysetFormat.parseKeysetWithoutSecret(serialized); 175 assertThat(keysetHandle1.equalsKeyset(keysetHandle2)).isTrue(); 176 } 177 } 178