Skip to content

Commit

Permalink
Add method for generating secret key (smallrye#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
ejba committed Jan 31, 2021
1 parent 8a24d88 commit e25e178
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 30 deletions.
5 changes: 5 additions & 0 deletions implementation/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-processor</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,36 @@
* @see <a href="https://tools.ietf.org/html/rfc7518#section-4">https://tools.ietf.org/html/rfc7518#section-4</a>
*/
public enum KeyEncryptionAlgorithm {
RSA_OAEP("RSA-OAEP"),
RSA_OAEP_256("RSA-OAEP-256"),
ECDH_ES("ECDH-ES"),
ECDH_ES_A28KW("ECDH-ES+128KW"),
ECDH_ES_A192KW("ECDH-ES+192KW"),
ECDH_ES_A256KW("ECDH-ES+A256KW"),
A128KW("A128KW"),
A192KW("A192KW"),
A256KW("A256KW"),
PBES2_HS256_A128KW("PBES2-HS256+A128KW"),
PBES2_HS384_A192KW("PBES2-HS384+A192KW"),
PBES2_HS512_A256KW("PBES2-HS512+A256KW");
RSA_OAEP("RSA-OAEP", 2048),
RSA_OAEP_256("RSA-OAEP-256", 2048),
ECDH_ES("ECDH-ES", 256),
ECDH_ES_A128KW("ECDH-ES+128KW", 128),
ECDH_ES_A192KW("ECDH-ES+192KW", 192),
ECDH_ES_A256KW("ECDH-ES+A256KW", 256),
A128KW("A128KW", 128),
A192KW("A192KW", 192),
A256KW("A256KW", 256),
PBES2_HS256_A128KW("PBES2-HS256+A128KW", 256),
PBES2_HS384_A192KW("PBES2-HS384+A192KW", 384),
PBES2_HS512_A256KW("PBES2-HS512+A256KW", 512);

private String algorithmName;
private int keySizeBits;

private KeyEncryptionAlgorithm(String algorithmName) {
private KeyEncryptionAlgorithm(String algorithmName, int keySizeBits) {
this.algorithmName = algorithmName;
}

public String getAlgorithm() {
return algorithmName;
this.keySizeBits = keySizeBits;
}

public static KeyEncryptionAlgorithm fromAlgorithm(String algorithmName) {
return KeyEncryptionAlgorithm.valueOf(algorithmName.replaceAll("-", "_").replaceAll("\\+", "_"));
}

public int getKeySizeBits() {
return keySizeBits;
}

public String getAlgorithm() {
return algorithmName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@
* @see <a href="https://tools.ietf.org/html/rfc7518#section-3">https://tools.ietf.org/html/rfc7518#section-3</a>
*/
public enum SignatureAlgorithm {
RS256,
RS384,
RS512,
ES256,
ES384,
ES512,
HS256,
HS384,
HS512,
PS256,
PS384,
PS512;
RS256(256),
RS384(384),
RS512(512),
ES256(256),
ES384(384),
ES512(512),
HS256(256),
HS384(384),
HS512(512),
PS256(256),
PS384(384),
PS512(512);

private int keySize;

private SignatureAlgorithm(int keySize) {
this.keySize = keySize;
}

public int getKeySizeBits() {
return this.keySize;
}

public String getAlgorithm() {
return this.name();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.smallrye.jwt.algorithm;

public enum SymmetricKeyAlgorithm {
HS256("HS256", 256),
HS384("HS384", 384),
HS512("HS512", 512);

private String algorithmName;
private int keySize;

private SymmetricKeyAlgorithm(String algorithmName, int keySize) {
this.algorithmName = algorithmName;
this.keySize = keySize;
}

public String getAlgorithm() {
return algorithmName;
}

public int getKeySize() {
return keySize;
}

public static SymmetricKeyAlgorithm fromAlgorithm(String algorithmName) {
return SymmetricKeyAlgorithm.valueOf(algorithmName.replaceAll("-", "_").replaceAll("\\+", "_"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
Expand Down Expand Up @@ -64,6 +65,7 @@ public final class KeyUtils {

private static final String RSA = "RSA";
private static final String EC = "EC";
private static final String HMAC = "HMAC";

private KeyUtils() {
}
Expand Down Expand Up @@ -243,7 +245,47 @@ public static PublicKey decodePublicKey(String pemEncoded) throws GeneralSecurit

public static SecretKey createSecretKeyFromSecret(String secret) {
byte[] secretBytes = secret.getBytes(StandardCharsets.UTF_8);
return new SecretKeySpec(secretBytes, "AES");
return createSecretKeyFromSecret(secretBytes, "AES");
}

public static SecretKey createSecretKeyFromSecret(byte[] secretBytes, String algo) {
return new SecretKeySpec(secretBytes, algo);
}

/**
* Generates a SecretKey.
*
* @param algo key encryption algorithm.
* @return SecretKey.
* @throws NoSuchAlgorithmException algorithm not found.
*/
public static SecretKey generateSecretKey(KeyEncryptionAlgorithm algo) throws NoSuchAlgorithmException {
final String algoName = getSymmetricAlgoName(algo);

int keySizeBits = algo.getKeySizeBits() / 8;
byte[] bytes = new byte[keySizeBits];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(bytes);

return createSecretKeyFromSecret(bytes, algoName);
}

/**
* Generates a SecretKey.
*
* @param algo signature algorithm.
* @return SecretKey.
* @throws NoSuchAlgorithmException algorithm not found.
*/
public static SecretKey generateSecretKey(SignatureAlgorithm algo) throws NoSuchAlgorithmException {
final String algoName = getSymmetricAlgoName(algo);

int keySizeBits = algo.getKeySizeBits() / 8;
byte[] bytes = new byte[keySizeBits];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(bytes);

return createSecretKeyFromSecret(bytes, algoName);
}

/**
Expand Down Expand Up @@ -273,6 +315,20 @@ public static PublicKey decodeEncryptionPublicKey(String pemEncoded, KeyEncrypti
return kf.generatePublic(spec);
}

static String getSymmetricAlgoName(KeyEncryptionAlgorithm algo) throws NoSuchAlgorithmException {
if (algo.name().startsWith("PBES2")) {
return HMAC;
}
throw JWTUtilMessages.msg.unsupportedAlgorithm(algo.name());
}

static String getSymmetricAlgoName(SignatureAlgorithm algo) throws NoSuchAlgorithmException {
if (algo.name().startsWith("HS")) {
return HMAC;
}
throw JWTUtilMessages.msg.unsupportedAlgorithm(algo.name());
}

static String keyFactoryAlgorithm(SignatureAlgorithm algo) throws NoSuchAlgorithmException {
if (algo.name().startsWith("RS") || algo.name().startsWith("PS")) {
return RSA;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.smallrye.jwt.util;

import io.smallrye.jwt.algorithm.KeyEncryptionAlgorithm;
import io.smallrye.jwt.algorithm.SignatureAlgorithm;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;

import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class KeyUtilsTest {

@ParameterizedTest
@EnumSource(mode = EnumSource.Mode.INCLUDE, names = { "PBES2_HS256_A128KW", "PBES2_HS384_A192KW", "PBES2_HS512_A256KW" })
void givenSymmetricKey_thenReturnSecretKey(KeyEncryptionAlgorithm algo) throws NoSuchAlgorithmException {
SecretKey keySpec = KeyUtils.generateSecretKey(algo);
assertEquals(algo.getKeySizeBits() / 8, keySpec.getEncoded().length);
assertEquals("HMAC", keySpec.getAlgorithm());
}

@ParameterizedTest
@EnumSource(mode = EnumSource.Mode.EXCLUDE, names = { "PBES2_HS256_A128KW", "PBES2_HS384_A192KW", "PBES2_HS512_A256KW" })
void givenAsSymmetricKey_thenThrowNoSuchAlgorithmException(KeyEncryptionAlgorithm algo) {
assertThrows(NoSuchAlgorithmException.class, () -> KeyUtils.generateSecretKey(algo));
}

@ParameterizedTest
@EnumSource(mode = EnumSource.Mode.INCLUDE, names = { "HS256", "HS384", "HS512" })
void givenSymmetricKey_thenReturnSecretKey(SignatureAlgorithm algo) throws NoSuchAlgorithmException {
SecretKey keySpec = KeyUtils.generateSecretKey(algo);
assertEquals(algo.getKeySizeBits() / 8, keySpec.getEncoded().length);
assertEquals("HMAC", keySpec.getAlgorithm());
}

@ParameterizedTest
@EnumSource(mode = EnumSource.Mode.EXCLUDE, names = { "HS256", "HS384", "HS512" })
void givenAsSymmetricKey_thenThrowNoSuchAlgorithmException(SignatureAlgorithm algo) {
assertThrows(NoSuchAlgorithmException.class, () -> KeyUtils.generateSecretKey(algo));
}
}

0 comments on commit e25e178

Please sign in to comment.