|
47 | 47 | import javax.crypto.SecretKey;
|
48 | 48 | import java.nio.ByteBuffer;
|
49 | 49 | import java.nio.ByteOrder;
|
| 50 | +import java.security.Key; |
| 51 | +import java.security.NoSuchAlgorithmException; |
| 52 | +import java.security.SecureRandom; |
| 53 | +import java.util.ArrayList; |
50 | 54 | import java.util.Arrays;
|
| 55 | +import java.util.HashMap; |
51 | 56 | import java.util.List;
|
| 57 | +import java.util.Map; |
| 58 | +import java.util.Random; |
52 | 59 | import java.util.stream.Stream;
|
53 | 60 | import java.util.zip.Deflater;
|
54 | 61 |
|
@@ -450,6 +457,39 @@ public void corruptAnyBit() {
|
450 | 457 | }
|
451 | 458 | }
|
452 | 459 |
|
| 460 | + @Test |
| 461 | + public void encryptDifferentKeys() throws Exception { |
| 462 | + RollingKeyManager keyManager = new RollingKeyManager(); |
| 463 | + TransformedRecordSerializer<Message> serializer = TransformedRecordSerializerJCE.newDefaultBuilder() |
| 464 | + .setEncryptWhenSerializing(true) |
| 465 | + .setKeyManager(keyManager) |
| 466 | + .setWriteValidationRatio(1.0) |
| 467 | + .build(); |
| 468 | + |
| 469 | + List<MySimpleRecord> records = new ArrayList<>(); |
| 470 | + for (int i = 0; i < 10; i++) { |
| 471 | + records.add(MySimpleRecord.newBuilder() |
| 472 | + .setRecNo(1000 + i) |
| 473 | + .setNumValue2(i) |
| 474 | + .setStrValueIndexed(SONNET_108) |
| 475 | + .build()); |
| 476 | + } |
| 477 | + |
| 478 | + List<byte[]> serialized = new ArrayList<>(); |
| 479 | + for (MySimpleRecord record : records) { |
| 480 | + serialized.add(serialize(serializer, record)); |
| 481 | + } |
| 482 | + |
| 483 | + assertThat(keyManager.numberOfKeys(), greaterThan(5)); |
| 484 | + |
| 485 | + List<Message> deserialized = new ArrayList<>(); |
| 486 | + for (int i = 0; i < serialized.size(); i++) { |
| 487 | + deserialized.add(deserialize(serializer, Tuple.from(1000L + i), serialized.get(i))); |
| 488 | + } |
| 489 | + |
| 490 | + assertEquals(records, deserialized); |
| 491 | + } |
| 492 | + |
453 | 493 | private boolean isCompressed(byte[] serialized) {
|
454 | 494 | byte headerByte = serialized[0];
|
455 | 495 | return headerByte == TransformedRecordSerializerPrefix.PREFIX_COMPRESSED ||
|
@@ -505,4 +545,49 @@ public RecordSerializer<Message> widen() {
|
505 | 545 | throw new UnsupportedOperationException("cannot widen this serializer");
|
506 | 546 | }
|
507 | 547 | }
|
| 548 | + |
| 549 | + private static class RollingKeyManager implements TransformedRecordSerializerKeyManager { |
| 550 | + private final KeyGenerator keyGenerator; |
| 551 | + private final Map<Integer, SecretKey> keys; |
| 552 | + private final Random random; |
| 553 | + |
| 554 | + public RollingKeyManager() throws NoSuchAlgorithmException { |
| 555 | + keyGenerator = KeyGenerator.getInstance("AES"); |
| 556 | + keyGenerator.init(128); |
| 557 | + keys = new HashMap<>(); |
| 558 | + random = new SecureRandom(); |
| 559 | + } |
| 560 | + |
| 561 | + @Override |
| 562 | + public int getSerializationKey() { |
| 563 | + int newKey = random.nextInt(); |
| 564 | + if (!keys.containsKey(newKey)) { |
| 565 | + keys.put(newKey, keyGenerator.generateKey()); |
| 566 | + } |
| 567 | + return newKey; |
| 568 | + } |
| 569 | + |
| 570 | + @Override |
| 571 | + public Key getKey(final int keyNumber) { |
| 572 | + if (!keys.containsKey(keyNumber)) { |
| 573 | + throw new RecordCoreArgumentException("invalid key number"); |
| 574 | + } |
| 575 | + return keys.get(keyNumber); |
| 576 | + } |
| 577 | + |
| 578 | + @Override |
| 579 | + public String getCipher(final int keyNumber) { |
| 580 | + return CipherPool.DEFAULT_CIPHER; |
| 581 | + } |
| 582 | + |
| 583 | + @Override |
| 584 | + public Random getRandom(final int keyNumber) { |
| 585 | + return random; |
| 586 | + } |
| 587 | + |
| 588 | + public int numberOfKeys() { |
| 589 | + return keys.size(); |
| 590 | + } |
| 591 | + } |
| 592 | + |
508 | 593 | }
|
0 commit comments