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.internal; 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.assertEquals; 22 import static org.junit.Assert.assertThrows; 23 24 import com.google.crypto.tink.Aead; 25 import com.google.crypto.tink.CryptoFormat; 26 import com.google.crypto.tink.InsecureSecretKeyAccess; 27 import com.google.crypto.tink.Mac; 28 import com.google.crypto.tink.aead.AesGcmKey; 29 import com.google.crypto.tink.aead.PredefinedAeadParameters; 30 import com.google.crypto.tink.mac.HmacKey; 31 import com.google.crypto.tink.mac.HmacKeyManager; 32 import com.google.crypto.tink.proto.HashType; 33 import com.google.crypto.tink.proto.HmacParams; 34 import com.google.crypto.tink.proto.KeyData; 35 import com.google.crypto.tink.proto.KeyStatusType; 36 import com.google.crypto.tink.proto.Keyset; 37 import com.google.crypto.tink.proto.Keyset.Key; 38 import com.google.crypto.tink.proto.OutputPrefixType; 39 import com.google.crypto.tink.subtle.AesGcmJce; 40 import com.google.crypto.tink.subtle.Hex; 41 import com.google.crypto.tink.testing.TestUtil; 42 import com.google.crypto.tink.util.SecretBytes; 43 import com.google.protobuf.ByteString; 44 import java.security.GeneralSecurityException; 45 import java.util.ArrayList; 46 import java.util.HashMap; 47 import java.util.List; 48 import javax.annotation.Nullable; 49 import org.junit.BeforeClass; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.junit.runners.JUnit4; 53 54 /** Tests for PrimitiveSet. */ 55 @RunWith(JUnit4.class) 56 public class PrimitiveSetTest { 57 58 private static class DummyMac1 implements Mac { DummyMac1()59 public DummyMac1() {} 60 61 @Override computeMac(byte[] data)62 public byte[] computeMac(byte[] data) throws GeneralSecurityException { 63 return this.getClass().getSimpleName().getBytes(UTF_8); 64 } 65 66 @Override verifyMac(byte[] mac, byte[] data)67 public void verifyMac(byte[] mac, byte[] data) throws GeneralSecurityException { 68 return; 69 } 70 } 71 72 private static class DummyMac2 implements Mac { DummyMac2()73 public DummyMac2() {} 74 75 @Override computeMac(byte[] data)76 public byte[] computeMac(byte[] data) throws GeneralSecurityException { 77 return this.getClass().getSimpleName().getBytes(UTF_8); 78 } 79 80 @Override verifyMac(byte[] mac, byte[] data)81 public void verifyMac(byte[] mac, byte[] data) throws GeneralSecurityException { 82 return; 83 } 84 } 85 86 @BeforeClass setUp()87 public static void setUp() throws GeneralSecurityException { 88 HmacKeyManager.register(true); 89 } 90 getKeyFromProtoKey(Key key)91 com.google.crypto.tink.Key getKeyFromProtoKey(Key key) throws GeneralSecurityException { 92 @Nullable Integer idRequirement = key.getKeyId(); 93 if (key.getOutputPrefixType() == OutputPrefixType.RAW) { 94 idRequirement = null; 95 } 96 return MutableSerializationRegistry.globalInstance() 97 .parseKeyWithLegacyFallback( 98 ProtoKeySerialization.create( 99 key.getKeyData().getTypeUrl(), 100 key.getKeyData().getValue(), 101 key.getKeyData().getKeyMaterialType(), 102 key.getOutputPrefixType(), 103 idRequirement), 104 InsecureSecretKeyAccess.get()); 105 } 106 107 @Test primitiveSetWithOneEntry_works()108 public void primitiveSetWithOneEntry_works() throws Exception { 109 byte[] keyMaterial = Hex.decode("000102030405060708090a0b0c0d0e0f"); 110 AesGcmKey key = 111 AesGcmKey.builder() 112 .setParameters(PredefinedAeadParameters.AES128_GCM) 113 .setKeyBytes(SecretBytes.copyFrom(keyMaterial, InsecureSecretKeyAccess.get())) 114 .setIdRequirement(42) 115 .build(); 116 Aead fullPrimitive = AesGcmJce.create(key); 117 Keyset.Key protoKey = 118 TestUtil.createKey( 119 TestUtil.createAesGcmKeyData(keyMaterial), 120 42, 121 KeyStatusType.ENABLED, 122 OutputPrefixType.TINK); 123 PrimitiveSet<Aead> pset = 124 PrimitiveSet.newBuilder(Aead.class) 125 .addPrimaryFullPrimitive(fullPrimitive, key, protoKey) 126 .build(); 127 assertThat(pset.getAll()).hasSize(1); 128 List<PrimitiveSet.Entry<Aead>> entries = 129 pset.getPrimitive(CryptoFormat.getOutputPrefix(protoKey)); 130 assertThat(entries).hasSize(1); 131 PrimitiveSet.Entry<Aead> entry = entries.get(0); 132 assertThat(entry.getFullPrimitive()).isEqualTo(fullPrimitive); 133 assertThat(entry.getStatus()).isEqualTo(KeyStatusType.ENABLED); 134 assertThat(entry.getOutputPrefixType()).isEqualTo(OutputPrefixType.TINK); 135 assertThat(entry.getKeyId()).isEqualTo(42); 136 assertThat(entry.getKeyTypeUrl()).isEqualTo("type.googleapis.com/google.crypto.tink.AesGcmKey"); 137 assertThat(entry.getKey()).isEqualTo(key); 138 } 139 140 @Test testBasicFunctionality()141 public void testBasicFunctionality() throws Exception { 142 Key key1 = 143 Key.newBuilder() 144 .setKeyId(1) 145 .setStatus(KeyStatusType.ENABLED) 146 .setOutputPrefixType(OutputPrefixType.TINK) 147 .build(); 148 Key key2 = 149 Key.newBuilder() 150 .setKeyId(2) 151 .setStatus(KeyStatusType.ENABLED) 152 .setOutputPrefixType(OutputPrefixType.RAW) 153 .build(); 154 Key key3 = 155 Key.newBuilder() 156 .setKeyId(3) 157 .setStatus(KeyStatusType.ENABLED) 158 .setOutputPrefixType(OutputPrefixType.LEGACY) 159 .build(); 160 PrimitiveSet<Mac> pset = 161 PrimitiveSet.newBuilder(Mac.class) 162 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 163 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 164 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key3), key3) 165 .build(); 166 167 assertThat(pset.getAll()).hasSize(3); 168 169 List<PrimitiveSet.Entry<Mac>> entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)); 170 assertThat(entries).hasSize(1); 171 PrimitiveSet.Entry<Mac> entry = entries.get(0); 172 assertEquals( 173 DummyMac1.class.getSimpleName(), 174 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 175 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 176 assertEquals(1, entry.getKeyId()); 177 178 entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key2)); 179 assertThat(entries).hasSize(1); 180 entry = entries.get(0); 181 assertEquals( 182 DummyMac2.class.getSimpleName(), 183 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 184 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 185 assertEquals(2, entry.getKeyId()); 186 187 entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key3)); 188 assertThat(entries).hasSize(1); 189 entry = entries.get(0); 190 assertEquals( 191 DummyMac1.class.getSimpleName(), 192 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 193 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 194 assertEquals(3, entry.getKeyId()); 195 196 entry = pset.getPrimary(); 197 assertEquals( 198 DummyMac2.class.getSimpleName(), 199 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 200 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 201 assertEquals(2, entry.getKeyId()); 202 } 203 204 @Test testAddFullPrimitive_works()205 public void testAddFullPrimitive_works() throws Exception { 206 Key key1 = 207 Key.newBuilder() 208 .setKeyId(1) 209 .setStatus(KeyStatusType.ENABLED) 210 .setOutputPrefixType(OutputPrefixType.TINK) 211 .build(); 212 Key key2 = 213 Key.newBuilder() 214 .setKeyId(2) 215 .setStatus(KeyStatusType.ENABLED) 216 .setOutputPrefixType(OutputPrefixType.RAW) 217 .build(); 218 Key key3 = 219 Key.newBuilder() 220 .setKeyId(3) 221 .setStatus(KeyStatusType.ENABLED) 222 .setOutputPrefixType(OutputPrefixType.LEGACY) 223 .build(); 224 PrimitiveSet<Mac> pset = 225 PrimitiveSet.newBuilder(Mac.class) 226 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 227 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 228 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key3), key3) 229 .build(); 230 231 assertThat(pset.getAll()).hasSize(3); 232 233 List<PrimitiveSet.Entry<Mac>> entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)); 234 assertThat(entries).hasSize(1); 235 236 entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key2)); 237 assertThat(entries).hasSize(1); 238 239 entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key3)); 240 assertThat(entries).hasSize(1); 241 242 PrimitiveSet.Entry<Mac> entry = pset.getPrimary(); 243 assertThat(entry).isNotNull(); 244 } 245 246 @Test testAddFullPrimitive_fullPrimitiveHandledCorrectly()247 public void testAddFullPrimitive_fullPrimitiveHandledCorrectly() throws Exception { 248 Key key1 = 249 Key.newBuilder() 250 .setKeyId(1) 251 .setStatus(KeyStatusType.ENABLED) 252 .setOutputPrefixType(OutputPrefixType.TINK) 253 .build(); 254 Key key2 = 255 Key.newBuilder() 256 .setKeyId(2) 257 .setStatus(KeyStatusType.ENABLED) 258 .setOutputPrefixType(OutputPrefixType.RAW) 259 .build(); 260 Key key3 = 261 Key.newBuilder() 262 .setKeyId(3) 263 .setStatus(KeyStatusType.ENABLED) 264 .setOutputPrefixType(OutputPrefixType.LEGACY) 265 .build(); 266 PrimitiveSet<Mac> pset = 267 PrimitiveSet.newBuilder(Mac.class) 268 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 269 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 270 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key3), key3) 271 .build(); 272 273 PrimitiveSet.Entry<Mac> entry = pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)).get(0); 274 assertEquals( 275 DummyMac1.class.getSimpleName(), 276 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 277 278 entry = pset.getPrimitive(CryptoFormat.getOutputPrefix(key2)).get(0); 279 assertEquals( 280 DummyMac2.class.getSimpleName(), 281 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 282 283 entry = pset.getPrimitive(CryptoFormat.getOutputPrefix(key3)).get(0); 284 assertEquals( 285 DummyMac1.class.getSimpleName(), 286 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 287 288 entry = pset.getPrimary(); 289 assertEquals( 290 DummyMac2.class.getSimpleName(), 291 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 292 } 293 294 @Test testAddFullPrimitive_keysHandledCorrectly()295 public void testAddFullPrimitive_keysHandledCorrectly() throws Exception { 296 Key key1 = 297 Key.newBuilder() 298 .setKeyId(1) 299 .setStatus(KeyStatusType.ENABLED) 300 .setOutputPrefixType(OutputPrefixType.TINK) 301 .build(); 302 Key key2 = 303 Key.newBuilder() 304 .setKeyId(2) 305 .setStatus(KeyStatusType.ENABLED) 306 .setOutputPrefixType(OutputPrefixType.RAW) 307 .build(); 308 Key key3 = 309 Key.newBuilder() 310 .setKeyId(3) 311 .setStatus(KeyStatusType.ENABLED) 312 .setOutputPrefixType(OutputPrefixType.LEGACY) 313 .build(); 314 PrimitiveSet<Mac> pset = 315 PrimitiveSet.newBuilder(Mac.class) 316 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 317 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 318 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key3), key3) 319 .build(); 320 321 PrimitiveSet.Entry<Mac> entry = pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)).get(0); 322 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 323 assertEquals(1, entry.getKeyId()); 324 325 entry = pset.getPrimitive(CryptoFormat.getOutputPrefix(key2)).get(0); 326 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 327 assertEquals(2, entry.getKeyId()); 328 329 entry = pset.getPrimitive(CryptoFormat.getOutputPrefix(key3)).get(0); 330 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 331 assertEquals(3, entry.getKeyId()); 332 333 entry = pset.getPrimary(); 334 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 335 assertEquals(2, entry.getKeyId()); 336 } 337 338 @Test testAddFullPrimitive_throwsOnDoublePrimaryAdd()339 public void testAddFullPrimitive_throwsOnDoublePrimaryAdd() throws Exception { 340 Key key1 = 341 Key.newBuilder() 342 .setKeyId(1) 343 .setStatus(KeyStatusType.ENABLED) 344 .setOutputPrefixType(OutputPrefixType.TINK) 345 .build(); 346 Key key2 = 347 Key.newBuilder() 348 .setKeyId(2) 349 .setStatus(KeyStatusType.ENABLED) 350 .setOutputPrefixType(OutputPrefixType.RAW) 351 .build(); 352 assertThrows( 353 IllegalStateException.class, 354 () -> 355 PrimitiveSet.newBuilder(Mac.class) 356 .addPrimaryFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 357 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 358 .build()); 359 } 360 361 @Test testNoPrimary_getPrimaryReturnsNull()362 public void testNoPrimary_getPrimaryReturnsNull() throws Exception { 363 Key key = 364 Key.newBuilder() 365 .setKeyId(1) 366 .setStatus(KeyStatusType.ENABLED) 367 .setOutputPrefixType(OutputPrefixType.TINK) 368 .build(); 369 PrimitiveSet<Mac> pset = 370 PrimitiveSet.newBuilder(Mac.class) 371 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key), key) 372 .build(); 373 assertThat(pset.getPrimary()).isNull(); 374 } 375 376 @Test testEntryGetParametersToString()377 public void testEntryGetParametersToString() throws Exception { 378 Key key1 = 379 Key.newBuilder() 380 .setKeyId(1) 381 .setStatus(KeyStatusType.ENABLED) 382 .setOutputPrefixType(OutputPrefixType.TINK) 383 .setKeyData(KeyData.newBuilder().setTypeUrl("typeUrl1").build()) 384 .build(); 385 386 PrimitiveSet<Mac> pset = 387 PrimitiveSet.newBuilder(Mac.class) 388 .addPrimaryFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 389 .build(); 390 assertThat( 391 pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)).get(0).getParameters().toString()) 392 .isEqualTo("(typeUrl=typeUrl1, outputPrefixType=TINK)"); 393 } 394 395 @Test getKeyWithoutParser_givesLegacyProtoKey()396 public void getKeyWithoutParser_givesLegacyProtoKey() throws Exception { 397 PrimitiveSet.Builder<Mac> builder = PrimitiveSet.newBuilder(Mac.class); 398 Key key1 = 399 Key.newBuilder() 400 .setKeyId(1) 401 .setStatus(KeyStatusType.ENABLED) 402 .setOutputPrefixType(OutputPrefixType.TINK) 403 .setKeyData(KeyData.newBuilder().setTypeUrl("typeUrl1").build()) 404 .build(); 405 builder.addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1); 406 PrimitiveSet<Mac> pset = builder.build(); 407 com.google.crypto.tink.Key key = 408 pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)).get(0).getKey(); 409 410 assertThat(key).isInstanceOf(LegacyProtoKey.class); 411 LegacyProtoKey legacyProtoKey = (LegacyProtoKey) key; 412 assertThat(legacyProtoKey.getSerialization(InsecureSecretKeyAccess.get()).getTypeUrl()) 413 .isEqualTo("typeUrl1"); 414 } 415 416 @Test getKeyWithParser_works()417 public void getKeyWithParser_works() throws Exception { 418 // HmacKey's proto serialization HmacProtoSerialization is registed in HmacKeyManager. 419 Key protoKey = 420 TestUtil.createKey( 421 TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16), 422 /* keyId= */ 42, 423 KeyStatusType.ENABLED, 424 OutputPrefixType.TINK); 425 byte[] prefix = CryptoFormat.getOutputPrefix(protoKey); 426 PrimitiveSet.Builder<Mac> builder = PrimitiveSet.newBuilder(Mac.class); 427 builder.addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(protoKey), protoKey); 428 PrimitiveSet<Mac> pset = builder.build(); 429 430 com.google.crypto.tink.Key key = pset.getPrimitive(prefix).get(0).getKey(); 431 assertThat(key).isInstanceOf(HmacKey.class); 432 HmacKey hmacKey = (HmacKey) key; 433 assertThat(hmacKey.getIdRequirementOrNull()).isEqualTo(42); 434 } 435 436 @Test addPrimitiveWithInvalidKeyThatHasAParser_throws()437 public void addPrimitiveWithInvalidKeyThatHasAParser_throws() throws Exception { 438 // HmacKey's proto serialization HmacProtoSerialization is registed in HmacKeyManager. 439 com.google.crypto.tink.proto.HmacKey invalidProtoHmacKey = 440 com.google.crypto.tink.proto.HmacKey.newBuilder() 441 .setVersion(999) 442 .setKeyValue(ByteString.copyFromUtf8("01234567890123456")) 443 .setParams(HmacParams.newBuilder().setHash(HashType.UNKNOWN_HASH).setTagSize(0)) 444 .build(); 445 Key protoKey = 446 TestUtil.createKey( 447 TestUtil.createKeyData( 448 invalidProtoHmacKey, 449 "type.googleapis.com/google.crypto.tink.HmacKey", 450 KeyData.KeyMaterialType.SYMMETRIC), 451 /* keyId= */ 42, 452 KeyStatusType.ENABLED, 453 OutputPrefixType.TINK); 454 455 PrimitiveSet.Builder<Mac> builder = PrimitiveSet.newBuilder(Mac.class); 456 assertThrows( 457 GeneralSecurityException.class, 458 () -> builder.addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(protoKey), protoKey)); 459 } 460 461 @Test testWithAnnotations()462 public void testWithAnnotations() throws Exception { 463 MonitoringAnnotations annotations = 464 MonitoringAnnotations.newBuilder().add("name", "value").build(); 465 PrimitiveSet<Mac> pset = PrimitiveSet.newBuilder(Mac.class).setAnnotations(annotations).build(); 466 467 HashMap<String, String> expected = new HashMap<>(); 468 expected.put("name", "value"); 469 assertThat(pset.getAnnotations().toMap()).containsExactlyEntriesIn(expected); 470 } 471 472 @Test testGetEmptyAnnotations()473 public void testGetEmptyAnnotations() throws Exception { 474 PrimitiveSet<Mac> pset = PrimitiveSet.newBuilder(Mac.class).build(); 475 assertThat(pset.getAnnotations()).isEqualTo(MonitoringAnnotations.EMPTY); 476 } 477 478 @Test testDuplicateKeys()479 public void testDuplicateKeys() throws Exception { 480 Key key1 = 481 Key.newBuilder() 482 .setKeyId(1) 483 .setStatus(KeyStatusType.ENABLED) 484 .setOutputPrefixType(OutputPrefixType.TINK) 485 .build(); 486 Key key2 = 487 Key.newBuilder() 488 .setKeyId(1) 489 .setStatus(KeyStatusType.ENABLED) 490 .setOutputPrefixType(OutputPrefixType.RAW) 491 .build(); 492 Key key3 = 493 Key.newBuilder() 494 .setKeyId(2) 495 .setStatus(KeyStatusType.ENABLED) 496 .setOutputPrefixType(OutputPrefixType.LEGACY) 497 .build(); 498 Key key4 = 499 Key.newBuilder() 500 .setKeyId(2) 501 .setStatus(KeyStatusType.ENABLED) 502 .setOutputPrefixType(OutputPrefixType.LEGACY) 503 .build(); 504 Key key5 = 505 Key.newBuilder() 506 .setKeyId(3) 507 .setStatus(KeyStatusType.ENABLED) 508 .setOutputPrefixType(OutputPrefixType.RAW) 509 .build(); 510 Key key6 = 511 Key.newBuilder() 512 .setKeyId(3) 513 .setStatus(KeyStatusType.ENABLED) 514 .setOutputPrefixType(OutputPrefixType.RAW) 515 .build(); 516 517 PrimitiveSet<Mac> pset = 518 PrimitiveSet.newBuilder(Mac.class) 519 .addFullPrimitive(new DummyMac1(), null, key1) 520 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 521 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key3), key3) 522 .addFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key4), key4) 523 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key5), key5) 524 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key6), key6) 525 .build(); 526 527 assertThat(pset.getAll()).hasSize(3); // 3 instead of 6 because of duplicated key ids 528 529 // tink keys 530 List<PrimitiveSet.Entry<Mac>> entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key1)); 531 assertThat(entries).hasSize(1); 532 PrimitiveSet.Entry<Mac> entry = entries.get(0); 533 assertEquals( 534 DummyMac1.class.getSimpleName(), 535 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 536 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 537 assertEquals(1, entry.getKeyId()); 538 539 // raw keys 540 List<Integer> ids = new ArrayList<>(); // The order of the keys is an implementation detail. 541 entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key2)); 542 assertThat(entries).hasSize(3); 543 entry = entries.get(0); 544 assertEquals( 545 DummyMac2.class.getSimpleName(), 546 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 547 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 548 ids.add(entry.getKeyId()); 549 entry = entries.get(1); 550 assertEquals( 551 DummyMac1.class.getSimpleName(), 552 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 553 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 554 ids.add(entry.getKeyId()); 555 entry = entries.get(2); 556 assertEquals( 557 DummyMac1.class.getSimpleName(), 558 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 559 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 560 ids.add(entry.getKeyId()); 561 562 assertThat(ids).containsExactly(1, 3, 3); 563 // legacy keys 564 entries = pset.getPrimitive(CryptoFormat.getOutputPrefix(key3)); 565 assertThat(entries).hasSize(2); 566 entry = entries.get(0); 567 assertEquals( 568 DummyMac1.class.getSimpleName(), 569 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 570 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 571 assertEquals(2, entry.getKeyId()); 572 entry = entries.get(1); 573 assertEquals( 574 DummyMac2.class.getSimpleName(), 575 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 576 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 577 assertEquals(2, entry.getKeyId()); 578 579 entry = pset.getPrimary(); 580 assertEquals( 581 DummyMac2.class.getSimpleName(), 582 new String(entry.getFullPrimitive().computeMac(null), UTF_8)); 583 assertEquals(KeyStatusType.ENABLED, entry.getStatus()); 584 assertEquals(1, entry.getKeyId()); 585 } 586 587 @Test testAddFullPrimive_withUnknownPrefixType_shouldFail()588 public void testAddFullPrimive_withUnknownPrefixType_shouldFail() throws Exception { 589 Key key1 = Key.newBuilder().setKeyId(1).setStatus(KeyStatusType.ENABLED).build(); 590 591 assertThrows( 592 GeneralSecurityException.class, 593 () -> 594 PrimitiveSet.newBuilder(Mac.class) 595 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 596 .build()); 597 assertThrows( 598 GeneralSecurityException.class, 599 () -> 600 PrimitiveSet.newBuilder(Mac.class) 601 .addPrimaryFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 602 .build()); 603 } 604 605 @Test testAddFullPrimive_withDisabledKey_shouldFail()606 public void testAddFullPrimive_withDisabledKey_shouldFail() throws Exception { 607 Key key1 = 608 Key.newBuilder() 609 .setKeyId(1) 610 .setStatus(KeyStatusType.DISABLED) 611 .setOutputPrefixType(OutputPrefixType.TINK) 612 .build(); 613 614 assertThrows( 615 GeneralSecurityException.class, 616 () -> 617 PrimitiveSet.newBuilder(Mac.class) 618 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 619 .build()); 620 assertThrows( 621 GeneralSecurityException.class, 622 () -> 623 PrimitiveSet.newBuilder(Mac.class) 624 .addPrimaryFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 625 .build()); 626 } 627 628 @Test testAddFullPrimive_withNullPrimitive_throwsNullPointerException()629 public void testAddFullPrimive_withNullPrimitive_throwsNullPointerException() throws Exception { 630 Key key = 631 Key.newBuilder() 632 .setKeyId(1) 633 .setStatus(KeyStatusType.ENABLED) 634 .setOutputPrefixType(OutputPrefixType.TINK) 635 .build(); 636 637 assertThrows( 638 NullPointerException.class, 639 () -> 640 PrimitiveSet.newBuilder(Mac.class) 641 .addFullPrimitive(null, getKeyFromProtoKey(key), key)); 642 643 assertThrows( 644 NullPointerException.class, 645 () -> 646 PrimitiveSet.newBuilder(Mac.class) 647 .addPrimaryFullPrimitive(null, getKeyFromProtoKey(key), key)); 648 } 649 650 @Test testPrefixIsUnique()651 public void testPrefixIsUnique() throws Exception { 652 Key key1 = 653 Key.newBuilder() 654 .setKeyId(0xffffffff) 655 .setStatus(KeyStatusType.ENABLED) 656 .setOutputPrefixType(OutputPrefixType.TINK) 657 .build(); 658 Key key2 = 659 Key.newBuilder() 660 .setKeyId(0xffffffdf) 661 .setStatus(KeyStatusType.ENABLED) 662 .setOutputPrefixType(OutputPrefixType.RAW) 663 .build(); 664 Key key3 = 665 Key.newBuilder() 666 .setKeyId(0xffffffef) 667 .setStatus(KeyStatusType.ENABLED) 668 .setOutputPrefixType(OutputPrefixType.LEGACY) 669 .build(); 670 671 PrimitiveSet<Mac> pset = 672 PrimitiveSet.newBuilder(Mac.class) 673 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key1), key1) 674 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key2), key2) 675 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key3), key3) 676 .build(); 677 678 assertThat(pset.getAll()).hasSize(3); 679 assertThat(pset.getPrimitive(Hex.decode("01ffffffff"))).hasSize(1); 680 assertThat(pset.getPrimitive(Hex.decode("01ffffffef"))).isEmpty(); 681 assertThat(pset.getPrimitive(Hex.decode("00ffffffff"))).isEmpty(); 682 assertThat(pset.getPrimitive(Hex.decode("00ffffffef"))).hasSize(1); 683 } 684 685 @Test getAllInKeysetOrder_works()686 public void getAllInKeysetOrder_works() throws Exception { 687 Key key0 = 688 Key.newBuilder() 689 .setKeyId(0xffffffff) 690 .setStatus(KeyStatusType.ENABLED) 691 .setOutputPrefixType(OutputPrefixType.TINK) 692 .build(); 693 Key key1 = 694 Key.newBuilder() 695 .setKeyId(0xffffffdf) 696 .setStatus(KeyStatusType.ENABLED) 697 .setOutputPrefixType(OutputPrefixType.RAW) 698 .build(); 699 Key key2 = 700 Key.newBuilder() 701 .setKeyId(0xffffffef) 702 .setStatus(KeyStatusType.ENABLED) 703 .setOutputPrefixType(OutputPrefixType.LEGACY) 704 .build(); 705 PrimitiveSet<Mac> pset = 706 PrimitiveSet.newBuilder(Mac.class) 707 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key0), key0) 708 .addPrimaryFullPrimitive(new DummyMac2(), getKeyFromProtoKey(key1), key1) 709 .addFullPrimitive(new DummyMac1(), getKeyFromProtoKey(key2), key2) 710 .build(); 711 712 List<PrimitiveSet.Entry<Mac>> entries = pset.getAllInKeysetOrder(); 713 assertThat(entries).hasSize(3); 714 assertThat(entries.get(0).getOutputPrefixType()).isEqualTo(OutputPrefixType.TINK); 715 assertThat(entries.get(1).getOutputPrefixType()).isEqualTo(OutputPrefixType.RAW); 716 assertThat(entries.get(2).getOutputPrefixType()).isEqualTo(OutputPrefixType.LEGACY); 717 } 718 } 719