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.streamingaead; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertTrue; 21 22 import com.google.crypto.tink.InsecureSecretKeyAccess; 23 import com.google.crypto.tink.Key; 24 import com.google.crypto.tink.KeyTemplate; 25 import com.google.crypto.tink.KeyTemplates; 26 import com.google.crypto.tink.KeysetHandle; 27 import com.google.crypto.tink.Parameters; 28 import com.google.crypto.tink.RegistryConfiguration; 29 import com.google.crypto.tink.StreamingAead; 30 import com.google.crypto.tink.TinkProtoKeysetFormat; 31 import com.google.crypto.tink.internal.KeyManagerRegistry; 32 import com.google.crypto.tink.internal.SlowInputStream; 33 import com.google.crypto.tink.keyderivation.KeyDerivationConfig; 34 import com.google.crypto.tink.keyderivation.KeysetDeriver; 35 import com.google.crypto.tink.keyderivation.PrfBasedKeyDerivationKey; 36 import com.google.crypto.tink.keyderivation.PrfBasedKeyDerivationParameters; 37 import com.google.crypto.tink.prf.HkdfPrfKey; 38 import com.google.crypto.tink.prf.HkdfPrfParameters; 39 import com.google.crypto.tink.subtle.AesGcmHkdfStreaming; 40 import com.google.crypto.tink.subtle.Hex; 41 import com.google.crypto.tink.testing.StreamingTestUtil; 42 import com.google.crypto.tink.util.SecretBytes; 43 import java.io.ByteArrayInputStream; 44 import java.util.Arrays; 45 import java.util.Set; 46 import java.util.TreeSet; 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.experimental.theories.DataPoints; 50 import org.junit.experimental.theories.FromDataPoints; 51 import org.junit.experimental.theories.Theories; 52 import org.junit.experimental.theories.Theory; 53 import org.junit.runner.RunWith; 54 55 /** Test for AesGcmHkdfStreamingKeyManager. */ 56 @RunWith(Theories.class) 57 public class AesGcmHkdfStreamingKeyManagerTest { 58 59 @Before register()60 public void register() throws Exception { 61 StreamingAeadConfig.register(); 62 KeyDerivationConfig.register(); 63 } 64 65 @Test testKeyManagerRegistered()66 public void testKeyManagerRegistered() throws Exception { 67 assertThat( 68 KeyManagerRegistry.globalInstance() 69 .getKeyManager( 70 "type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey", 71 StreamingAead.class)) 72 .isNotNull(); 73 } 74 75 @Test getPrimitive_works()76 public void getPrimitive_works() throws Exception { 77 Parameters parameters = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters(); 78 KeysetHandle handle = KeysetHandle.generateNew(parameters); 79 StreamingAead streamingAead = 80 handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class); 81 StreamingAead directAead = 82 AesGcmHkdfStreaming.create( 83 (com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey) handle.getAt(0).getKey()); 84 85 StreamingTestUtil.testEncryptDecryptDifferentInstances( 86 streamingAead, directAead, 0, 2049, 1000); 87 } 88 89 @Test testSkip()90 public void testSkip() throws Exception { 91 KeysetHandle handle = 92 KeysetHandle.generateNew( 93 AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters()); 94 StreamingAead streamingAead = 95 handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class); 96 int offset = 0; 97 int plaintextSize = 1 << 16; 98 // Runs the test with different sizes for the chunks to skip. 99 StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 1); 100 StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 64); 101 StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 300); 102 } 103 104 @Test testNewKeyMultipleTimes()105 public void testNewKeyMultipleTimes() throws Exception { 106 Parameters parameters = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters(); 107 Set<String> keys = new TreeSet<>(); 108 // Calls newKey multiple times and make sure that they generate different keys. 109 int numTests = 100; 110 for (int i = 0; i < numTests; i++) { 111 KeysetHandle handle = KeysetHandle.generateNew(parameters); 112 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey key = 113 (com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey) handle.getAt(0).getKey(); 114 keys.add(Hex.encode(key.getInitialKeyMaterial().toByteArray(InsecureSecretKeyAccess.get()))); 115 } 116 assertThat(keys).hasSize(numTests); 117 } 118 119 @Test testAes128GcmHkdf4KBTemplate()120 public void testAes128GcmHkdf4KBTemplate() throws Exception { 121 KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate(); 122 assertThat(template.toParameters()) 123 .isEqualTo( 124 AesGcmHkdfStreamingParameters.builder() 125 .setKeySizeBytes(16) 126 .setDerivedAesGcmKeySizeBytes(16) 127 .setCiphertextSegmentSizeBytes(4 * 1024) 128 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256) 129 .build()); 130 } 131 132 @Test testAes256GcmHkdf4KBTemplate()133 public void testAes256GcmHkdf4KBTemplate() throws Exception { 134 KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes256GcmHkdf4KBTemplate(); 135 assertThat(template.toParameters()) 136 .isEqualTo( 137 AesGcmHkdfStreamingParameters.builder() 138 .setKeySizeBytes(32) 139 .setDerivedAesGcmKeySizeBytes(32) 140 .setCiphertextSegmentSizeBytes(4 * 1024) 141 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256) 142 .build()); 143 } 144 145 @Test testAes128GcmHkdf1MBTemplate()146 public void testAes128GcmHkdf1MBTemplate() throws Exception { 147 KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf1MBTemplate(); 148 assertThat(template.toParameters()) 149 .isEqualTo( 150 AesGcmHkdfStreamingParameters.builder() 151 .setKeySizeBytes(16) 152 .setDerivedAesGcmKeySizeBytes(16) 153 .setCiphertextSegmentSizeBytes(1024 * 1024) 154 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256) 155 .build()); 156 } 157 158 @Test testAes256GcmHkdf1MBTemplate()159 public void testAes256GcmHkdf1MBTemplate() throws Exception { 160 KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes256GcmHkdf1MBTemplate(); 161 assertThat(template.toParameters()) 162 .isEqualTo( 163 AesGcmHkdfStreamingParameters.builder() 164 .setKeySizeBytes(32) 165 .setDerivedAesGcmKeySizeBytes(32) 166 .setCiphertextSegmentSizeBytes(1024 * 1024) 167 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256) 168 .build()); 169 } 170 171 @DataPoints("templateNames") 172 public static final String[] KEY_TEMPLATES = 173 new String[] { 174 "AES128_GCM_HKDF_4KB", "AES128_GCM_HKDF_1MB", "AES256_GCM_HKDF_4KB", "AES256_GCM_HKDF_1MB", 175 }; 176 177 @Theory testTemplates(@romDataPoints"templateNames") String templateName)178 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 179 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 180 assertThat(h.size()).isEqualTo(1); 181 assertThat(h.getAt(0).getKey().getParameters()) 182 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 183 } 184 185 @Theory testCreateKeyFromRandomness(@romDataPoints"templateNames") String templateName)186 public void testCreateKeyFromRandomness(@FromDataPoints("templateNames") String templateName) 187 throws Exception { 188 byte[] keyMaterial = 189 new byte[] { 190 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 191 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 192 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 193 }; 194 AesGcmHkdfStreamingParameters parameters = 195 (AesGcmHkdfStreamingParameters) KeyTemplates.get(templateName).toParameters(); 196 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey key = 197 AesGcmHkdfStreamingKeyManager.createAesGcmHkdfStreamingKeyFromRandomness( 198 parameters, new ByteArrayInputStream(keyMaterial), null, InsecureSecretKeyAccess.get()); 199 byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes()); 200 Key expectedKey = 201 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey.create( 202 parameters, SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get())); 203 assertTrue(key.equalsKey(expectedKey)); 204 } 205 206 @Test testCreateKeyFromRandomness_slowInputStream_works()207 public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception { 208 AesGcmHkdfStreamingParameters parameters = 209 AesGcmHkdfStreamingParameters.builder() 210 .setKeySizeBytes(16) 211 .setDerivedAesGcmKeySizeBytes(16) 212 .setCiphertextSegmentSizeBytes(1024 * 1024) 213 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256) 214 .build(); 215 216 byte[] keyMaterial = 217 new byte[] { 218 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 219 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 220 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 221 }; 222 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey key = 223 AesGcmHkdfStreamingKeyManager.createAesGcmHkdfStreamingKeyFromRandomness( 224 parameters, SlowInputStream.copyFrom(keyMaterial), null, InsecureSecretKeyAccess.get()); 225 byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes()); 226 Key expectedKey = 227 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey.create( 228 parameters, SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get())); 229 assertTrue(key.equalsKey(expectedKey)); 230 } 231 232 @Test deriveKeyset_isAsExpected()233 public void deriveKeyset_isAsExpected() throws Exception { 234 HkdfPrfKey prfKey = 235 HkdfPrfKey.builder() 236 .setParameters( 237 HkdfPrfParameters.builder() 238 .setKeySizeBytes(32) 239 .setHashType(HkdfPrfParameters.HashType.SHA256) 240 .build()) 241 .setKeyBytes( 242 SecretBytes.copyFrom( 243 Hex.decode("0102030405060708091011121314151617181920212123242526272829303132"), 244 InsecureSecretKeyAccess.get())) 245 .build(); 246 247 PrfBasedKeyDerivationParameters derivationParameters = 248 PrfBasedKeyDerivationParameters.builder() 249 .setDerivedKeyParameters(PredefinedStreamingAeadParameters.AES256_GCM_HKDF_1MB) 250 .setPrfParameters(prfKey.getParameters()) 251 .build(); 252 253 PrfBasedKeyDerivationKey keyDerivationKey = 254 PrfBasedKeyDerivationKey.create(derivationParameters, prfKey, /* idRequirement= */ null); 255 KeysetHandle keyset = 256 KeysetHandle.newBuilder() 257 .addEntry(KeysetHandle.importKey(keyDerivationKey).withFixedId(789789).makePrimary()) 258 .build(); 259 KeysetDeriver deriver = keyset.getPrimitive(RegistryConfiguration.get(), KeysetDeriver.class); 260 261 KeysetHandle derivedKeyset = deriver.deriveKeyset(Hex.decode("000102")); 262 263 assertThat(derivedKeyset.size()).isEqualTo(1); 264 // The only thing which we need to test is equalsKey(), but we first test other things to make 265 // test failures have nicer messages. 266 assertThat(derivedKeyset.getAt(0).getKey().getParameters()) 267 .isEqualTo(derivationParameters.getDerivedKeyParameters()); 268 assertTrue( 269 derivedKeyset 270 .getAt(0) 271 .getKey() 272 .equalsKey( 273 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey.create( 274 PredefinedStreamingAeadParameters.AES256_GCM_HKDF_1MB, 275 SecretBytes.copyFrom( 276 Hex.decode( 277 "94e397d674deda6e965295698491a3feb69838a35f1d48143f3c4cbad90eeb24"), 278 InsecureSecretKeyAccess.get())))); 279 } 280 281 @Test serializeAndParse_works()282 public void serializeAndParse_works() throws Exception { 283 Parameters parameters = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters(); 284 KeysetHandle handle = KeysetHandle.generateNew(parameters); 285 byte[] serializedHandle = 286 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()); 287 KeysetHandle parsedHandle = 288 TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get()); 289 assertThat(parsedHandle.equalsKeyset(handle)).isTrue(); 290 } 291 } 292