@Test
  public void testDefaultEncryptDecrypt() throws InvalidProtocolBufferException {
    final String METHOD = "testDefaultEncryptDecrypt";
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    byte[] encrypted = service.encrypt(appInstanceBytes, "a");
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("uncrypted length = %d", appInstanceBytes.length));
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("encrypted length = %d", encrypted.length));

    final byte[] decrypted = service.decrypt(encrypted, "a");
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("decrypted length = %d", appInstanceBytes.length));
    final RunRightFastApplicationInstance appInstance2 =
        RunRightFastApplicationInstance.parseFrom(decrypted);
    assertThat(appInstance2, is(equalTo(appInstance)));
  }
/** @author alfio */
@Log
public class EncryptionServiceImplTest {

  private final RunRightFastApplicationInstance appInstance =
      RunRightFastApplicationInstance.newBuilder()
          .setAppDeploymentVersion("201509-1")
          .setAppName(getClass().getSimpleName())
          .setAppVersion("1.0.0")
          .setHost("test-01")
          .setJvmId("123@test-01")
          .setStartedOn(Instant.now().toString())
          .build();

  private final byte[] appInstanceBytes = appInstance.toByteArray();

  private AesCipherService aesCipherService(final int keySize) {
    final AesCipherService aes = new AesCipherService();
    aes.setKeySize(keySize);
    return aes;
  }

  /** Test of getEncryptionKeys method, of class EncryptionServiceImpl. */
  @Test
  public void testGetEncryptionKeys() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    assertThat(service.getEncryptionKeys().size(), is(1));
    assertThat(service.getEncryptionKeys().contains("a"), is(true));
    assertThat(service.getEncryptionKeys().contains("b"), is(false));
  }

  @Test
  public void testDefaultEncryptDecrypt() throws InvalidProtocolBufferException {
    final String METHOD = "testDefaultEncryptDecrypt";
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    byte[] encrypted = service.encrypt(appInstanceBytes, "a");
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("uncrypted length = %d", appInstanceBytes.length));
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("encrypted length = %d", encrypted.length));

    final byte[] decrypted = service.decrypt(encrypted, "a");
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("decrypted length = %d", appInstanceBytes.length));
    final RunRightFastApplicationInstance appInstance2 =
        RunRightFastApplicationInstance.parseFrom(decrypted);
    assertThat(appInstance2, is(equalTo(appInstance)));
  }

  @Test
  public void testBasicEncryptionDecryption() throws InvalidProtocolBufferException {
    final String METHOD = "testBasicEncryptionDecryption";
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    final Encryption encryption = service.encryption("a");
    final Decryption decryption = service.decryption("a");
    byte[] encrypted = encryption.apply(appInstanceBytes);
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("uncrypted length = %d", appInstanceBytes.length));
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("encrypted length = %d", encrypted.length));

    final byte[] decrypted = decryption.apply(encrypted);
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("decrypted length = %d", appInstanceBytes.length));
    final RunRightFastApplicationInstance appInstance2 =
        RunRightFastApplicationInstance.parseFrom(decrypted);
    assertThat(appInstance2, is(equalTo(appInstance)));
  }

  @Test
  public void testDefaultEncryptDecrypt_256KeySize() throws InvalidProtocolBufferException {
    final String METHOD = "testDefaultEncryptDecrypt_256KeySize";
    final AesCipherService aes = aesCipherService(256);
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    byte[] encrypted = service.encrypt(appInstanceBytes, "a");
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("uncrypted length = %d", appInstanceBytes.length));
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("encrypted length = %d", encrypted.length));

    final byte[] decrypted = service.decrypt(encrypted, "a");
    log.logp(
        Level.INFO,
        getClass().getName(),
        METHOD,
        String.format("decrypted length = %d", appInstanceBytes.length));
    final RunRightFastApplicationInstance appInstance2 =
        RunRightFastApplicationInstance.parseFrom(decrypted);
    assertThat(appInstance2, is(equalTo(appInstance)));
  }

  @Test(expected = UnknownSecretKeyException.class)
  public void testInvalidSecretKey_cipherFunctions() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    service.cipherFunctions("b");
  }

  @Test(expected = UnknownSecretKeyException.class)
  public void testInvalidSecretKey_encrypt() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    service.encrypt("data".getBytes(), "b");
  }

  @Test(expected = UnknownSecretKeyException.class)
  public void testInvalidSecretKey_encryption() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    service.encryption("b");
  }

  @Test(expected = UnknownSecretKeyException.class)
  public void testInvalidSecretKey_decrypt() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    service.decrypt(service.encrypt("data".getBytes(), "a"), "b");
  }

  @Test(expected = UnknownSecretKeyException.class)
  public void testInvalidSecretKey_decryption() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder().put("a", aes.generateNewKey()).build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    service.decryption("b");
  }

  @Test(expected = EncryptionServiceException.class)
  public void testInvalidSecretKey_decrypt_with_wrong_key() {
    final AesCipherService aes = new AesCipherService();
    final Map<String, Key> keys =
        ImmutableMap.<String, Key>builder()
            .put("a", aes.generateNewKey())
            .put("b", aes.generateNewKey())
            .build();
    final EncryptionService service = new EncryptionServiceImpl(aes, keys);
    service.decrypt(service.encrypt("data".getBytes(), "a"), "b");
  }

  @Test
  public void testStoringSecretKeys() throws IOException {
    final AesCipherService cipherService = new AesCipherService();
    cipherService.setKeySize(AESKeySizes.KEY_SIZE_256);

    final Key key = cipherService.generateNewKey();
    final byte[] keyBytes = SerializationUtils.serialize(key);
    final ByteString keyByteString = ByteString.copyFrom(keyBytes);

    final String keyName = "GLOBAL";
    final SecretKeys keys =
        SecretKeys.newBuilder().putAllKeys(ImmutableMap.of(keyName, keyByteString)).build();

    final EncryptionService service1 = new EncryptionServiceImpl(cipherService, toKeyMap(keys));

    final byte[] encryptedData = service1.encrypt("data".getBytes(), keyName);
    assertThat("data", is(new String(service1.decrypt(encryptedData, keyName))));

    final File secretKeysFile = new File("build/temp/secretKeys");
    secretKeysFile.getParentFile().mkdirs();
    try (final OutputStream os = new FileOutputStream(secretKeysFile)) {
      keys.writeTo(os);
    }

    final AesCipherService cipherService2 = new AesCipherService();
    cipherService2.setKeySize(AESKeySizes.KEY_SIZE_256);
    try (final InputStream is = new FileInputStream(secretKeysFile)) {
      final EncryptionService service2 =
          new EncryptionServiceImpl(cipherService2, toKeyMap(SecretKeys.parseFrom(is)));
      assertThat("data", is(new String(service2.decrypt(encryptedData, keyName))));
    }
  }
}