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 java.nio.charset.StandardCharsets.UTF_8; 21 import static org.junit.Assert.assertArrayEquals; 22 import static org.junit.Assert.assertThrows; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import com.google.crypto.tink.Aead; 27 import com.google.crypto.tink.InsecureSecretKeyAccess; 28 import com.google.crypto.tink.Key; 29 import com.google.crypto.tink.KeyTemplate; 30 import com.google.crypto.tink.KeyTemplates; 31 import com.google.crypto.tink.KeysetHandle; 32 import com.google.crypto.tink.Parameters; 33 import com.google.crypto.tink.RegistryConfiguration; 34 import com.google.crypto.tink.internal.KeyManagerRegistry; 35 import com.google.crypto.tink.internal.SlowInputStream; 36 import com.google.crypto.tink.subtle.AesGcmJce; 37 import com.google.crypto.tink.subtle.Bytes; 38 import com.google.crypto.tink.subtle.Hex; 39 import com.google.crypto.tink.util.SecretBytes; 40 import java.io.ByteArrayInputStream; 41 import java.security.GeneralSecurityException; 42 import java.util.Arrays; 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 AesGcmJce and its key manager. */ 52 @RunWith(Theories.class) 53 public class AesGcmKeyManagerTest { 54 @Before register()55 public void register() throws Exception { 56 AeadConfig.register(); 57 } 58 59 private static class NistTestVector { 60 String name; 61 public byte[] keyValue; 62 public byte[] plaintext; 63 public byte[] aad; 64 public byte[] iv; 65 public byte[] ciphertext; 66 public byte[] tag; 67 NistTestVector( String name, String keyValue, String plaintext, String aad, String iv, String ciphertext, String tag)68 public NistTestVector( 69 String name, 70 String keyValue, 71 String plaintext, 72 String aad, 73 String iv, 74 String ciphertext, 75 String tag) { 76 try { 77 this.name = name; 78 this.keyValue = Hex.decode(keyValue); 79 this.plaintext = Hex.decode(plaintext); 80 this.aad = Hex.decode(aad); 81 this.iv = Hex.decode(iv); 82 this.ciphertext = Hex.decode(ciphertext); 83 this.tag = Hex.decode(tag); 84 } catch (Exception ignored) { 85 // Ignored 86 } 87 } 88 } 89 90 // Test vectors from 91 // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf. 92 NistTestVector[] nistTestVectors = { 93 new NistTestVector( 94 "Test Case 1", 95 "00000000000000000000000000000000", 96 "", 97 "", 98 "000000000000000000000000", 99 "", 100 "58e2fccefa7e3061367f1d57a4e7455a"), 101 new NistTestVector( 102 "Test Case 2", 103 "00000000000000000000000000000000", 104 "00000000000000000000000000000000", 105 "", 106 "000000000000000000000000", 107 "0388dace60b6a392f328c2b971b2fe78", 108 "ab6e47d42cec13bdf53a67b21257bddf"), 109 new NistTestVector( 110 "Test Case 3", 111 "feffe9928665731c6d6a8f9467308308", 112 "d9313225f88406e5a55909c5aff5269a" 113 + "86a7a9531534f7da2e4c303d8a318a72" 114 + "1c3c0c95956809532fcf0e2449a6b525" 115 + "b16aedf5aa0de657ba637b391aafd255", 116 "", 117 "cafebabefacedbaddecaf888", 118 "42831ec2217774244b7221b784d0d49c" 119 + "e3aa212f2c02a4e035c17e2329aca12e" 120 + "21d514b25466931c7d8f6a5aac84aa05" 121 + "1ba30b396a0aac973d58e091473f5985", 122 "4d5c2af327cd64a62cf35abd2ba6fab4"), 123 new NistTestVector( 124 "Test Case 4", 125 "feffe9928665731c6d6a8f9467308308", 126 "d9313225f88406e5a55909c5aff5269a" 127 + "86a7a9531534f7da2e4c303d8a318a72" 128 + "1c3c0c95956809532fcf0e2449a6b525" 129 + "b16aedf5aa0de657ba637b39", 130 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", 131 "cafebabefacedbaddecaf888", 132 "42831ec2217774244b7221b784d0d49c" 133 + "e3aa212f2c02a4e035c17e2329aca12e" 134 + "21d514b25466931c7d8f6a5aac84aa05" 135 + "1ba30b396a0aac973d58e091", 136 "5bc94fbc3221a5db94fae95ae7121a47"), 137 new NistTestVector( 138 "Test Case 5", 139 "feffe9928665731c6d6a8f9467308308", 140 "d9313225f88406e5a55909c5aff5269a" 141 + "86a7a9531534f7da2e4c303d8a318a72" 142 + "1c3c0c95956809532fcf0e2449a6b525" 143 + "b16aedf5aa0de657ba637b39", 144 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", 145 "cafebabefacedbad", 146 "61353b4c2806934a777ff51fa22a4755" 147 + "699b2a714fcdc6f83766e5f97b6c7423" 148 + "73806900e49f24b22b097544d4896b42" 149 + "4989b5e1ebac0f07c23f4598", 150 "3612d2e79e3b0785561be14aaca2fccb"), 151 new NistTestVector( 152 "Test Case 6", 153 "feffe9928665731c6d6a8f9467308308", 154 "d9313225f88406e5a55909c5aff5269a" 155 + "86a7a9531534f7da2e4c303d8a318a72" 156 + "1c3c0c95956809532fcf0e2449a6b525" 157 + "b16aedf5aa0de657ba637b39", 158 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", 159 "9313225df88406e555909c5aff5269aa" 160 + "6a7a9538534f7da1e4c303d2a318a728" 161 + "c3c0c95156809539fcf0e2429a6b5254" 162 + "16aedbf5a0de6a57a637b39b", 163 "8ce24998625615b603a033aca13fb894" 164 + "be9112a5c3a211a8ba262a3cca7e2ca7" 165 + "01e4a9a4fba43c90ccdcb281d48c7c6f" 166 + "d62875d2aca417034c34aee5", 167 "619cc5aefffe0bfa462af43c1699d050"), 168 new NistTestVector( 169 "Test Case 13", 170 "00000000000000000000000000000000" + "00000000000000000000000000000000", 171 "", 172 "", 173 "000000000000000000000000", 174 "", 175 "530f8afbc74536b9a963b4f1c4cb738b"), 176 new NistTestVector( 177 "Test Case 14", 178 "00000000000000000000000000000000" + "00000000000000000000000000000000", 179 "00000000000000000000000000000000", 180 "", 181 "000000000000000000000000", 182 "cea7403d4d606b6e074ec5d3baf39d18", 183 "d0d1c8a799996bf0265b98b5d48ab919"), 184 new NistTestVector( 185 "Test Case 15", 186 "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", 187 "d9313225f88406e5a55909c5aff5269a" 188 + "86a7a9531534f7da2e4c303d8a318a72" 189 + "1c3c0c95956809532fcf0e2449a6b525" 190 + "b16aedf5aa0de657ba637b391aafd255", 191 "", 192 "cafebabefacedbaddecaf888", 193 "522dc1f099567d07f47f37a32a84427d" 194 + "643a8cdcbfe5c0c97598a2bd2555d1aa" 195 + "8cb08e48590dbb3da7b08b1056828838" 196 + "c5f61e6393ba7a0abcc9f662898015ad", 197 "b094dac5d93471bdec1a502270e3cc6c"), 198 new NistTestVector( 199 "Test Case 16", 200 "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", 201 "d9313225f88406e5a55909c5aff5269a" 202 + "86a7a9531534f7da2e4c303d8a318a72" 203 + "1c3c0c95956809532fcf0e2449a6b525" 204 + "b16aedf5aa0de657ba637b39", 205 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", 206 "cafebabefacedbaddecaf888", 207 "522dc1f099567d07f47f37a32a84427d" 208 + "643a8cdcbfe5c0c97598a2bd2555d1aa" 209 + "8cb08e48590dbb3da7b08b1056828838" 210 + "c5f61e6393ba7a0abcc9f662", 211 "76fc6ece0f4e1768cddf8853bb2d551b"), 212 new NistTestVector( 213 "Test Case 17", 214 "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", 215 "d9313225f88406e5a55909c5aff5269a" 216 + "86a7a9531534f7da2e4c303d8a318a72" 217 + "1c3c0c95956809532fcf0e2449a6b525" 218 + "b16aedf5aa0de657ba637b39", 219 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", 220 "cafebabefacedbad", 221 "c3762df1ca787d32ae47c13bf19844cb" 222 + "af1ae14d0b976afac52ff7d79bba9de0" 223 + "feb582d33934a4f0954cc2363bc73f78" 224 + "62ac430e64abe499f47c9b1f", 225 "3a337dbf46a792c45e454913fe2ea8f2"), 226 new NistTestVector( 227 "Test Case 18", 228 "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", 229 "d9313225f88406e5a55909c5aff5269a" 230 + "86a7a9531534f7da2e4c303d8a318a72" 231 + "1c3c0c95956809532fcf0e2449a6b525" 232 + "b16aedf5aa0de657ba637b39", 233 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", 234 "9313225df88406e555909c5aff5269aa" 235 + "6a7a9538534f7da1e4c303d2a318a728" 236 + "c3c0c95156809539fcf0e2429a6b5254" 237 + "16aedbf5a0de6a57a637b39b", 238 "5a8def2f0c9e53f1f75d7853659e2a20" 239 + "eeb2b22aafde6419a058ab4f6f746bf4" 240 + "0fc0c3b780f244452da3ebf1c5d82cde" 241 + "a2418997200ef82e44ae7e3f", 242 "a44a8266ee1c8eb0c8b5d4cf5ae9f19a"), 243 }; 244 245 @Test testNistVectors()246 public void testNistVectors() throws Exception { 247 for (NistTestVector t : nistTestVectors) { 248 if (t.iv.length != 12 || t.tag.length != 16) { 249 // We support only 12-byte IV and 16-byte tag. 250 continue; 251 } 252 AesGcmParameters parameters = 253 AesGcmParameters.builder() 254 .setIvSizeBytes(12) 255 .setKeySizeBytes(t.keyValue.length) 256 .setTagSizeBytes(16) 257 .setVariant(AesGcmParameters.Variant.NO_PREFIX) 258 .build(); 259 AesGcmKey key = 260 AesGcmKey.builder() 261 .setParameters(parameters) 262 .setKeyBytes(SecretBytes.copyFrom(t.keyValue, InsecureSecretKeyAccess.get())) 263 .build(); 264 Aead aead = 265 KeysetHandle.newBuilder() 266 .addEntry(KeysetHandle.importKey(key).makePrimary().withRandomId()) 267 .build() 268 .getPrimitive(RegistryConfiguration.get(), Aead.class); 269 try { 270 byte[] ciphertext = Bytes.concat(t.iv, t.ciphertext, t.tag); 271 byte[] plaintext = aead.decrypt(ciphertext, t.aad); 272 assertArrayEquals(plaintext, t.plaintext); 273 } catch (GeneralSecurityException e) { 274 fail("Should not fail at " + t.name + ", but thrown exception " + e); 275 } 276 } 277 } 278 279 @Test testKeyManagerRegistered()280 public void testKeyManagerRegistered() throws Exception { 281 assertThat( 282 KeyManagerRegistry.globalInstance() 283 .getKeyManager("type.googleapis.com/google.crypto.tink.AesGcmKey", Aead.class)) 284 .isNotNull(); 285 } 286 287 @Test testAes128GcmTemplate()288 public void testAes128GcmTemplate() throws Exception { 289 KeyTemplate template = AesGcmKeyManager.aes128GcmTemplate(); 290 assertThat(template.toParameters()) 291 .isEqualTo( 292 AesGcmParameters.builder() 293 .setIvSizeBytes(12) 294 .setTagSizeBytes(16) 295 .setKeySizeBytes(16) 296 .setVariant(AesGcmParameters.Variant.TINK) 297 .build()); 298 } 299 300 @Test testRawAes128GcmTemplate()301 public void testRawAes128GcmTemplate() throws Exception { 302 KeyTemplate template = AesGcmKeyManager.rawAes128GcmTemplate(); 303 assertThat(template.toParameters()) 304 .isEqualTo( 305 AesGcmParameters.builder() 306 .setIvSizeBytes(12) 307 .setTagSizeBytes(16) 308 .setKeySizeBytes(16) 309 .setVariant(AesGcmParameters.Variant.NO_PREFIX) 310 .build()); 311 } 312 313 @Test testAes256GcmTemplate()314 public void testAes256GcmTemplate() throws Exception { 315 KeyTemplate template = AesGcmKeyManager.aes256GcmTemplate(); 316 assertThat(template.toParameters()) 317 .isEqualTo( 318 AesGcmParameters.builder() 319 .setIvSizeBytes(12) 320 .setTagSizeBytes(16) 321 .setKeySizeBytes(32) 322 .setVariant(AesGcmParameters.Variant.TINK) 323 .build()); 324 } 325 326 @Test testRawAes256GcmTemplate()327 public void testRawAes256GcmTemplate() throws Exception { 328 KeyTemplate template = AesGcmKeyManager.rawAes256GcmTemplate(); 329 assertThat(template.toParameters()) 330 .isEqualTo( 331 AesGcmParameters.builder() 332 .setIvSizeBytes(12) 333 .setTagSizeBytes(16) 334 .setKeySizeBytes(32) 335 .setVariant(AesGcmParameters.Variant.NO_PREFIX) 336 .build()); 337 } 338 339 @Test testKeyTemplatesWork()340 public void testKeyTemplatesWork() throws Exception { 341 Parameters p = AesGcmKeyManager.aes128GcmTemplate().toParameters(); 342 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 343 344 p = AesGcmKeyManager.rawAes128GcmTemplate().toParameters(); 345 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 346 347 p = AesGcmKeyManager.aes256GcmTemplate().toParameters(); 348 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 349 350 p = AesGcmKeyManager.rawAes256GcmTemplate().toParameters(); 351 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 352 } 353 354 @DataPoints("templateNames") 355 public static final String[] KEY_TEMPLATES = 356 new String[] { 357 "AES128_GCM", "AES128_GCM_RAW", "AES256_GCM", "AES256_GCM_RAW", 358 }; 359 360 @Theory testTemplates(@romDataPoints"templateNames") String templateName)361 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 362 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 363 assertThat(h.size()).isEqualTo(1); 364 assertThat(h.getAt(0).getKey().getParameters()) 365 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 366 } 367 368 @Theory testCreateKeyFromRandomness(@romDataPoints"templateNames") String templateName)369 public void testCreateKeyFromRandomness(@FromDataPoints("templateNames") String templateName) 370 throws Exception { 371 byte[] keyMaterial = 372 new byte[] { 373 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, 374 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 375 }; 376 AesGcmParameters parameters = (AesGcmParameters) KeyTemplates.get(templateName).toParameters(); 377 AesGcmKey key = 378 AesGcmKeyManager.createAesGcmKeyFromRandomness( 379 parameters, 380 new ByteArrayInputStream(keyMaterial), 381 parameters.hasIdRequirement() ? 123 : null, 382 InsecureSecretKeyAccess.get()); 383 byte[] truncatedKeyMaterial = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes()); 384 Key expectedKey = 385 AesGcmKey.builder() 386 .setParameters(parameters) 387 .setIdRequirement(parameters.hasIdRequirement() ? 123 : null) 388 .setKeyBytes(SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get())) 389 .build(); 390 assertTrue(key.equalsKey(expectedKey)); 391 } 392 393 @Test callingCreateTwiceGivesDifferentKeys()394 public void callingCreateTwiceGivesDifferentKeys() throws Exception { 395 Parameters p = AesGcmKeyManager.aes128GcmTemplate().toParameters(); 396 Key key = KeysetHandle.generateNew(p).getAt(0).getKey(); 397 for (int i = 0; i < 1000; ++i) { 398 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().equalsKey(key)).isFalse(); 399 } 400 } 401 402 @Test test_24byte_keyCreation_throws()403 public void test_24byte_keyCreation_throws() throws Exception { 404 // We currently disallow creation of AesGcmKeys with 24 bytes (Tink doesn't support using these 405 // for consistency among the languages, so we also disallow creation at the moment). 406 AesGcmParameters p = 407 AesGcmParameters.builder() 408 .setIvSizeBytes(12) 409 .setTagSizeBytes(16) 410 .setKeySizeBytes(24) 411 .build(); 412 assertThrows(GeneralSecurityException.class, () -> KeysetHandle.generateNew(p)); 413 } 414 415 @Test test_24byte_primitiveCreation_throws()416 public void test_24byte_primitiveCreation_throws() throws Exception { 417 // We currently disallow creation of AesGcmKeys with 24 bytes (Tink doesn't support using these 418 // for consistency among the languages, so we also disallow creation at the moment). 419 AesGcmParameters p = 420 AesGcmParameters.builder() 421 .setIvSizeBytes(12) 422 .setTagSizeBytes(16) 423 .setKeySizeBytes(24) 424 .build(); 425 AesGcmKey key = 426 AesGcmKey.builder().setParameters(p).setKeyBytes(SecretBytes.randomBytes(24)).build(); 427 KeysetHandle keysetHandle = 428 KeysetHandle.newBuilder() 429 .addEntry(KeysetHandle.importKey(key).makePrimary().withRandomId()) 430 .build(); 431 assertThrows( 432 GeneralSecurityException.class, 433 () -> keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class)); 434 } 435 436 @Test test_24byte_createKeyFromRandomness_throws()437 public void test_24byte_createKeyFromRandomness_throws() throws Exception { 438 // We currently disallow creation of AesGcmKeys with 24 bytes (Tink doesn't support using these 439 // for consistency among the languages, so we also disallow creation at the moment). 440 AesGcmParameters parameters = 441 AesGcmParameters.builder() 442 .setIvSizeBytes(12) 443 .setTagSizeBytes(16) 444 .setKeySizeBytes(24) 445 .build(); 446 byte[] keyMaterial = 447 new byte[] { 448 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, 449 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 450 }; 451 assertThrows( 452 GeneralSecurityException.class, 453 () -> 454 AesGcmKeyManager.createAesGcmKeyFromRandomness( 455 parameters, 456 SlowInputStream.copyFrom(keyMaterial), 457 null, 458 InsecureSecretKeyAccess.get())); 459 } 460 461 @Test testCreateKeyFromRandomness_slowInputStream_works()462 public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception { 463 byte[] keyMaterial = 464 new byte[] { 465 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, 466 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 467 }; 468 AesGcmParameters parameters = 469 AesGcmParameters.builder() 470 .setIvSizeBytes(12) 471 .setTagSizeBytes(16) 472 .setKeySizeBytes(32) 473 .setVariant(AesGcmParameters.Variant.NO_PREFIX) 474 .build(); 475 AesGcmKey key = 476 AesGcmKeyManager.createAesGcmKeyFromRandomness( 477 parameters, SlowInputStream.copyFrom(keyMaterial), null, InsecureSecretKeyAccess.get()); 478 byte[] truncatedKeyMaterial = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes()); 479 Key expectedKey = 480 AesGcmKey.builder() 481 .setParameters(parameters) 482 .setIdRequirement(null) 483 .setKeyBytes(SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get())) 484 .build(); 485 assertTrue(key.equalsKey(expectedKey)); 486 } 487 488 @Test getPrimitiveFromKeysetHandle()489 public void getPrimitiveFromKeysetHandle() throws Exception { 490 AesGcmParameters parameters = 491 AesGcmParameters.builder() 492 .setIvSizeBytes(12) 493 .setTagSizeBytes(16) 494 .setKeySizeBytes(16) 495 .setVariant(AesGcmParameters.Variant.TINK) 496 .build(); 497 AesGcmKey key = 498 AesGcmKey.builder() 499 .setParameters(parameters) 500 .setKeyBytes(SecretBytes.randomBytes(16)) 501 .setIdRequirement(31) 502 .build(); 503 KeysetHandle keysetHandle = 504 KeysetHandle.newBuilder().addEntry(KeysetHandle.importKey(key).makePrimary()).build(); 505 byte[] plaintext = "plaintext".getBytes(UTF_8); 506 byte[] aad = "aad".getBytes(UTF_8); 507 508 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 509 Aead directAead = AesGcmJce.create(key); 510 511 Object unused = directAead.decrypt(aead.encrypt(plaintext, aad), aad); 512 unused = aead.decrypt(directAead.encrypt(plaintext, aad), aad); 513 } 514 } 515