EncryptionKeyCanaryMapper { public void mapUuidsToKeys(final EncryptionKeySet keySet) throws Exception { final List<EncryptionKeyCanary> encryptionKeyCanaries = encryptionKeyCanaryDataService.findAll(); for (final EncryptionKeyProvider provider : encryptionKeysConfiguration.getProviders()) { final EncryptionProvider encryptionService = providerFactory.getEncryptionService(provider); for (final EncryptionKeyMetadata keyMetadata : provider.getKeys()) { final KeyProxy keyProxy = encryptionService.createKeyProxy(keyMetadata); EncryptionKeyCanary matchingCanary = null; for (final EncryptionKeyCanary canary : encryptionKeyCanaries) { if (keyProxy.matchesCanary(canary)) { matchingCanary = canary; break; } } final EncryptionKey encryptionKey = new EncryptionKey(encryptionService, null, keyProxy.getKey(), keyMetadata.getEncryptionKeyName()); if (matchingCanary == null) { if (keyMetadata.isActive()) { matchingCanary = createCanary(keyProxy, encryptionService, encryptionKey); } else { continue; } } if (keyMetadata.isActive()) { keySet.setActive(matchingCanary.getUuid()); } try { encryptionKey.setUuid(matchingCanary.getUuid()); keySet.add(encryptionKey); } catch (final Exception e) { throw new RuntimeException("Failed to connect to encryption provider", e); } } } if (keySet.getActive() == null) { throw new RuntimeException("No active key was found"); } } @Autowired  EncryptionKeyCanaryMapper(
    final EncryptionKeyCanaryDataService encryptionKeyCanaryDataService,
    final EncryptionKeysConfiguration encryptionKeysConfiguration,
    final TimedRetry timedRetry,
    final EncryptionProviderFactory providerFactory
  ); void mapUuidsToKeys(final EncryptionKeySet keySet); void delete(final List<UUID> uuids); static final Charset CHARSET; static final String CANARY_VALUE; static final String DEPRECATED_CANARY_VALUE; static final int CANARY_POPULATION_WAIT_SEC; }
