I will be signing a token with SHA256 and I am wondering on the length of the secret I should put. Does having a secret key length over 256 bits have any benefits if I am using sha256. So if my key is 300 bits long is this more secure?
HMAC + SHA256 jwt secret length
cryptographyhashjwt
Related Solutions
Share the password
(a char[]
) and salt
(a byte[]
—8 bytes selected by a SecureRandom
makes a good salt—which doesn't need to be kept secret) with the recipient out-of-band. Then to derive a good key from this information:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
The magic numbers (which could be defined as constants somewhere) 65536 and 256 are the key derivation iteration count and the key size, respectively.
The key derivation function is iterated to require significant computational effort, and that prevents attackers from quickly trying many different passwords. The iteration count can be changed depending on the computing resources available.
The key size can be reduced to 128 bits, which is still considered "strong" encryption, but it doesn't give much of a safety margin if attacks are discovered that weaken AES.
Used with a proper block-chaining mode, the same derived key can be used to encrypt many messages. In Cipher Block Chaining (CBC), a random initialization vector (IV) is generated for each message, yielding different cipher text even if the plain text is identical. CBC may not be the most secure mode available to you (see AEAD below); there are many other modes with different security properties, but they all use a similar random input. In any case, the outputs of each encryption operation are the cipher text and the initialization vector:
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes(StandardCharsets.UTF_8));
Store the ciphertext
and the iv
. On decryption, the SecretKey
is regenerated in exactly the same way, using using the password with the same salt and iteration parameters. Initialize the cipher with this key and the initialization vector stored with the message:
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), StandardCharsets.UTF_8);
System.out.println(plaintext);
Java 7 included API support for AEAD cipher modes, and the "SunJCE" provider included with OpenJDK and Oracle distributions implements these beginning with Java 8. One of these modes is strongly recommended in place of CBC; it will protect the integrity of the data as well as their privacy.
A java.security.InvalidKeyException
with the message "Illegal key size or default parameters" means that the cryptography strength is limited; the unlimited strength jurisdiction policy files are not in the correct location. In a JDK, they should be placed under ${jdk}/jre/lib/security
Based on the problem description, it sounds like the policy files are not correctly installed. Systems can easily have multiple Java runtimes; double-check to make sure that the correct location is being used.
The standard Oracle JDK 7 implementation uses what's called a Linear Congruential Generator to produce random values in java.util.Random
.
Taken from java.util.Random
source code (JDK 7u2), from a comment on the method protected int next(int bits)
, which is the one that generates the random values:
This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer and described by Donald E. Knuth in The Art of Computer Programming, Volume 3: Seminumerical Algorithms, section 3.2.1.
Predictability of Linear Congruential Generators
Hugo Krawczyk wrote a pretty good paper about how these LCGs can be predicted ("How to predict congruential generators"). If you're lucky and interested, you may still find a free, downloadable version of it on the web. And there's plenty more research that clearly shows that you should never use an LCG for security-critical purposes. This also means that your random numbers are predictable right now, something you don't want for session IDs and the like.
How to break a Linear Congruential Generator
The assumption that an attacker would have to wait for the LCG to repeat after a full cycle is wrong. Even with an optimal cycle (the modulus m in its recurrence relation) it is very easy to predict future values in much less time than a full cycle. After all, it's just a bunch of modular equations that need to be solved, which becomes easy as soon as you have observed enough output values of the LCG.
The security doesn't improve with a "better" seed. It simply doesn't matter if you seed with a random value generated by SecureRandom
or even produce the value by rolling a die several times.
An attacker will simply compute the seed from the output values observed. This takes significantly less time than 2^48 in the case of java.util.Random
. Disbelievers may try out this experiment, where it is shown that you can predict future Random
outputs observing only two(!) output values in time roughly 2^16. It takes not even a second on a modern computer to predict the output of your random numbers right now.
Conclusion
Replace your current code. Use SecureRandom
exclusively. Then at least you will have a little guarantee that the result will be hard to predict. If you want the properties of a cryptographically secure PRNG (in your case, that's what you want), then you have to go with SecureRandom
only. Being clever about changing the way it was supposed to be used will almost always result in something less secure...
Best Answer
The length of the key has to be <= 512 bits because that is the size of the pads. If someone is trying to brute force your key, having a key size of 512 bits will be the most secure.
So to answer your question. Yes, having a key length 300 bits is more secure than one with length 256 bits.