0

The following groovy/java code does ecnrypt given string with password and iv.

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;

byte[] iv = "1234567812345678";
byte[] keyb = "ABCDEFGHIJKLMNOPQRSTUVWX";

IvParameterSpec ivspec = new IvParameterSpec(iv);
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");

Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);

String plainText = "Encrypt this text with AES - MODE CBC";

byte[] input = plainText.getBytes("UTF-8");
byte[] encoded = ci.doFinal(input);

System.out.println(encoded.encodeBase64().toString());

I am looking for some guidance on how can I add both salt and iterations to the process.

Yeti
  • 1,108
  • 19
  • 28
Luke G
  • 1,741
  • 6
  • 23
  • 34

1 Answers1

2

I believe you are thinking of Password Based Encryption (PBE). To do this in Java, you are going to want something like this (source):

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

public static byte[] encrypt(final byte[] data, final char[] password,
    final byte[] salt, final int noIterations) {
  try {
    final String method = "PBEWITHHMACSHA512ANDAES_256";
    final SecretKeyFactory kf = SecretKeyFactory.getInstance(method);
    final PBEKeySpec keySpec = new PBEKeySpec(password);
    final SecretKey key = kf.generateSecret(keySpec);
    final Cipher ciph = Cipher.getInstance(method);
    final PBEParameterSpec params = new PBEParameterSpec(salt, noIterations);
    return ciph.doFinal(data);
  } catch (final Exception e) {
    // best not to let the encryption error bubble out
    throw new RuntimeException("Spurious encryption error");
  }
}
Jeff Brower
  • 594
  • 3
  • 13
  • Regarding thee salt, I suggest it contain two elements, one fixed and unique for the application, another a variable such as the user id. These two will ensure that the same password will not generate the same key for two users or for the same user in two applications. – Jonathan Rosenne Aug 31 '18 at 11:23
  • @JonathanRosenne Perhaps even better would be to store the salt along with the ciphertext, that way you can generate a random salt (using [SecureRandom.nextBytes](https://docs.oracle.com/javase/10/docs/api/java/security/SecureRandom.html#nextBytes(byte%5B%5D))) with every encrypted value. This prevents dictionary attacks and solves the issue you mentioned. – Jeff Brower Aug 31 '18 at 11:34
  • Storing the random salt creates another exposure, it the database gets hacked. The fixed unique element of the salt is not stored in the database. – Jonathan Rosenne Aug 31 '18 at 11:37
  • @JonathanRosenne Check out [this answer](https://stackoverflow.com/a/1219908/10070933). Knowing the salt is only helpful for an attacker if it is known ahead of time. If it's in the same place as the encrypted password, it is no help to the attacker. There is *no harm* in storing the salt in plaintext in the database. – Jeff Brower Aug 31 '18 at 11:43
  • See [NIST Special Publication 800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html#verifier-secrets): "The secret salt value SHALL be stored separately from the hashed memorized secrets (e.g., in a specialized device like a hardware security module). With this additional iteration, brute-force attacks on the hashed memorized secrets are impractical as long as the secret salt value remains secret". While addressing a different issue, it explains the exposure of off-line cracking. – Jonathan Rosenne Aug 31 '18 at 12:29