package dbathon.web.gvds.misc;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.enterprise.context.ApplicationScoped;
import com.google.common.base.Charsets;

@ApplicationScoped
public class Pbkdf2Service {

  /**
   * TODO: good/more/less?
   */
  private static final int ITERATIONS = 8000;

  /**
   * TODO: maybe cache the hash for some time to reduce the overhead for every request
   */
  public byte[] hashPassword(String password, String salt) {
    final PBEKeySpec spec =
        new PBEKeySpec(password.toCharArray(), salt.getBytes(Charsets.UTF_8), ITERATIONS, 256);

    try {
      final SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
      return secretKeyFactory.generateSecret(spec).getEncoded();
    }
    catch (final NoSuchAlgorithmException | InvalidKeySpecException e) {
      throw new RuntimeException(e);
    }
  }

}

@@ -115,32 +115,109 @@
 ySpecException;%0A
+import java.util.concurrent.TimeUnit;%0Aimport javax.annotation.PostConstruct;%0A
 import javax.cry
@@ -370,251 +370,830 @@
 ts;%0A
-%0A@ApplicationScoped%0Apublic class Pbkdf2Service %7B%0A%0A  /**%0A   * TODO: good/more/less?%0A   */%0A  private static final int ITERATIONS = 8000;%0A%0A  /**%0A   * TODO: maybe cache the hash for some time to reduce the overhead for every request%0A   */%0A  public
+import com.google.common.cache.CacheBuilder;%0Aimport com.google.common.cache.CacheLoader;%0Aimport com.google.common.cache.LoadingCache;%0Aimport com.google.common.collect.ImmutableList;%0A%0A@ApplicationScoped%0Apublic class Pbkdf2Service %7B%0A%0A  /**%0A   * TODO: good/more/less?%0A   */%0A  private static final int ITERATIONS = 8000;%0A%0A  private LoadingCache%3CImmutableList%3CString%3E, byte%5B%5D%3E cache;%0A%0A  @PostConstruct%0A  private void postConstruct() %7B%0A    cache =%0A        CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(1000).build(%0A            new CacheLoader%3CImmutableList%3CString%3E, byte%5B%5D%3E() %7B%0A              @Override%0A              public byte%5B%5D load(ImmutableList%3CString%3E key) throws Exception %7B%0A                return hashPasswordInternal(key.get(0), key.get(1));%0A              %7D%0A            %7D);%0A  %7D%0A%0A  private
  byt
@@ -1208,16 +1208,24 @@
 Password
+Internal
 (String 
@@ -1676,10 +1676,235 @@
  %7D%0A  %7D%0A%0A
+  public byte%5B%5D hashPassword(String password, String salt) %7B%0A    final byte%5B%5D hash = cache.getUnchecked(ImmutableList.of(password, salt));%0A    // clone the array to prevent external modification%0A    return hash.clone();%0A  %7D%0A%0A
 %7D%0A

add caching to Pbkdf2Service