package io.jsonwebtoken.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Classes;
import javax.crypto.SecretKey;
import java.security.KeyPair;
/**
* Utility class for securely generating {@link SecretKey}s and {@link KeyPair}s.
*
* @since 0.10.0
*/
public final class Keys {
private static final String MAC = "io.jsonwebtoken.impl.crypto.MacProvider";
private static final String RSA = "io.jsonwebtoken.impl.crypto.RsaProvider";
private static final String EC = "io.jsonwebtoken.impl.crypto.EllipticCurveProvider";
private static final Class[] SIG_ARG_TYPES = new Class[]{SignatureAlgorithm.class};
//prevent instantiation
private Keys() {
}
/**
* Returns a new {@link SecretKey} with a key length suitable for use with the specified {@link SignatureAlgorithm}.
*
*
JWA Specification (RFC 7518), Section 3.2
* requires minimum key lengths to be used for each respective Signature Algorithm. This method returns a
* secure-random generated SecretKey that adheres to the required minimum key length. The lengths are:
*
*
*
* Algorithm |
* Key Length |
*
*
* HS256 |
* 256 bits (32 bytes) |
*
*
* HS384 |
* 384 bits (48 bytes) |
*
*
* HS512 |
* 512 bits (64 bytes) |
*
*
*
* @param alg the {@code SignatureAlgorithm} to inspect to determine which key length to use.
* @return a new {@link SecretKey} instance suitable for use with the specified {@link SignatureAlgorithm}.
* @throws IllegalArgumentException for any input value other than {@link SignatureAlgorithm#HS256},
* {@link SignatureAlgorithm#HS384}, or {@link SignatureAlgorithm#HS512}
*/
public static SecretKey secretKeyFor(SignatureAlgorithm alg) throws IllegalArgumentException {
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
switch (alg) {
case HS256:
case HS384:
case HS512:
return Classes.invokeStatic(MAC, "generateKey", SIG_ARG_TYPES, alg);
default:
String msg = "The " + alg.name() + " algorithm does not support shared secret keys.";
throw new IllegalArgumentException(msg);
}
}
/**
* Returns a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
*
* If the {@code alg} argument is an RSA algorithm, a KeyPair is generated based on the following:
*
*
*
* JWA Algorithm |
* Key Size |
*
*
* RS256 |
* 2048 bits |
*
*
* PS256 |
* 2048 bits |
*
*
* RS384 |
* 3072 bits |
*
*
* PS256 |
* 3072 bits |
*
*
* RS512 |
* 4096 bits |
*
*
* PS512 |
* 4096 bits |
*
*
*
* If the {@code alg} argument is an Elliptic Curve algorithm, a KeyPair is generated based on the following:
*
*
*
* JWA Algorithm |
* Key Size |
* JWA Curve Name |
* ASN1 OID Curve Name |
*
*
* EC256 |
* 256 bits |
* {@code P-256} |
* {@code secp256r1} |
*
*
* EC384 |
* 384 bits |
* {@code P-384} |
* {@code secp384r1} |
*
*
* EC512 |
* 512 bits |
* {@code P-512} |
* {@code secp521r1} |
*
*
*
* @param alg the {@code SignatureAlgorithm} to inspect to determine which asymmetric algorithm to use.
* @return a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
* @throws IllegalArgumentException if {@code alg} equals {@link SignatureAlgorithm#HS256 HS256},
* {@link SignatureAlgorithm#HS384 HS384}, {@link SignatureAlgorithm#HS512 HS512}
* or {@link SignatureAlgorithm#NONE NONE}.
*/
public static KeyPair keyPairFor(SignatureAlgorithm alg) throws IllegalArgumentException {
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
switch (alg) {
case RS256:
case PS256:
case RS384:
case PS384:
case RS512:
case PS512:
return Classes.invokeStatic(RSA, "generateKeyPair", SIG_ARG_TYPES, alg);
case ES256:
case ES384:
case ES512:
return Classes.invokeStatic(EC, "generateKeyPair", SIG_ARG_TYPES, alg);
default:
String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
throw new IllegalArgumentException(msg);
}
}
}