1 // Copyright 2017 Google LLC 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 21 import com.google.crypto.tink.InsecureSecretKeyAccess; 22 import com.google.crypto.tink.KeyTemplate; 23 import com.google.crypto.tink.KeyTemplates; 24 import com.google.crypto.tink.KeysetHandle; 25 import com.google.crypto.tink.Parameters; 26 import com.google.crypto.tink.RegistryConfiguration; 27 import com.google.crypto.tink.StreamingAead; 28 import com.google.crypto.tink.TinkProtoKeysetFormat; 29 import com.google.crypto.tink.internal.KeyManagerRegistry; 30 import com.google.crypto.tink.streamingaead.internal.testing.AesCtrHmacStreamingTestUtil; 31 import com.google.crypto.tink.streamingaead.internal.testing.StreamingAeadTestVector; 32 import com.google.crypto.tink.subtle.AesCtrHmacStreaming; 33 import com.google.crypto.tink.subtle.Hex; 34 import com.google.crypto.tink.testing.StreamingTestUtil; 35 import com.google.crypto.tink.testing.StreamingTestUtil.ByteBufferChannel; 36 import java.io.ByteArrayInputStream; 37 import java.io.InputStream; 38 import java.nio.ByteBuffer; 39 import java.nio.channels.ReadableByteChannel; 40 import java.util.Set; 41 import java.util.TreeSet; 42 import javax.annotation.Nullable; 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.experimental.theories.DataPoints; 46 import org.junit.experimental.theories.FromDataPoints; 47 import org.junit.experimental.theories.Theories; 48 import org.junit.experimental.theories.Theory; 49 import org.junit.runner.RunWith; 50 51 /** Test for AesCtrHmacStreamingKeyManager. */ 52 @RunWith(Theories.class) 53 public class AesCtrHmacStreamingKeyManagerTest { 54 @Before register()55 public void register() throws Exception { 56 StreamingAeadConfig.register(); 57 } 58 59 @Test testKeyManagerRegistered()60 public void testKeyManagerRegistered() throws Exception { 61 assertThat( 62 KeyManagerRegistry.globalInstance() 63 .getKeyManager( 64 "type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey", 65 StreamingAead.class)) 66 .isNotNull(); 67 } 68 69 @Test testSkip()70 public void testSkip() throws Exception { 71 Parameters parameters = 72 AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate().toParameters(); 73 KeysetHandle handle = KeysetHandle.generateNew(parameters); 74 StreamingAead streamingAead = 75 handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class); 76 77 int offset = 0; 78 int plaintextSize = 1 << 16; 79 // Runs the test with different sizes for the chunks to skip. 80 StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 1); 81 StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 64); 82 StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 300); 83 } 84 85 @Test createKey_multipleTimes_differentValues()86 public void createKey_multipleTimes_differentValues() throws Exception { 87 Parameters parameters = 88 AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate().toParameters(); 89 Set<String> keys = new TreeSet<>(); 90 // Calls newKey multiple times and make sure that they generate different keys. 91 int numTests = 100; 92 for (int i = 0; i < numTests; i++) { 93 KeysetHandle handle = KeysetHandle.generateNew(parameters); 94 com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey key = 95 (com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey) handle.getAt(0).getKey(); 96 keys.add(Hex.encode(key.getInitialKeyMaterial().toByteArray(InsecureSecretKeyAccess.get()))); 97 } 98 assertThat(keys).hasSize(numTests); 99 } 100 101 @Test getPrimitive_works()102 public void getPrimitive_works() throws Exception { 103 Parameters parameters = 104 AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate().toParameters(); 105 KeysetHandle handle = KeysetHandle.generateNew(parameters); 106 StreamingAead streamingAead = 107 handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class); 108 StreamingAead directAead = 109 AesCtrHmacStreaming.create( 110 (com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey) handle.getAt(0).getKey()); 111 112 StreamingTestUtil.testEncryptDecryptDifferentInstances( 113 streamingAead, directAead, 0, 2049, 1000); 114 } 115 116 @Test testAes128CtrHmacSha2564KBTemplate()117 public void testAes128CtrHmacSha2564KBTemplate() throws Exception { 118 KeyTemplate template = AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate(); 119 assertThat(template.toParameters()) 120 .isEqualTo( 121 AesCtrHmacStreamingParameters.builder() 122 .setKeySizeBytes(16) 123 .setDerivedKeySizeBytes(16) 124 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 125 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 126 .setHmacTagSizeBytes(32) 127 .setCiphertextSegmentSizeBytes(4 * 1024) 128 .build()); 129 } 130 131 @Test testAes128CtrHmacSha2561MBTemplate()132 public void testAes128CtrHmacSha2561MBTemplate() throws Exception { 133 KeyTemplate template = AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2561MBTemplate(); 134 assertThat(template.toParameters()) 135 .isEqualTo( 136 AesCtrHmacStreamingParameters.builder() 137 .setKeySizeBytes(16) 138 .setDerivedKeySizeBytes(16) 139 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 140 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 141 .setHmacTagSizeBytes(32) 142 .setCiphertextSegmentSizeBytes(1024 * 1024) 143 .build()); 144 } 145 146 @Test testAes256CtrHmacSha2564KBTemplate()147 public void testAes256CtrHmacSha2564KBTemplate() throws Exception { 148 KeyTemplate template = AesCtrHmacStreamingKeyManager.aes256CtrHmacSha2564KBTemplate(); 149 assertThat(template.toParameters()) 150 .isEqualTo( 151 AesCtrHmacStreamingParameters.builder() 152 .setKeySizeBytes(32) 153 .setDerivedKeySizeBytes(32) 154 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 155 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 156 .setHmacTagSizeBytes(32) 157 .setCiphertextSegmentSizeBytes(4 * 1024) 158 .build()); 159 } 160 161 @Test testAes256CtrHmacSha2561MBTemplate()162 public void testAes256CtrHmacSha2561MBTemplate() throws Exception { 163 KeyTemplate template = AesCtrHmacStreamingKeyManager.aes256CtrHmacSha2561MBTemplate(); 164 assertThat(template.toParameters()) 165 .isEqualTo( 166 AesCtrHmacStreamingParameters.builder() 167 .setKeySizeBytes(32) 168 .setDerivedKeySizeBytes(32) 169 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 170 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256) 171 .setHmacTagSizeBytes(32) 172 .setCiphertextSegmentSizeBytes(1024 * 1024) 173 .build()); 174 } 175 176 @DataPoints("templateNames") 177 public static final String[] KEY_TEMPLATES = 178 new String[] { 179 "AES128_CTR_HMAC_SHA256_4KB", 180 "AES128_CTR_HMAC_SHA256_1MB", 181 "AES256_CTR_HMAC_SHA256_4KB", 182 "AES256_CTR_HMAC_SHA256_1MB" 183 }; 184 185 @Theory testTemplates(@romDataPoints"templateNames") String templateName)186 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 187 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 188 assertThat(h.size()).isEqualTo(1); 189 assertThat(h.getAt(0).getKey().getParameters()) 190 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 191 } 192 193 @Test serializeAndParse_works()194 public void serializeAndParse_works() throws Exception { 195 Parameters parameters = 196 AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2561MBTemplate().toParameters(); 197 KeysetHandle handle = KeysetHandle.generateNew(parameters); 198 byte[] serializedHandle = 199 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()); 200 KeysetHandle parsedHandle = 201 TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get()); 202 assertThat(parsedHandle.equalsKeyset(handle)).isTrue(); 203 } 204 205 @DataPoints("testVectors") 206 public static final StreamingAeadTestVector[] streamingTestVector = 207 AesCtrHmacStreamingTestUtil.createAesCtrHmacTestVectors(); 208 209 @Theory decryptCiphertextInputStream_works( @romDataPoints"testVectors") StreamingAeadTestVector v)210 public void decryptCiphertextInputStream_works( 211 @FromDataPoints("testVectors") StreamingAeadTestVector v) throws Exception { 212 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getKey()).makePrimary(); 213 @Nullable Integer id = v.getKey().getIdRequirementOrNull(); 214 if (id == null) { 215 entry.withRandomId(); 216 } else { 217 entry.withFixedId(id); 218 } 219 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 220 StreamingAead streamingAead = 221 handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class); 222 InputStream plaintextStream = 223 streamingAead.newDecryptingStream( 224 new ByteArrayInputStream(v.getCiphertext()), v.getAssociatedData()); 225 byte[] decryption = new byte[v.getPlaintext().length]; 226 plaintextStream.read(decryption); 227 assertThat(decryption).isEqualTo(v.getPlaintext()); 228 } 229 230 @Theory decryptCiphertextChannel_works( @romDataPoints"testVectors") StreamingAeadTestVector v)231 public void decryptCiphertextChannel_works( 232 @FromDataPoints("testVectors") StreamingAeadTestVector v) throws Exception { 233 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getKey()).makePrimary(); 234 @Nullable Integer id = v.getKey().getIdRequirementOrNull(); 235 if (id == null) { 236 entry.withRandomId(); 237 } else { 238 entry.withFixedId(id); 239 } 240 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 241 StreamingAead streamingAead = 242 handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class); 243 ReadableByteChannel plaintextChannel = 244 streamingAead.newDecryptingChannel( 245 new ByteBufferChannel(v.getCiphertext()), v.getAssociatedData()); 246 ByteBuffer decryption = ByteBuffer.allocate(v.getPlaintext().length); 247 plaintextChannel.read(decryption); 248 assertThat(decryption.array()).isEqualTo(v.getPlaintext()); 249 } 250 } 251