0
votes

I wanted to implement a custom secret key with AES encryption and I have found the following implementation and details about doing so.

byte[] key = (SALT2 + username + my_custom_secret_key).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

But I have the following doubts:

byte[] my_key = (SALT2 + username + my_custom_secret_key).getBytes("UTF-8");
SecretKeySpec secretKeySpec = new SecretKeySpec(my_key, "AES");

If I were to use typical sample codes like:

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
  1. How/where should I store my secret key i.e. "mysecretkey_123456"
  2. Why is there a need to "hash" the combination of "(SALT2 + username + password)" using SHA-1/2 and pass the byte[] array to the SecretKeySpec?
  3. Why can't I send the cleartext secret key as byte[] ?
  4. I am trying to ensure the "key" is dynamic so that it is based on a salt+username+my_custom_secret_key, so that the same encrypted string will have different output.

Java AES and using my own Key

https://www.securecoding.cert.org/confluence/display/java/MSC61-J.+Do+not+use+insecure+or+weak+cryptographic+algorithms

How to generate SALT value in Java?

1

1 Answers

2
votes

Answers to your doubts:

  1. How/where should I store my secret key i.e. "mysecretkey_123456"?

That depends. What I'm looking at seems to be a password rather than a key. So storing it inside your head or a password manager would be advised.

  1. Why is there a need to "hash" the combination of "(SALT2 + username + password)" using SHA-1/2 and pass the byte[] array to the SecretKeySpec?

This is because an AES key consists of exactly 16, 24 or 32 bytes that should be random to an attacker. A password neither has a consistent length nor the randomness required.

What the code segment does is to create a password hashing function or password based key derivation function (PBKDF). Of course just using SHA-1 doesn't cut it, you should use PBKDF2 or one of bcrypt, scrypt or Argon2. Then configure one of these functions with a high work factor (or iteration count) to provide for key strengthening. PBKDF2 - albeit not the greatest - is part of the Java runtime environment, making it relatively easy to deploy.

In case your "cleartext key" called my_custom_secret_key already has a strength of 128 bits or more then you could use a Key Based Key Derivation Function such as HKDF instead.

  1. Why can't I send the cleartext secret key as byte[] ?

Who says you can't? The code sample seems to mistaken a key and a password, so I presume that's where the confusion comes from. You would generally use bytes for high entropy secret keys.

For passwords using char[] is advised; this is because you cannot destroy the contents of a String after you've used it for verifying the password or deriving the key. A char[] on the other hand can be cleared by filling it with zeros directly after use. This works equally well on keys stored in a byte[] of course.

  1. I am trying to ensure the "key" is dynamic so that it is based on a salt+username+my_custom_secret_key, so that the same encrypted string will have different output.

That will work as long as the salt is large and random enough, say 16 bytes SecureRandom regenerated every time a salt is required for encryption.

That way the generated key will always be random enough and your encryption would be safe when using a secure mode (i.e. any mode build in Java but ECB, preferably something like GCM mode encryption).