@Test public void mapUuidsToKeys_shouldCreateTheKeys() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); final Collection<EncryptionKey> keys = keySet.getKeys(); assertThat(keys.size(), equalTo(3)); assertThat(keys.stream().map(EncryptionKey::getKey).collect(Collectors.toList()), containsInAnyOrder( activeKey, existingKey1, existingKey2 )); }
@Test public void mapUuidsToKeys_shouldContainAReferenceToActiveKey() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertThat(keySet.getKeys(), hasItem(keySet.getActive())); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_andThereAreNoCanariesInTheDatabase_andKeyCreationIsEnabled_createsAndSavesACanaryToTheDatabase() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); final List<EncryptionKeyCanary> canaries = newArrayList(); when(encryptionKeyCanaryDataService.findAll()).thenReturn(canaries); when(encryptionKeyCanaryDataService.save(any(EncryptionKeyCanary.class))) .thenAnswer(invocation -> { canaries.add(activeKeyCanary); return activeKeyCanary; }); when(encryptionService.encrypt(any(EncryptionKey.class), eq(CANARY_VALUE))).thenReturn(new EncryptedValue( null, "fake-encrypted-value", "fake-nonce")); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertCanaryValueWasEncryptedAndSavedToDatabase(); assertThat(keySet.get(activeCanaryUuid).getKey(), equalTo(activeKey)); assertThat(keySet.getActive().getUuid(), equalTo(activeCanaryUuid)); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_andThereAreNoCanariesInTheDatabase_andKeyCreationIsDisabled_waitsForAnotherProcessToPutACanaryToTheDatabase() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(false); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); final List<EncryptionKeyCanary> noCanaries = newArrayList(); final List<EncryptionKeyCanary> oneCanary = Lists.newArrayList(activeKeyCanary); when(encryptionKeyCanaryDataService.findAll()) .thenReturn(noCanaries) .thenReturn(noCanaries) .thenReturn(oneCanary); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); verify(encryptionKeyCanaryDataService, never()).save(any()); verify(timedRetry).retryEverySecondUntil(eq(600L), any()); assertThat(keySet.getActive().getUuid(), equalTo(activeCanaryUuid)); }
@Test public void mapUuidsToKeys_whenKeyCreationIsDisabled_AndNoKeyIsEverCreated_ThrowsAnException() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(false); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); when(encryptionKeyCanaryDataService.findAll()).thenReturn(newArrayList()); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); exception.expectMessage("Timed out waiting for active key canary to be created"); subject.mapUuidsToKeys(keySet); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_whenThereIsNoMatchingCanaryInTheDatabase_whenDecryptingWithTheWrongKeyRaisesAnInternalException_itShouldCreateACanaryForTheKey() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); final EncryptionKeyCanary nonMatchingCanary = new EncryptionKeyCanary(); nonMatchingCanary.setUuid(UUID.randomUUID()); nonMatchingCanary.setEncryptedCanaryValue("fake-non-matching-encrypted-value".getBytes(UTF_8)); nonMatchingCanary.setNonce("fake-non-matching-nonce".getBytes(UTF_8)); when(encryptionKeyCanaryDataService.findAll()) .thenReturn(asArrayList(nonMatchingCanary)); when(encryptionService .decrypt(activeKey, nonMatchingCanary.getEncryptedCanaryValue(), nonMatchingCanary.getNonce())) .thenThrow(new AEADBadTagException()); when(encryptionKeyCanaryDataService.save(any(EncryptionKeyCanary.class))) .thenReturn(activeKeyCanary); when(encryptionService.encrypt(any(EncryptionKey.class), eq(CANARY_VALUE))).thenReturn(new EncryptedValue( null, "fake-encrypted-value", "fake-nonce")); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertCanaryValueWasEncryptedAndSavedToDatabase(); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_whenThereIsNoMatchingCanaryInTheDatabase_whenDecryptingWithTheWrongKeyRaisesAnHSMException_itShouldCreateACanaryForTheKey() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); final EncryptionKeyCanary nonMatchingCanary = new EncryptionKeyCanary(); nonMatchingCanary.setUuid(UUID.randomUUID()); nonMatchingCanary.setEncryptedCanaryValue("fake-non-matching-encrypted-value".getBytes(UTF_8)); nonMatchingCanary.setNonce("fake-non-matching-nonce".getBytes(UTF_8)); when(encryptionKeyCanaryDataService.findAll()) .thenReturn(asArrayList(nonMatchingCanary)); when(encryptionService .decrypt(activeKey, nonMatchingCanary.getEncryptedCanaryValue(), nonMatchingCanary.getNonce())) .thenThrow(new IllegalBlockSizeException( "Could not process input data: function 'C_Decrypt' returns 0x40")); when(encryptionKeyCanaryDataService.save(any(EncryptionKeyCanary.class))) .thenReturn(activeKeyCanary); when(encryptionService.encrypt(any(EncryptionKey.class), eq(CANARY_VALUE))).thenReturn(new EncryptedValue( null, "fake-encrypted-value", "fake-nonce")); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertCanaryValueWasEncryptedAndSavedToDatabase(); }
@Test public void mapUuidsToKeys_whenThereIsNoActiveKey() throws Exception { final List<EncryptionKeyMetadata> keys = asList(existingKey1Data, existingKey2Data); activeProvider.setKeys(keys); final List<EncryptionKeyProvider> providers = asList(activeProvider); when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders()).thenReturn(providers); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); exception.expectMessage("No active key was found"); subject.mapUuidsToKeys(keySet); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_whenThereIsNoMatchingCanaryInTheDatabase_whenDecryptingWithTheWrongKeyRaisesAnHSMException_throwsTheException() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); final EncryptionKeyCanary nonMatchingCanary = new EncryptionKeyCanary(); nonMatchingCanary.setUuid(UUID.randomUUID()); nonMatchingCanary.setEncryptedCanaryValue("fake-non-matching-encrypted-value".getBytes(UTF_8)); nonMatchingCanary.setNonce("fake-non-matching-nonce".getBytes(UTF_8)); when(encryptionKeyCanaryDataService.findAll()) .thenReturn(asArrayList(nonMatchingCanary)); when(activeKeyProxy.matchesCanary(nonMatchingCanary)) .thenThrow(new RuntimeException(new IllegalBlockSizeException( "I don't know what 0x41 means and neither do you"))); when(encryptionKeyCanaryDataService.save(any(EncryptionKeyCanary.class))) .thenReturn(activeKeyCanary); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); exception.expectMessage("javax.crypto.IllegalBlockSizeException: I don't know what 0x41 means and neither do you"); subject.mapUuidsToKeys(keySet); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_whenThereIsNoMatchingCanaryInTheDatabase_whenDecryptingWithTheWrongKeyReturnsAnIncorrectCanaryValue_createsACanaryForTheKey() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); final EncryptionKeyCanary nonMatchingCanary = new EncryptionKeyCanary(); nonMatchingCanary.setUuid(UUID.randomUUID()); nonMatchingCanary.setEncryptedCanaryValue("fake-non-matching-encrypted-value".getBytes(UTF_8)); nonMatchingCanary.setNonce("fake-non-matching-nonce".getBytes(UTF_8)); when(encryptionKeyCanaryDataService.findAll()) .thenReturn(asArrayList(nonMatchingCanary)); when(encryptionService.decrypt(activeKey, nonMatchingCanary.getEncryptedCanaryValue(), nonMatchingCanary.getNonce())) .thenReturn("different-canary-value"); when(encryptionKeyCanaryDataService.save(any(EncryptionKeyCanary.class))) .thenReturn(activeKeyCanary); when(encryptionService.encrypt(any(EncryptionKey.class), eq(CANARY_VALUE))).thenReturn(new EncryptedValue( null, "fake-encrypted-value", "fake-nonce")); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertCanaryValueWasEncryptedAndSavedToDatabase(); }
@Test public void mapUuidsToKeys_whenTheActiveKeyIsTheOnlyKey_whenThereIsAMatchingCanaryInTheDatabase_shouldMapTheKeyToTheMatchingCanary() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders().get(0).getKeys()).thenReturn(asList(activeKeyData)); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); when(encryptionKeyCanaryDataService.findAll()).thenReturn(asArrayList(activeKeyCanary)); when(encryptionService .decrypt(activeKey, activeKeyCanary.getEncryptedCanaryValue(), activeKeyCanary.getNonce())) .thenReturn(CANARY_VALUE); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertThat(keySet.get(activeCanaryUuid).getKey(), equalTo(activeKey)); verify(encryptionService, times(0)) .encrypt(eq(activeCanaryUuid), eq(activeKey), any(String.class)); assertThat(keySet.getActive().getUuid(), equalTo(activeCanaryUuid)); }
@Test public void mapUuidsToKeys_whenThereAreMultipleKeys_andMatchingCanariesForEveryKey_itShouldReturnAMapBetweenMatchingCanariesAndKeys() throws Exception { activeProvider.setKeys(asList(existingKey1Data, activeKeyData, existingKey2Data)); final List<EncryptionKeyProvider> providers = asList(activeProvider); when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders()).thenReturn(providers); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertThat(keySet.get(activeCanaryUuid).getKey(), equalTo(activeKey)); assertThat(keySet.get(existingCanaryUuid1).getKey(), equalTo(existingKey1)); assertThat(keySet.get(existingCanaryUuid2).getKey(), equalTo(existingKey2)); assertThat(keySet.getInactiveUuids().toArray(), arrayContainingInAnyOrder(existingCanaryUuid1, existingCanaryUuid2)); assertThat(keySet.getActive().getUuid(), equalTo(activeCanaryUuid)); }
@Test public void mapUuidsToKeys_whenThereAreMultipleKeys_andCanariesForKeysWeDontHave_itShouldNotBeIncluded() throws Exception { when(encryptionKeysConfiguration.isKeyCreationEnabled()).thenReturn(true); when(encryptionKeysConfiguration.getProviders()).thenReturn(asList(activeProvider)); when(encryptionKeyCanaryDataService.findAll()) .thenReturn(asArrayList(unknownCanary, activeKeyCanary)); subject = new EncryptionKeyCanaryMapper(encryptionKeyCanaryDataService, encryptionKeysConfiguration, timedRetry, providerFactory); subject.mapUuidsToKeys(keySet); assertThat(keySet.get(activeCanaryUuid).getKey(), equalTo(activeKey)); assertThat(keySet.get(unknownCanaryUuid), equalTo(null)); assertThat(keySet.getActive().getUuid(), equalTo(activeCanaryUuid)); assertThat(keySet.getInactiveUuids().size(), equalTo(0)); }