0

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?

ilovetolearn
  • 2,006
  • 5
  • 33
  • 64

1 Answers1

2

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).

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • I wanted to share my so called AES "custom password" between 2 java programs so that we can use the same key to encrypt and decrypt data. How do I protect/store my "custom password" for security reasons? – ilovetolearn May 27 '17 at 01:04
  • The reason I wanted to use a "password" instead of a key is because I wanted the ciphertext to change for every use. i.e. based on every time the server startup, or per user's session, or per user's transaction. – ilovetolearn May 27 '17 at 01:10
  • In a system key store, on a thumb drive, on a protected account, input it during startup, in an encrypted configuration file. Full key management is a bit much to discuss here. When you require completely autonomous application then you may only be able to *obfuscate* the password though. In the end you need to store it somewhere and encrypting it again leads to a chicken-egg problem. – Maarten Bodewes May 27 '17 at 01:10
  • You use the salt for that. Different salt, different derived key. – Maarten Bodewes May 27 '17 at 01:10
  • In this case, Should I send (SALT2 + username + password) or hash(SALT2 + username + password) as a byte[] array to the SecretKeySpec and why? which approach is better? – ilovetolearn May 27 '17 at 01:12
  • As you mention, since I need to exchange data and keys between 2 java programs/processes and it leads to a chicken-egg problem, should I be considering to use self-sign certificates and to encrypt/decrypt the data? since the public keys of Program A and Program B can be exchanged and kept secure in the Java keystore? – ilovetolearn May 27 '17 at 01:14
  • Yes, for processes / sockets you would normally use TLS and (self-signed) certificates. If you try to implement transport mode security yourself you will fail in some horrible unexpected way. Note that although the public keys can be known to attackers you do need to **trust** that the public keys came unchanged from the right source. No security without trust. – Maarten Bodewes May 27 '17 at 01:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/145247/discussion-between-youcanlearnanything-and-maarten-bodewes). – ilovetolearn May 27 '17 at 01:45