mirror of
https://github.com/jwtk/jjwt.git
synced 2025-02-16 17:54:58 +00:00
test cleanup, renamed SymmetricAeadAlgorithm to AeadAlgorithm (symmetric is always required in the JWT RFCs, no need for the extra verbosity)
This commit is contained in:
parent
e6db3da6b0
commit
f77697cef1
@ -15,8 +15,8 @@
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.Key;
|
||||
@ -26,7 +26,7 @@ import java.security.Key;
|
||||
*/
|
||||
public interface JweBuilder extends JwtBuilder<JweBuilder> {
|
||||
|
||||
JweBuilder encryptWith(SymmetricAeadAlgorithm enc);
|
||||
JweBuilder encryptWith(AeadAlgorithm enc);
|
||||
|
||||
JweBuilder withKey(SecretKey key);
|
||||
|
||||
|
@ -17,9 +17,9 @@ package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Deserializer;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.Provider;
|
||||
@ -339,7 +339,7 @@ public interface JwtParserBuilder {
|
||||
@Deprecated
|
||||
JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
|
||||
|
||||
JwtParserBuilder addEncryptionAlgorithms(Collection<SymmetricAeadAlgorithm> encAlgs);
|
||||
JwtParserBuilder addEncryptionAlgorithms(Collection<AeadAlgorithm> encAlgs);
|
||||
|
||||
JwtParserBuilder addSignatureAlgorithms(Collection<SignatureAlgorithm<?,?>> sigAlgs);
|
||||
|
||||
|
@ -20,9 +20,9 @@ import io.jsonwebtoken.Identifiable;
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface SymmetricAeadAlgorithm extends Identifiable, SecretKeyGenerator {
|
||||
public interface AeadAlgorithm extends Identifiable, SecretKeyGenerator {
|
||||
|
||||
AeadResult encrypt(SymmetricAeadRequest request) throws SecurityException;
|
||||
AeadResult encrypt(AeadRequest request) throws SecurityException;
|
||||
|
||||
PayloadSupplier<byte[]> decrypt(DecryptSymmetricAeadRequest request) throws SecurityException;
|
||||
PayloadSupplier<byte[]> decrypt(DecryptAeadRequest request) throws SecurityException;
|
||||
}
|
@ -20,5 +20,5 @@ import javax.crypto.SecretKey;
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface SymmetricAeadRequest extends CryptoRequest<byte[], SecretKey>, AssociatedDataSupplier {
|
||||
public interface AeadRequest extends CryptoRequest<byte[], SecretKey>, AssociatedDataSupplier {
|
||||
}
|
@ -18,5 +18,5 @@ package io.jsonwebtoken.security;
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface DecryptSymmetricAeadRequest extends SymmetricAeadRequest, InitializationVectorSupplier, DigestSupplier {
|
||||
public interface DecryptAeadRequest extends AeadRequest, InitializationVectorSupplier, DigestSupplier {
|
||||
}
|
@ -32,7 +32,7 @@ public final class EncryptionAlgorithms {
|
||||
private static final String BRIDGE_CLASSNAME = "io.jsonwebtoken.impl.security.EncryptionAlgorithmsBridge";
|
||||
private static final Class<?>[] ID_ARG_TYPES = new Class[]{String.class};
|
||||
|
||||
public static Collection<SymmetricAeadAlgorithm> values() {
|
||||
public static Collection<AeadAlgorithm> values() {
|
||||
return Classes.invokeStatic(BRIDGE_CLASSNAME, "values", null, (Object[]) null);
|
||||
}
|
||||
|
||||
@ -45,12 +45,12 @@ public final class EncryptionAlgorithms {
|
||||
* @return the associated Encryption Algorithm instance or {@code null} otherwise.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-5.1">RFC 7518, Section 5.1</a>
|
||||
*/
|
||||
public static SymmetricAeadAlgorithm findById(String id) {
|
||||
public static AeadAlgorithm findById(String id) {
|
||||
Assert.hasText(id, "id cannot be null or empty.");
|
||||
return Classes.invokeStatic(BRIDGE_CLASSNAME, "findById", ID_ARG_TYPES, id);
|
||||
}
|
||||
|
||||
private static SymmetricAeadAlgorithm forId(String id) {
|
||||
private static AeadAlgorithm forId(String id) {
|
||||
Assert.hasText(id, "id cannot be null or empty.");
|
||||
return Classes.invokeStatic(BRIDGE_CLASSNAME, "forId", ID_ARG_TYPES, id);
|
||||
}
|
||||
@ -60,40 +60,40 @@ public final class EncryptionAlgorithms {
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.2.3">RFC 7518, Section 5.2.3</a>. This algorithm
|
||||
* requires a 256 bit (32 byte) key.
|
||||
*/
|
||||
public static final SymmetricAeadAlgorithm A128CBC_HS256 = forId("A128CBC-HS256");
|
||||
public static final AeadAlgorithm A128CBC_HS256 = forId("A128CBC-HS256");
|
||||
|
||||
/**
|
||||
* AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm, as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.2.4">RFC 7518, Section 5.2.4</a>. This algorithm
|
||||
* requires a 384 bit (48 byte) key.
|
||||
*/
|
||||
public static final SymmetricAeadAlgorithm A192CBC_HS384 = forId("A192CBC-HS384");
|
||||
public static final AeadAlgorithm A192CBC_HS384 = forId("A192CBC-HS384");
|
||||
|
||||
/**
|
||||
* AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm, as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.2.5">RFC 7518, Section 5.2.5</a>. This algorithm
|
||||
* requires a 512 bit (64 byte) key.
|
||||
*/
|
||||
public static final SymmetricAeadAlgorithm A256CBC_HS512 = forId("A256CBC-HS512");
|
||||
public static final AeadAlgorithm A256CBC_HS512 = forId("A256CBC-HS512");
|
||||
|
||||
/**
|
||||
* "AES GCM using 128-bit key" as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.3">RFC 7518, Section 5.3</a>. This algorithm requires
|
||||
* a 128 bit (16 byte) key.
|
||||
*/
|
||||
public static final SymmetricAeadAlgorithm A128GCM = forId("A128GCM");
|
||||
public static final AeadAlgorithm A128GCM = forId("A128GCM");
|
||||
|
||||
/**
|
||||
* "AES GCM using 192-bit key" as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.3">RFC 7518, Section 5.3</a>. This algorithm requires
|
||||
* a 192 bit (24 byte) key.
|
||||
*/
|
||||
public static final SymmetricAeadAlgorithm A192GCM = forId("A192GCM");
|
||||
public static final AeadAlgorithm A192GCM = forId("A192GCM");
|
||||
|
||||
/**
|
||||
* "AES GCM using 256-bit key" as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.3">RFC 7518, Section 5.3</a>. This algorithm requires
|
||||
* a 256 bit (32 byte) key.
|
||||
*/
|
||||
public static final SymmetricAeadAlgorithm A256GCM = forId("A256GCM");
|
||||
public static final AeadAlgorithm A256GCM = forId("A256GCM");
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import java.util.Collection;
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final class KeyAlgorithms {
|
||||
|
||||
//prevent instantiation
|
||||
@ -69,15 +70,12 @@ public final class KeyAlgorithms {
|
||||
public static final KeyAlgorithm<SecretKey, SecretKey> A128GCMKW = forId0("A128GCMKW");
|
||||
public static final KeyAlgorithm<SecretKey, SecretKey> A192GCMKW = forId0("A192GCMKW");
|
||||
public static final KeyAlgorithm<SecretKey, SecretKey> A256GCMKW = forId0("A256GCMKW");
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static final RsaKeyAlgorithm RSA1_5 = forId0("RSA1_5");
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static final RsaKeyAlgorithm RSA_OAEP = forId0("RSA-OAEP");
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static final RsaKeyAlgorithm RSA_OAEP_256 = forId0("RSA-OAEP-256");
|
||||
public static final KeyAlgorithm<PbeKey, SecretKey> PBES2_HS256_A128KW = forId0("PBES2-HS256+A128KW");
|
||||
public static final KeyAlgorithm<PbeKey, SecretKey> PBES2_HS384_A192KW = forId0("PBES2-HS384+A192KW");
|
||||
public static final KeyAlgorithm<PbeKey, SecretKey> PBES2_HS512_A256KW = forId0("PBES2-HS512+A256KW");
|
||||
public static final RsaKeyAlgorithm RSA1_5 = forId0("RSA1_5");
|
||||
public static final RsaKeyAlgorithm RSA_OAEP = forId0("RSA-OAEP");
|
||||
public static final RsaKeyAlgorithm RSA_OAEP_256 = forId0("RSA-OAEP-256");
|
||||
|
||||
public static int estimateIterations(KeyAlgorithm<PbeKey, SecretKey> alg, long desiredMillis) {
|
||||
return Classes.invokeStatic(BRIDGE_CLASSNAME, "estimateIterations", ESTIMATE_ITERATIONS_ARG_TYPES, alg, desiredMillis);
|
||||
|
@ -24,7 +24,7 @@ import java.security.Key;
|
||||
*/
|
||||
public interface KeyRequest<K extends Key> extends SecurityRequest, KeySupplier<K> {
|
||||
|
||||
SymmetricAeadAlgorithm getEncryptionAlgorithm();
|
||||
AeadAlgorithm getEncryptionAlgorithm();
|
||||
|
||||
JweHeader getHeader();
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ import java.security.KeyPair;
|
||||
public final class Keys {
|
||||
|
||||
private static final String BRIDGE_CLASSNAME = "io.jsonwebtoken.impl.security.KeysBridge";
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final Class[] TO_PBE_ARG_TYPES = new Class[]{PBEKey.class};
|
||||
|
||||
//prevent instantiation
|
||||
private Keys() {
|
||||
@ -223,10 +225,23 @@ public final class Keys {
|
||||
return asalg.generateKeyPair();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JJWT {@link PbeKey} directly backed by the specified JCA {@link PBEKey}. The returned instance
|
||||
* is directly linked to the specified {@code PBEKey} - a call to either key's {@link SecretKey#destroy() destroy}
|
||||
* method will destroy the other to ensure correct/safe cleanup for both.
|
||||
*
|
||||
* @param key the {@code PBEKey} to represent as a {@code PbeKey} instance.
|
||||
* @return a JJWT {@link PbeKey} instance that wraps the specified JCA {@link PBEKey}
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public static PbeKey toPbeKey(PBEKey key) {
|
||||
return forPbe().forKey(key).build();
|
||||
return Classes.invokeStatic(BRIDGE_CLASSNAME, "toPbeKey", TO_PBE_ARG_TYPES, new Object[]{key});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link PbeKeyBuilder} to use to construct a {@link PbeKey} instance.
|
||||
* @return
|
||||
*/
|
||||
public static PbeKeyBuilder<PbeKey> forPbe() {
|
||||
return Classes.invokeStatic(BRIDGE_CLASSNAME, "forPbe", null, (Object[]) null);
|
||||
}
|
||||
|
@ -22,8 +22,20 @@ import javax.crypto.SecretKey;
|
||||
*/
|
||||
public interface PbeKey extends SecretKey {
|
||||
|
||||
/**
|
||||
* Returns a clone of the underlying password character array represented by this Key. Like all
|
||||
* {@code SecretKey} implementations, if you wish to clear the backing password character array for
|
||||
* safety/security reasons, call the {@link #destroy()} method, ensuring the key instance can no longer
|
||||
* be used.
|
||||
*
|
||||
* @return a clone of the underlying password character array represented by this Key.
|
||||
*/
|
||||
char[] getPassword();
|
||||
|
||||
int getWorkFactor();
|
||||
|
||||
/**
|
||||
* Returns the number of hashing iterations to perform.
|
||||
*
|
||||
* @return the number of hashing iterations to perform.
|
||||
*/
|
||||
int getIterations();
|
||||
}
|
||||
|
@ -15,20 +15,38 @@
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
import javax.crypto.interfaces.PBEKey;
|
||||
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface PbeKeyBuilder<K extends PbeKey> {
|
||||
|
||||
PbeKeyBuilder<K> forKey(PBEKey jcaKey);
|
||||
|
||||
PbeKeyBuilder<K> setPassword(String password);
|
||||
|
||||
/**
|
||||
* Sets the password character array for the constructed key. This does not clone the argument - changes made
|
||||
* to the backing array will be reflected by the constructed key and any {@link PbeKey#destroy()} call will do
|
||||
* the same. This is to ensure that any clearing of the password argument for security/safety reasons also
|
||||
* guarantees the resulting key is also cleared and vice versa.
|
||||
*
|
||||
* @param password password character array for the constructed key
|
||||
* @return this builder for method chaining
|
||||
*/
|
||||
PbeKeyBuilder<K> setPassword(char[] password);
|
||||
|
||||
PbeKeyBuilder<K> setWorkFactor(int workFactor);
|
||||
/**
|
||||
* Sets the number of hashing iterations to perform when deriving an encryption key.
|
||||
*
|
||||
* @param iterations the number of hashing iterations to perform when deriving an encryption key.
|
||||
* @return @return this builder for method chaining
|
||||
*/
|
||||
PbeKeyBuilder<K> setIterations(int iterations);
|
||||
|
||||
/**
|
||||
* Constructs a new {@link PbeKey} that shares the {@link #setPassword(char[]) specified} password character array.
|
||||
* Changes to that char array will be reflected in the returned key, and similarly,
|
||||
* any call to the key's {@link PbeKey#destroy() destroy} method will clear/overwrite the shared char array.
|
||||
* This is to ensure that any clearing of the password char array for security/safety reasons also
|
||||
* guarantees the key is also cleared and vice versa.
|
||||
*
|
||||
* @return a new {@link PbeKey} that shares the {@link #setPassword(char[]) specified} password character array.
|
||||
*/
|
||||
K build();
|
||||
}
|
||||
|
@ -6,14 +6,16 @@ import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.impl.lang.Function;
|
||||
import io.jsonwebtoken.impl.lang.PropagatingExceptionFunction;
|
||||
import io.jsonwebtoken.impl.lang.Services;
|
||||
import io.jsonwebtoken.impl.security.DefaultAeadRequest;
|
||||
import io.jsonwebtoken.impl.security.DefaultKeyRequest;
|
||||
import io.jsonwebtoken.impl.security.DefaultSymmetricAeadRequest;
|
||||
import io.jsonwebtoken.io.SerializationException;
|
||||
import io.jsonwebtoken.io.Serializer;
|
||||
import io.jsonwebtoken.lang.Arrays;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.AeadRequest;
|
||||
import io.jsonwebtoken.security.AeadResult;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyAlgorithms;
|
||||
@ -22,8 +24,6 @@ import io.jsonwebtoken.security.KeyResult;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.PbeKey;
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
import io.jsonwebtoken.security.SymmetricAeadRequest;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.interfaces.PBEKey;
|
||||
@ -33,8 +33,8 @@ import java.util.Map;
|
||||
|
||||
public class DefaultJweBuilder extends DefaultJwtBuilder<JweBuilder> implements JweBuilder {
|
||||
|
||||
private SymmetricAeadAlgorithm enc; // MUST be Symmetric AEAD per https://tools.ietf.org/html/rfc7516#section-4.1.2
|
||||
private Function<SymmetricAeadRequest, AeadResult> encFunction;
|
||||
private AeadAlgorithm enc; // MUST be Symmetric AEAD per https://tools.ietf.org/html/rfc7516#section-4.1.2
|
||||
private Function<AeadRequest, AeadResult> encFunction;
|
||||
|
||||
private KeyAlgorithm<Key, ?> alg;
|
||||
private Function<KeyRequest<Key>, KeyResult> algFunction;
|
||||
@ -65,13 +65,13 @@ public class DefaultJweBuilder extends DefaultJwtBuilder<JweBuilder> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweBuilder encryptWith(final SymmetricAeadAlgorithm enc) {
|
||||
public JweBuilder encryptWith(final AeadAlgorithm enc) {
|
||||
this.enc = Assert.notNull(enc, "Encryption algorithm cannot be null.");
|
||||
Assert.hasText(enc.getId(), "Encryption algorithm id cannot be null or empty.");
|
||||
String encMsg = enc.getId() + " encryption failed.";
|
||||
this.encFunction = wrap(encMsg, new Function<SymmetricAeadRequest, AeadResult>() {
|
||||
this.encFunction = wrap(encMsg, new Function<AeadRequest, AeadResult>() {
|
||||
@Override
|
||||
public AeadResult apply(SymmetricAeadRequest request) {
|
||||
public AeadResult apply(AeadRequest request) {
|
||||
return enc.encrypt(request);
|
||||
}
|
||||
});
|
||||
@ -159,7 +159,7 @@ public class DefaultJweBuilder extends DefaultJwtBuilder<JweBuilder> implements
|
||||
final String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes);
|
||||
byte[] aad = base64UrlEncodedHeader.getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
SymmetricAeadRequest encRequest = new DefaultSymmetricAeadRequest(provider, secureRandom, plaintext, cek, aad);
|
||||
AeadRequest encRequest = new DefaultAeadRequest(provider, secureRandom, plaintext, cek, aad);
|
||||
AeadResult encResult = encFunction.apply(encRequest);
|
||||
|
||||
byte[] iv = Assert.notEmpty(encResult.getInitializationVector(), "Encryption result must have a non-empty initialization vector.");
|
||||
|
@ -61,7 +61,8 @@ import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.DateFormats;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
import io.jsonwebtoken.security.DecryptSymmetricAeadRequest;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.DecryptAeadRequest;
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest;
|
||||
import io.jsonwebtoken.security.InvalidKeyException;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
@ -70,7 +71,6 @@ import io.jsonwebtoken.security.PayloadSupplier;
|
||||
import io.jsonwebtoken.security.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.SignatureAlgorithms;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
import io.jsonwebtoken.security.VerifySignatureRequest;
|
||||
import io.jsonwebtoken.security.WeakKeyException;
|
||||
|
||||
@ -121,7 +121,7 @@ public class DefaultJwtParser implements JwtParser {
|
||||
return locFn(JwsHeader.ALGORITHM, MISSING_JWS_ALG_MSG, SignatureAlgorithmsBridge.REGISTRY, extras);
|
||||
}
|
||||
|
||||
private static Function<JweHeader, SymmetricAeadAlgorithm> encFn(Collection<SymmetricAeadAlgorithm> extras) {
|
||||
private static Function<JweHeader, AeadAlgorithm> encFn(Collection<AeadAlgorithm> extras) {
|
||||
return locFn(JweHeader.ENCRYPTION_ALGORITHM, MISSING_ENC_MSG, EncryptionAlgorithmsBridge.REGISTRY, extras);
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ public class DefaultJwtParser implements JwtParser {
|
||||
|
||||
private final Function<JwsHeader, SignatureAlgorithm<?, ?>> signatureAlgorithmLocator;
|
||||
|
||||
private final Function<JweHeader, SymmetricAeadAlgorithm> encryptionAlgorithmLocator;
|
||||
private final Function<JweHeader, AeadAlgorithm> encryptionAlgorithmLocator;
|
||||
|
||||
private final Function<JweHeader, KeyAlgorithm<?, ?>> keyAlgorithmLocator;
|
||||
|
||||
@ -169,7 +169,7 @@ public class DefaultJwtParser implements JwtParser {
|
||||
this.signingKeyResolver = constantKeyLocator;
|
||||
this.signatureAlgorithmLocator = sigFn(Collections.<SignatureAlgorithm<?, ?>>emptyList());
|
||||
this.keyAlgorithmLocator = keyFn(Collections.<KeyAlgorithm<?, ?>>emptyList());
|
||||
this.encryptionAlgorithmLocator = encFn(Collections.<SymmetricAeadAlgorithm>emptyList());
|
||||
this.encryptionAlgorithmLocator = encFn(Collections.<AeadAlgorithm>emptyList());
|
||||
this.compressionCodecLocator = new CompressionCodecLocator<>(new DefaultCompressionCodecResolver());
|
||||
}
|
||||
|
||||
@ -186,7 +186,7 @@ public class DefaultJwtParser implements JwtParser {
|
||||
CompressionCodecResolver compressionCodecResolver,
|
||||
Collection<SignatureAlgorithm<?, ?>> extraSigAlgs,
|
||||
Collection<KeyAlgorithm<?, ?>> extraKeyAlgs,
|
||||
Collection<SymmetricAeadAlgorithm> extraEncAlgs) {
|
||||
Collection<AeadAlgorithm> extraEncAlgs) {
|
||||
this.provider = provider;
|
||||
this.signingKeyResolver = Assert.notNull(signingKeyResolver, "SigningKeyResolver cannot be null.");
|
||||
this.keyLocator = Assert.notNull(keyLocator, "Key Locator cannot be null.");
|
||||
@ -438,7 +438,7 @@ public class DefaultJwtParser implements JwtParser {
|
||||
if (!Strings.hasText(enc)) {
|
||||
throw new MalformedJwtException(MISSING_ENC_MSG);
|
||||
}
|
||||
final SymmetricAeadAlgorithm encAlg = this.encryptionAlgorithmLocator.apply(jweHeader);
|
||||
final AeadAlgorithm encAlg = this.encryptionAlgorithmLocator.apply(jweHeader);
|
||||
if (encAlg == null) {
|
||||
String msg = "Unrecognized JWE encryption algorithm '" + enc + "'.";
|
||||
throw new UnsupportedJwtException(msg);
|
||||
@ -466,7 +466,7 @@ public class DefaultJwtParser implements JwtParser {
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
||||
DecryptSymmetricAeadRequest decryptRequest =
|
||||
DecryptAeadRequest decryptRequest =
|
||||
new DefaultAeadResult(this.provider, null, bytes, cek, aad, tag, iv);
|
||||
PayloadSupplier<byte[]> result = encAlg.decrypt(decryptRequest);
|
||||
bytes = result.getPayload();
|
||||
|
@ -35,10 +35,10 @@ import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.io.Deserializer;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.Provider;
|
||||
@ -73,7 +73,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
||||
|
||||
private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver();
|
||||
|
||||
private final Collection<SymmetricAeadAlgorithm> extraEncryptionAlgorithms = new LinkedHashSet<>();
|
||||
private final Collection<AeadAlgorithm> extraEncryptionAlgorithms = new LinkedHashSet<>();
|
||||
|
||||
private final Collection<KeyAlgorithm<?, ?>> extraKeyAlgorithms = new LinkedHashSet<>();
|
||||
|
||||
@ -215,8 +215,8 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParserBuilder addEncryptionAlgorithms(Collection<SymmetricAeadAlgorithm> encAlgs) {
|
||||
Assert.notEmpty(encAlgs, "Additional SymmetricAeadAlgorithm collection cannot be null or empty.");
|
||||
public JwtParserBuilder addEncryptionAlgorithms(Collection<AeadAlgorithm> encAlgs) {
|
||||
Assert.notEmpty(encAlgs, "Additional AeadAlgorithm collection cannot be null or empty.");
|
||||
this.extraEncryptionAlgorithms.addAll(encAlgs);
|
||||
return this;
|
||||
}
|
||||
|
@ -69,13 +69,13 @@ public final class Bytes {
|
||||
public static byte[] concat(byte[]... arrays) {
|
||||
int len = 0;
|
||||
int count = Arrays.length(arrays);
|
||||
for(int i = 0; i < count; i++) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
len += arrays[i].length;
|
||||
}
|
||||
byte[] output = new byte[len];
|
||||
int position = 0;
|
||||
if (len > 0) {
|
||||
for(byte[] array : arrays) {
|
||||
for (byte[] array : arrays) {
|
||||
int alen = Arrays.length(array);
|
||||
if (alen > 0) {
|
||||
System.arraycopy(array, 0, output, position, alen);
|
||||
@ -87,7 +87,7 @@ public final class Bytes {
|
||||
}
|
||||
|
||||
public static long bitLength(byte[] bytes) {
|
||||
return bytes == null ? 0 : bytes.length * (long)Byte.SIZE;
|
||||
return bytes == null ? 0 : bytes.length * (long) Byte.SIZE;
|
||||
}
|
||||
|
||||
public static String bitsMsg(long bitLength) {
|
||||
@ -95,7 +95,7 @@ public final class Bytes {
|
||||
}
|
||||
|
||||
public static String bytesMsg(int byteArrayLength) {
|
||||
return bitsMsg((long)byteArrayLength * Byte.SIZE);
|
||||
return bitsMsg((long) byteArrayLength * Byte.SIZE);
|
||||
}
|
||||
|
||||
public static void increment(byte[] a) {
|
||||
|
@ -6,12 +6,12 @@ import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||
import io.jsonwebtoken.impl.lang.ValueGetter;
|
||||
import io.jsonwebtoken.io.Encoders;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyRequest;
|
||||
import io.jsonwebtoken.security.KeyResult;
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -34,7 +34,7 @@ public class AesGcmKeyAlgorithm extends AesAlgorithm implements KeyAlgorithm<Sec
|
||||
|
||||
Assert.notNull(request, "request cannot be null.");
|
||||
final SecretKey kek = assertKey(request);
|
||||
SymmetricAeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null.");
|
||||
AeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null.");
|
||||
final SecretKey cek = Assert.notNull(enc.generateKey(), "Request encryption algorithm cannot generate a null key.");
|
||||
final byte[] iv = ensureInitializationVector(request);
|
||||
final AlgorithmParameterSpec ivSpec = getIvSpec(iv);
|
||||
|
@ -2,12 +2,12 @@ package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyRequest;
|
||||
import io.jsonwebtoken.security.KeyResult;
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -28,7 +28,7 @@ public class AesWrapKeyAlgorithm extends AesAlgorithm implements KeyAlgorithm<Se
|
||||
public KeyResult getEncryptionKey(KeyRequest<SecretKey> request) throws SecurityException {
|
||||
Assert.notNull(request, "request cannot be null.");
|
||||
final SecretKey kek = assertKey(request);
|
||||
SymmetricAeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null.");
|
||||
AeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null.");
|
||||
final SecretKey cek = enc.generateKey();
|
||||
Assert.notNull(cek, "Request encryption algorithm cannot generate a null key.");
|
||||
|
||||
|
@ -1,29 +1,29 @@
|
||||
package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.security.AeadRequest;
|
||||
import io.jsonwebtoken.security.InitializationVectorSupplier;
|
||||
import io.jsonwebtoken.security.SymmetricAeadRequest;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class DefaultSymmetricAeadRequest extends DefaultCryptoRequest<byte[], SecretKey> implements SymmetricAeadRequest, InitializationVectorSupplier {
|
||||
public class DefaultAeadRequest extends DefaultCryptoRequest<byte[], SecretKey> implements AeadRequest, InitializationVectorSupplier {
|
||||
|
||||
private final byte[] IV;
|
||||
|
||||
private final byte[] AAD;
|
||||
|
||||
DefaultSymmetricAeadRequest(Provider provider, SecureRandom secureRandom, byte[] data, SecretKey key, byte[] aad, byte[] iv) {
|
||||
DefaultAeadRequest(Provider provider, SecureRandom secureRandom, byte[] data, SecretKey key, byte[] aad, byte[] iv) {
|
||||
super(provider, secureRandom, data, key);
|
||||
this.AAD = aad;
|
||||
this.IV = iv;
|
||||
}
|
||||
|
||||
public DefaultSymmetricAeadRequest(Provider provider, SecureRandom secureRandom, byte[] data, SecretKey key, byte[] aad) {
|
||||
public DefaultAeadRequest(Provider provider, SecureRandom secureRandom, byte[] data, SecretKey key, byte[] aad) {
|
||||
this(provider, secureRandom, data, key, aad, null);
|
||||
}
|
||||
|
||||
public DefaultSymmetricAeadRequest(byte[] data, SecretKey key, byte[] aad) {
|
||||
public DefaultAeadRequest(byte[] data, SecretKey key, byte[] aad) {
|
||||
this(null, null, data, key, aad, null);
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadResult;
|
||||
import io.jsonwebtoken.security.DecryptSymmetricAeadRequest;
|
||||
import io.jsonwebtoken.security.DecryptAeadRequest;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class DefaultAeadResult extends DefaultSymmetricAeadRequest implements AeadResult, DecryptSymmetricAeadRequest {
|
||||
public class DefaultAeadResult extends DefaultAeadRequest implements AeadResult, DecryptAeadRequest {
|
||||
|
||||
private final byte[] TAG;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.Provider;
|
||||
@ -12,7 +12,7 @@ public class DefaultDecryptionKeyRequest<K extends Key> extends DefaultKeyReques
|
||||
|
||||
private final byte[] payload;
|
||||
|
||||
public DefaultDecryptionKeyRequest(Provider provider, SecureRandom secureRandom, K key, JweHeader header, SymmetricAeadAlgorithm encryptionAlgorithm, byte[] payload) {
|
||||
public DefaultDecryptionKeyRequest(Provider provider, SecureRandom secureRandom, K key, JweHeader header, AeadAlgorithm encryptionAlgorithm, byte[] payload) {
|
||||
super(provider, secureRandom, key, header, encryptionAlgorithm);
|
||||
this.payload = payload;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyRequest;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.Provider;
|
||||
@ -12,12 +12,12 @@ import java.security.SecureRandom;
|
||||
public class DefaultKeyRequest<K extends Key> extends DefaultKeyedRequest<K> implements KeyRequest<K> {
|
||||
|
||||
private final JweHeader header;
|
||||
private final SymmetricAeadAlgorithm encryptionAlgorithm;
|
||||
private final AeadAlgorithm encryptionAlgorithm;
|
||||
|
||||
public DefaultKeyRequest(Provider provider, SecureRandom secureRandom, K key, JweHeader header, SymmetricAeadAlgorithm encryptionAlgorithm) {
|
||||
public DefaultKeyRequest(Provider provider, SecureRandom secureRandom, K key, JweHeader header, AeadAlgorithm encryptionAlgorithm) {
|
||||
super(provider, secureRandom, key);
|
||||
this.header = Assert.notNull(header, "JweHeader cannot be null.");
|
||||
this.encryptionAlgorithm = Assert.notNull(encryptionAlgorithm, "SymmetricAeadAlgorithm argument cannot be null.");
|
||||
this.encryptionAlgorithm = Assert.notNull(encryptionAlgorithm, "AeadAlgorithm argument cannot be null.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -26,7 +26,7 @@ public class DefaultKeyRequest<K extends Key> extends DefaultKeyedRequest<K> imp
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymmetricAeadAlgorithm getEncryptionAlgorithm() {
|
||||
public AeadAlgorithm getEncryptionAlgorithm() {
|
||||
return this.encryptionAlgorithm;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Objects;
|
||||
import io.jsonwebtoken.security.PbeKey;
|
||||
|
||||
@ -8,27 +9,17 @@ public class DefaultPbeKey implements PbeKey {
|
||||
private static final String RAW_FORMAT = "RAW";
|
||||
private static final String NONE_ALGORITHM = "NONE";
|
||||
|
||||
private volatile boolean destroyed = false;
|
||||
private volatile boolean destroyed;
|
||||
private final char[] chars;
|
||||
//private final byte[] bytes;
|
||||
private final int workFactor;
|
||||
private final int iterations;
|
||||
|
||||
// private static byte[] toBytes(char[] chars) {
|
||||
// ByteBuffer buf = StandardCharsets.UTF_8.encode(CharBuffer.wrap(chars));
|
||||
// byte[] bytes = new byte[buf.limit()];
|
||||
// buf.get(bytes);
|
||||
// return bytes;
|
||||
// }
|
||||
|
||||
public DefaultPbeKey(char[] password, int workFactor) {
|
||||
boolean empty = Objects.isEmpty(password);
|
||||
this.chars = empty ? new char[0] : password.clone();
|
||||
//this.bytes = empty ? new byte[0] : toBytes(this.chars);
|
||||
if (workFactor < 0) {
|
||||
String msg = "workFactor cannot be negative. Value: " + workFactor;
|
||||
public DefaultPbeKey(char[] password, int iterations) {
|
||||
if (iterations <= 0) {
|
||||
String msg = "iterations must be a positive integer. Value: " + iterations;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
this.workFactor = workFactor;
|
||||
this.iterations = iterations;
|
||||
this.chars = Assert.notEmpty(password, "Password character array cannot be null or empty.");
|
||||
}
|
||||
|
||||
private void assertActive() {
|
||||
@ -45,8 +36,8 @@ public class DefaultPbeKey implements PbeKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorkFactor() {
|
||||
return this.workFactor;
|
||||
public int getIterations() {
|
||||
return this.iterations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,16 +53,11 @@ public class DefaultPbeKey implements PbeKey {
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
throw new UnsupportedOperationException("getEncoded is not supported for PbeKey instances.");
|
||||
//assertActive();
|
||||
//return this.bytes.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// if (bytes != null) {
|
||||
// java.util.Arrays.fill(bytes, (byte) 0);
|
||||
// }
|
||||
if (chars != null) {
|
||||
if (!destroyed && chars != null) {
|
||||
java.util.Arrays.fill(chars, '\u0000');
|
||||
}
|
||||
this.destroyed = true;
|
||||
@ -91,7 +77,7 @@ public class DefaultPbeKey implements PbeKey {
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof DefaultPbeKey) {
|
||||
DefaultPbeKey other = (DefaultPbeKey) obj;
|
||||
return this.workFactor == other.workFactor &&
|
||||
return this.iterations == other.iterations &&
|
||||
Objects.nullSafeEquals(this.chars, other.chars);
|
||||
}
|
||||
return false;
|
||||
@ -99,6 +85,6 @@ public class DefaultPbeKey implements PbeKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "password=<redacted>, workFactor=" + this.workFactor;
|
||||
return "password=<redacted>, iterations=" + this.iterations;
|
||||
}
|
||||
}
|
||||
|
@ -4,93 +4,26 @@ import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.PbeKey;
|
||||
import io.jsonwebtoken.security.PbeKeyBuilder;
|
||||
|
||||
import javax.crypto.interfaces.PBEKey;
|
||||
import javax.security.auth.Destroyable;
|
||||
|
||||
//
|
||||
// MAINTAINER NOTE:
|
||||
//
|
||||
// If editing/modifying this class, DO NOT attempt to call jcaKey.getPassword(): doing so creates a clone of that
|
||||
// character array. There is no need to create copies of sensitive data (that we would be responsible for cleaning up)
|
||||
// since the JcaPbeKey implementation will just delegate to the jcaKey as needed.
|
||||
//
|
||||
public class DefaultPbeKeyBuilder<K extends PbeKey> implements PbeKeyBuilder<K>, Destroyable {
|
||||
public class DefaultPbeKeyBuilder implements PbeKeyBuilder<PbeKey> {
|
||||
|
||||
private char[] password;
|
||||
private int workFactor;
|
||||
private PBEKey jcaKey;
|
||||
private volatile boolean destroyed;
|
||||
|
||||
private static char[] assertPassword(char[] password) {
|
||||
Assert.notEmpty(password, "Password cannot be null or empty.");
|
||||
return password;
|
||||
}
|
||||
|
||||
private static int assertWorkFactor(int workFactor) {
|
||||
if (workFactor < 0) {
|
||||
String msg = "workFactor cannot be negative.";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
return workFactor;
|
||||
}
|
||||
private int iterations;
|
||||
|
||||
@Override
|
||||
public PbeKeyBuilder<K> forKey(PBEKey jcaKey) {
|
||||
this.jcaKey = Assert.notNull(jcaKey, "PBEKey cannot be null.");
|
||||
public DefaultPbeKeyBuilder setPassword(final char[] password) {
|
||||
this.password = Assert.notEmpty(password, "password cannot be null or empty.");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PbeKeyBuilder<K> setPassword(String password) {
|
||||
return setPassword(Assert.notNull(password, "password cannot be null.").toCharArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultPbeKeyBuilder<K> setPassword(char[] password) {
|
||||
this.password = password;
|
||||
public DefaultPbeKeyBuilder setIterations(final int iterations) {
|
||||
Assert.isTrue(iterations > 0, "iterations must be a positive integer.");
|
||||
this.iterations = iterations;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultPbeKeyBuilder<K> setWorkFactor(int workFactor) {
|
||||
this.workFactor = workFactor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.password != null) {
|
||||
destroyed = true;
|
||||
java.util.Arrays.fill(this.password, '\u0000');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
private void assertActive() {
|
||||
if (destroyed) {
|
||||
String msg = "This PbeKeyBuilder has been destroyed in order to clean/zero-out internal password " +
|
||||
"arrays for safety. Please use a new builder for each PbeKey instance you need to create.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public K build() {
|
||||
try {
|
||||
if (this.jcaKey != null) {
|
||||
return (K) new JcaPbeKey(this.jcaKey);
|
||||
}
|
||||
assertActive();
|
||||
assertPassword(this.password);
|
||||
assertWorkFactor(this.workFactor);
|
||||
return (K) new DefaultPbeKey(this.password, this.workFactor);
|
||||
} finally {
|
||||
destroy();
|
||||
}
|
||||
public PbeKey build() {
|
||||
return new DefaultPbeKey(this.password, this.iterations);
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest;
|
||||
import io.jsonwebtoken.security.KeyRequest;
|
||||
import io.jsonwebtoken.security.KeyResult;
|
||||
import io.jsonwebtoken.security.RsaKeyAlgorithm;
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -35,7 +35,7 @@ public class DefaultRsaKeyAlgorithm<E extends RSAKey & PublicKey, D extends RSAK
|
||||
public KeyResult getEncryptionKey(final KeyRequest<E> request) throws SecurityException {
|
||||
Assert.notNull(request, "Request cannot be null.");
|
||||
final E kek = Assert.notNull(request.getKey(), "Request key encryption key cannot be null.");
|
||||
SymmetricAeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null.");
|
||||
AeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null.");
|
||||
final SecretKey cek = Assert.notNull(enc.generateKey(), "Request encryption algorithm cannot generate a null key.");
|
||||
|
||||
byte[] ciphertext = execute(request, Cipher.class, new CheckedFunction<Cipher, byte[]>() {
|
||||
|
@ -46,6 +46,8 @@ class DispatchingJwkFactory implements JwkFactory<Key, Jwk<Key>> {
|
||||
@Override
|
||||
public Jwk<Key> createJwk(JwkContext<Key> ctx) {
|
||||
|
||||
Assert.notNull(ctx, "JwkContext cannot be null.");
|
||||
|
||||
final Key key = ctx.getKey();
|
||||
final String kty = Strings.clean(ctx.getType());
|
||||
|
||||
|
@ -4,7 +4,7 @@ import io.jsonwebtoken.UnsupportedJwtException;
|
||||
import io.jsonwebtoken.impl.IdRegistry;
|
||||
import io.jsonwebtoken.impl.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -16,11 +16,11 @@ public class EncryptionAlgorithmsBridge {
|
||||
}
|
||||
|
||||
//For parser implementation - do not expose outside the impl module:
|
||||
public static final Registry<String, SymmetricAeadAlgorithm> REGISTRY;
|
||||
public static final Registry<String, AeadAlgorithm> REGISTRY;
|
||||
|
||||
static {
|
||||
REGISTRY = new IdRegistry<>(Collections.of(
|
||||
(SymmetricAeadAlgorithm) new HmacAesAeadAlgorithm(128),
|
||||
(AeadAlgorithm) new HmacAesAeadAlgorithm(128),
|
||||
new HmacAesAeadAlgorithm(192),
|
||||
new HmacAesAeadAlgorithm(256),
|
||||
new GcmAesAeadAlgorithm(128),
|
||||
@ -29,18 +29,18 @@ public class EncryptionAlgorithmsBridge {
|
||||
));
|
||||
}
|
||||
|
||||
public static Collection<SymmetricAeadAlgorithm> values() {
|
||||
public static Collection<AeadAlgorithm> values() {
|
||||
return REGISTRY.values();
|
||||
}
|
||||
|
||||
public static SymmetricAeadAlgorithm findById(String id) {
|
||||
public static AeadAlgorithm findById(String id) {
|
||||
return REGISTRY.apply(id);
|
||||
}
|
||||
|
||||
public static SymmetricAeadAlgorithm forId(String id) {
|
||||
SymmetricAeadAlgorithm alg = findById(id);
|
||||
public static AeadAlgorithm forId(String id) {
|
||||
AeadAlgorithm alg = findById(id);
|
||||
if (alg == null) {
|
||||
String msg = "Unrecognized JWA SymmetricAeadAlgorithm identifier: " + id;
|
||||
String msg = "Unrecognized JWA AeadAlgorithm identifier: " + id;
|
||||
throw new UnsupportedJwtException(msg);
|
||||
}
|
||||
return alg;
|
||||
|
@ -5,11 +5,11 @@ import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||
import io.jsonwebtoken.lang.Arrays;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.RuntimeEnvironment;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.AeadRequest;
|
||||
import io.jsonwebtoken.security.AeadResult;
|
||||
import io.jsonwebtoken.security.DecryptSymmetricAeadRequest;
|
||||
import io.jsonwebtoken.security.DecryptAeadRequest;
|
||||
import io.jsonwebtoken.security.PayloadSupplier;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
import io.jsonwebtoken.security.SymmetricAeadRequest;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -18,7 +18,7 @@ import java.security.spec.AlgorithmParameterSpec;
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class GcmAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadAlgorithm {
|
||||
public class GcmAesAeadAlgorithm extends AesAlgorithm implements AeadAlgorithm {
|
||||
|
||||
//TODO: Remove this static block when JDK 7 support is removed
|
||||
// JDK <= 7 does not support AES GCM mode natively and so BouncyCastle is required
|
||||
@ -33,7 +33,7 @@ public class GcmAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadAl
|
||||
}
|
||||
|
||||
@Override
|
||||
public AeadResult encrypt(final SymmetricAeadRequest req) throws SecurityException {
|
||||
public AeadResult encrypt(final AeadRequest req) throws SecurityException {
|
||||
|
||||
Assert.notNull(req, "Request cannot be null.");
|
||||
final SecretKey key = assertKey(req);
|
||||
@ -65,7 +65,7 @@ public class GcmAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadAl
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayloadSupplier<byte[]> decrypt(final DecryptSymmetricAeadRequest req) throws SecurityException {
|
||||
public PayloadSupplier<byte[]> decrypt(final DecryptAeadRequest req) throws SecurityException {
|
||||
|
||||
Assert.notNull(req, "Request cannot be null.");
|
||||
final SecretKey key = assertKey(req);
|
||||
|
@ -1,15 +1,16 @@
|
||||
package io.jsonwebtoken.impl.security;
|
||||
|
||||
import io.jsonwebtoken.impl.lang.Bytes;
|
||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.AeadRequest;
|
||||
import io.jsonwebtoken.security.AeadResult;
|
||||
import io.jsonwebtoken.security.CryptoRequest;
|
||||
import io.jsonwebtoken.security.DecryptSymmetricAeadRequest;
|
||||
import io.jsonwebtoken.security.DecryptAeadRequest;
|
||||
import io.jsonwebtoken.security.PayloadSupplier;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
import io.jsonwebtoken.security.SignatureRequest;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
import io.jsonwebtoken.security.SymmetricAeadRequest;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -21,7 +22,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class HmacAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadAlgorithm {
|
||||
public class HmacAesAeadAlgorithm extends AesAlgorithm implements AeadAlgorithm {
|
||||
|
||||
private static final String TRANSFORMATION_STRING = "AES/CBC/PKCS5Padding";
|
||||
|
||||
@ -40,9 +41,8 @@ public class HmacAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadA
|
||||
this.SIGALG = sigAlg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") //Used via reflection by io.jsonwebtoken.security.EncryptionAlgorithms
|
||||
public HmacAesAeadAlgorithm(int keyLength) {
|
||||
this(id(keyLength), new MacSignatureAlgorithm(id(keyLength), "HmacSHA" + digestLength(keyLength), keyLength));
|
||||
public HmacAesAeadAlgorithm(int keyBitLength) {
|
||||
this(id(keyBitLength), new MacSignatureAlgorithm(id(keyBitLength), "HmacSHA" + digestLength(keyBitLength), keyBitLength));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,7 +56,7 @@ public class HmacAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadA
|
||||
}
|
||||
|
||||
@Override
|
||||
public AeadResult encrypt(final SymmetricAeadRequest req) {
|
||||
public AeadResult encrypt(final AeadRequest req) {
|
||||
|
||||
Assert.notNull(req, "Request cannot be null.");
|
||||
|
||||
@ -89,7 +89,7 @@ public class HmacAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadA
|
||||
long aadLength = io.jsonwebtoken.lang.Arrays.length(aad);
|
||||
long aadLengthInBits = aadLength * Byte.SIZE;
|
||||
long aadLengthInBitsAsUnsignedInt = aadLengthInBits & 0xffffffffL;
|
||||
byte[] AL = toBytes(aadLengthInBitsAsUnsignedInt);
|
||||
byte[] AL = Bytes.toBytes(aadLengthInBitsAsUnsignedInt);
|
||||
|
||||
byte[] toHash = new byte[(int) aadLength + iv.length + ciphertext.length + AL.length];
|
||||
|
||||
@ -113,18 +113,8 @@ public class HmacAesAeadAlgorithm extends AesAlgorithm implements SymmetricAeadA
|
||||
return assertTag(Arrays.copyOfRange(digest, 0, macKeyBytes.length));
|
||||
}
|
||||
|
||||
private static byte[] toBytes(long l) {
|
||||
byte[] b = new byte[8];
|
||||
for (int i = 7; i > 0; i--) {
|
||||
b[i] = (byte) l;
|
||||
l >>>= 8;
|
||||
}
|
||||
b[0] = (byte) l;
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayloadSupplier<byte[]> decrypt(final DecryptSymmetricAeadRequest req) {
|
||||
public PayloadSupplier<byte[]> decrypt(final DecryptAeadRequest req) {
|
||||
|
||||
Assert.notNull(req, "Request cannot be null.");
|
||||
|
||||
|
@ -20,7 +20,7 @@ public class JcaPbeKey implements PbeKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorkFactor() {
|
||||
public int getIterations() {
|
||||
return this.jcaKey.getIterationCount();
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import io.jsonwebtoken.impl.IdRegistry;
|
||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||
import io.jsonwebtoken.impl.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest;
|
||||
import io.jsonwebtoken.security.EncryptionAlgorithms;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
@ -15,7 +16,6 @@ import io.jsonwebtoken.security.KeyResult;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.PbeKey;
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
import io.jsonwebtoken.security.SymmetricAeadAlgorithm;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
@ -101,7 +101,7 @@ public final class KeyAlgorithmsBridge {
|
||||
return new KeyAlgorithm<PbeKey, SecretKey>() {
|
||||
@Override
|
||||
public KeyResult getEncryptionKey(KeyRequest<PbeKey> request) throws SecurityException {
|
||||
int iterations = request.getKey().getWorkFactor();
|
||||
int iterations = request.getKey().getIterations();
|
||||
char[] password = request.getKey().getPassword();
|
||||
try {
|
||||
alg.deriveKey(factory, password, rfcSalt, iterations);
|
||||
@ -148,7 +148,7 @@ public final class KeyAlgorithmsBridge {
|
||||
final int PASSWORD_LENGTH = 8;
|
||||
|
||||
final JweHeader HEADER = new DefaultJweHeader(); // not used during execution, needed to satisfy API call.
|
||||
final SymmetricAeadAlgorithm ENC_ALG = EncryptionAlgorithms.A128GCM; // not used, needed to satisfy API
|
||||
final AeadAlgorithm ENC_ALG = EncryptionAlgorithms.A128GCM; // not used, needed to satisfy API
|
||||
|
||||
if (alg instanceof Pbes2HsAkwAlgorithm) {
|
||||
// Strip away all things that cause time during computation except for the actual hashing algorithm:
|
||||
@ -161,7 +161,7 @@ public final class KeyAlgorithmsBridge {
|
||||
for (int i = 0; points.size() < NUM_SAMPLES; i++) {
|
||||
|
||||
char[] password = randomChars(PASSWORD_LENGTH);
|
||||
PbeKey pbeKey = Keys.forPbe().setPassword(password).setWorkFactor(workFactor).build();
|
||||
PbeKey pbeKey = Keys.forPbe().setPassword(password).setIterations(workFactor).build();
|
||||
KeyRequest<PbeKey> request = new DefaultKeyRequest<>(null, null, pbeKey, HEADER, ENC_ALG);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
@ -3,6 +3,8 @@ package io.jsonwebtoken.impl.security;
|
||||
import io.jsonwebtoken.security.PbeKey;
|
||||
import io.jsonwebtoken.security.PbeKeyBuilder;
|
||||
|
||||
import javax.crypto.interfaces.PBEKey;
|
||||
|
||||
@SuppressWarnings({"unused"}) // reflection bridge class for the io.jsonwebtoken.security.Keys implementation
|
||||
public class KeysBridge {
|
||||
|
||||
@ -10,7 +12,11 @@ public class KeysBridge {
|
||||
private KeysBridge() {
|
||||
}
|
||||
|
||||
public static PbeKey toPbeKey(PBEKey key) {
|
||||
return new JcaPbeKey(key);
|
||||
}
|
||||
|
||||
public static PbeKeyBuilder<PbeKey> forPbe() {
|
||||
return new DefaultPbeKeyBuilder<>();
|
||||
return new DefaultPbeKeyBuilder();
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ public class Pbes2HsAkwAlgorithm extends CryptoAlgorithm implements KeyAlgorithm
|
||||
Assert.notNull(request, "request cannot be null.");
|
||||
final PbeKey pbeKey = Assert.notNull(request.getKey(), "request.getKey() cannot be null.");
|
||||
|
||||
final int iterations = assertIterations(pbeKey.getWorkFactor());
|
||||
final int iterations = assertIterations(pbeKey.getIterations());
|
||||
byte[] inputSalt = generateInputSalt(request);
|
||||
final byte[] rfcSalt = toRfcSalt(inputSalt);
|
||||
final String p2s = Encoders.BASE64URL.encode(inputSalt);
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package io.jsonwebtoken
|
||||
|
||||
import io.jsonwebtoken.SignatureAlgorithm
|
||||
import io.jsonwebtoken.impl.DefaultHeader
|
||||
import io.jsonwebtoken.impl.DefaultJweHeader
|
||||
import io.jsonwebtoken.impl.DefaultJwsHeader
|
||||
@ -25,9 +26,7 @@ import io.jsonwebtoken.impl.lang.Services
|
||||
import io.jsonwebtoken.io.Encoders
|
||||
import io.jsonwebtoken.io.Serializer
|
||||
import io.jsonwebtoken.lang.Strings
|
||||
import io.jsonwebtoken.security.Keys
|
||||
import io.jsonwebtoken.security.SignatureAlgorithms
|
||||
import io.jsonwebtoken.security.WeakKeyException
|
||||
import io.jsonwebtoken.security.*
|
||||
import org.junit.Test
|
||||
|
||||
import javax.crypto.Mac
|
||||
@ -37,6 +36,7 @@ import java.security.Key
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.security.interfaces.RSAPrivateKey
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
@ -815,5 +815,13 @@ class JwtsTest {
|
||||
//noinspection GrEqualsBetweenInconvertibleTypes
|
||||
assert token.body == claims
|
||||
}
|
||||
|
||||
void testFoo() {
|
||||
RSAPrivateKey key;
|
||||
Jwts.jweBuilder()
|
||||
.encryptWith(EncryptionAlgorithms.A128GCM)
|
||||
.usingKey(key)
|
||||
.fromKeyAlgorithm(KeyAlgorithms.PBES2_HS256_A128KW.withIterations(1203023))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ class DefaultJweBuilderTest {
|
||||
|
||||
for( KeyAlgorithm<? extends Key,? extends Key> keyAlg : KeyAlgorithms.values() ) {
|
||||
|
||||
for(SymmetricAeadAlgorithm encAlg : EncryptionAlgorithms.values() ) {
|
||||
for(AeadAlgorithm encAlg : EncryptionAlgorithms.values() ) {
|
||||
Key kek = encAlg.generateKey();
|
||||
String jwe = builder().setSubject('joe').encryptWith(encAlg).withKeyFrom(kek, keyAlg).compact()
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.jsonwebtoken.impl.security
|
||||
|
||||
|
||||
import io.jsonwebtoken.lang.Assert
|
||||
import io.jsonwebtoken.security.Jwks
|
||||
import io.jsonwebtoken.security.RsaPublicJwkBuilder
|
||||
import io.jsonwebtoken.security.SignatureAlgorithms
|
||||
@ -10,12 +10,14 @@ import java.security.cert.X509Certificate
|
||||
import java.security.interfaces.RSAPrivateKey
|
||||
import java.security.interfaces.RSAPublicKey
|
||||
|
||||
import static org.junit.Assert.*
|
||||
import static org.junit.Assert.assertEquals
|
||||
import static org.junit.Assert.assertSame
|
||||
|
||||
class AbstractAsymmetricJwkBuilderTest {
|
||||
|
||||
private static final X509Certificate CERT = CertUtils.readTestCertificate(SignatureAlgorithms.RS256)
|
||||
private static final RSAPublicKey PUB_KEY = (RSAPublicKey)CERT.getPublicKey();
|
||||
private static final List<X509Certificate> CHAIN = [CERT]
|
||||
private static final RSAPublicKey PUB_KEY = (RSAPublicKey) CERT.getPublicKey()
|
||||
|
||||
private static RsaPublicJwkBuilder builder() {
|
||||
return Jwks.builder().setKey(PUB_KEY)
|
||||
@ -28,9 +30,9 @@ class AbstractAsymmetricJwkBuilderTest {
|
||||
assertEquals val, jwk.getPublicKeyUse()
|
||||
assertEquals val, jwk.use
|
||||
|
||||
def privateKey = CertUtils.readTestPrivateKey(SignatureAlgorithms.RS256);
|
||||
def privateKey = CertUtils.readTestPrivateKey(SignatureAlgorithms.RS256)
|
||||
|
||||
jwk = builder().setPublicKeyUse(val).setPrivateKey((RSAPrivateKey)privateKey).build()
|
||||
jwk = builder().setPublicKeyUse(val).setPrivateKey((RSAPrivateKey) privateKey).build()
|
||||
assertEquals val, jwk.getPublicKeyUse()
|
||||
assertEquals val, jwk.use
|
||||
}
|
||||
@ -38,28 +40,25 @@ class AbstractAsymmetricJwkBuilderTest {
|
||||
@Test
|
||||
void testX509Url() {
|
||||
def val = new URI(UUID.randomUUID().toString())
|
||||
assertEquals val, builder().setX509Url(val).build().getX509Url()
|
||||
assertSame val, builder().setX509Url(val).build().getX509Url()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testX509CertificateChain() {
|
||||
def a = UUID.randomUUID().toString()
|
||||
def b = UUID.randomUUID().toString()
|
||||
def val = [a, b] as List<String>
|
||||
assertEquals val, builder().setX509CertificateChain(val).build().getX509CertificateChain()
|
||||
assertEquals CHAIN, builder().setX509CertificateChain(CHAIN).build().getX509CertificateChain()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testX509CertificateSha1Thumbprint() {
|
||||
def val = UUID.randomUUID().toString()
|
||||
assertEquals val, builder().setX509CertificateSha1Thumbprint(val).build().getX509CertificateSha1Thumbprint()
|
||||
def jwk = builder().setX509CertificateChain(CHAIN).withX509Sha1Thumbprint(true).build()
|
||||
Assert.notEmpty(jwk.getX509CertificateSha1Thumbprint())
|
||||
Assert.hasText(jwk.get(AbstractAsymmetricJwk.X509_SHA1_THUMBPRINT) as String)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testX509CertificateSha256Thumbprint() {
|
||||
def val = UUID.randomUUID().toString()
|
||||
assertEquals val, builder().setX509CertificateSha256Thumbprint(val).build().getX509CertificateSha256Thumbprint()
|
||||
def jwk = builder().setX509CertificateChain(CHAIN).withX509Sha256Thumbprint(true).build()
|
||||
Assert.notEmpty(jwk.getX509CertificateSha256Thumbprint())
|
||||
Assert.hasText(jwk.get(AbstractAsymmetricJwk.X509_SHA256_THUMBPRINT) as String)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ import org.junit.Test
|
||||
|
||||
import java.security.SecureRandom
|
||||
|
||||
import static org.junit.Assert.*
|
||||
import static org.junit.Assert.assertSame
|
||||
import static org.junit.Assert.fail
|
||||
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
@ -17,26 +18,6 @@ class AesAlgorithmTest {
|
||||
new TestAesAlgorithm('foo', 'foo', 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoEncryptFailure() {
|
||||
|
||||
def alg = new TestAesAlgorithm('foo', 'foo', 128) {
|
||||
@Override
|
||||
AeadResult encrypt(SymmetricAeadRequest symmetricAeadRequest) throws Exception {
|
||||
throw new IllegalArgumentException('broken')
|
||||
}
|
||||
}
|
||||
|
||||
def req = new DefaultSymmetricAeadRequest('bar'.getBytes(), alg.generateKey(), 'foo'.getBytes());
|
||||
|
||||
try {
|
||||
alg.encrypt(req)
|
||||
} catch (SecurityException expected) {
|
||||
assertTrue expected.getCause() instanceof IllegalArgumentException
|
||||
assertTrue expected.getCause().getMessage().equals('broken')
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAssertKeyLength() {
|
||||
|
||||
@ -60,26 +41,26 @@ class AesAlgorithmTest {
|
||||
|
||||
def secureRandom = new SecureRandom()
|
||||
|
||||
def req = new DefaultSymmetricAeadRequest(null, secureRandom, 'data'.getBytes(), alg.generateKey(), 'aad'.getBytes())
|
||||
def req = new DefaultAeadRequest(null, secureRandom, 'data'.getBytes(), alg.generateKey(), 'aad'.getBytes())
|
||||
|
||||
def returnedSecureRandom = alg.ensureSecureRandom(req)
|
||||
|
||||
assertSame(secureRandom, returnedSecureRandom)
|
||||
}
|
||||
|
||||
static class TestAesAlgorithm extends AesAlgorithm implements SymmetricAeadAlgorithm {
|
||||
static class TestAesAlgorithm extends AesAlgorithm implements AeadAlgorithm {
|
||||
|
||||
TestAesAlgorithm(String name, String transformationString, int requiredKeyLengthInBits) {
|
||||
super(name, transformationString, requiredKeyLengthInBits)
|
||||
}
|
||||
|
||||
@Override
|
||||
AeadResult encrypt(SymmetricAeadRequest symmetricAeadRequest) {
|
||||
AeadResult encrypt(AeadRequest symmetricAeadRequest) {
|
||||
return null
|
||||
}
|
||||
|
||||
@Override
|
||||
PayloadSupplier<byte[]> decrypt(DecryptSymmetricAeadRequest symmetricAeadDecryptionRequest) {
|
||||
PayloadSupplier<byte[]> decrypt(DecryptAeadRequest symmetricAeadDecryptionRequest) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import static org.junit.Assert.*
|
||||
class AesGcmKeyAlgorithmTest {
|
||||
|
||||
/**
|
||||
* This tests asserts that our SymmetricAeadAlgorithm implementation and the JCA 'AES/GCM/NoPadding' wrap algorithm
|
||||
* This tests asserts that our AeadAlgorithm implementation and the JCA 'AES/GCM/NoPadding' wrap algorithm
|
||||
* produce the exact same values. This should be the case when the transformation is identical, even though
|
||||
* one uses Cipher.WRAP_MODE and the other uses a raw plaintext byte array.
|
||||
*/
|
||||
@ -52,7 +52,7 @@ class AesGcmKeyAlgorithmTest {
|
||||
System.arraycopy(jcaResult, ciphertextLength, tag, 0, 16)
|
||||
def resultA = new DefaultAeadResult(null, null, ciphertext, kek, null, tag, iv)
|
||||
|
||||
def encRequest = new DefaultSymmetricAeadRequest(null, null, cek.getEncoded(), kek, null, iv)
|
||||
def encRequest = new DefaultAeadRequest(null, null, cek.getEncoded(), kek, null, iv)
|
||||
def encResult = EncryptionAlgorithms.A256GCM.encrypt(encRequest)
|
||||
|
||||
assertArrayEquals resultA.digest, encResult.digest
|
||||
|
@ -2,11 +2,14 @@ package io.jsonwebtoken.impl.security
|
||||
|
||||
import io.jsonwebtoken.impl.DefaultJweHeader
|
||||
import io.jsonwebtoken.lang.Arrays
|
||||
import io.jsonwebtoken.security.DecryptionKeyRequest
|
||||
import io.jsonwebtoken.security.EncryptionAlgorithms
|
||||
import org.junit.Test
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import java.security.Key
|
||||
|
||||
import static org.easymock.EasyMock.*
|
||||
import static org.junit.Assert.assertEquals
|
||||
import static org.junit.Assert.assertSame
|
||||
|
||||
@ -21,7 +24,7 @@ class DirectKeyAlgorithmTest {
|
||||
void testGetEncryptionKey() {
|
||||
def alg = new DirectKeyAlgorithm()
|
||||
def key = new SecretKeySpec(new byte[1], "AES")
|
||||
def request = new DefaultKeyRequest(null, null, key, key, new DefaultJweHeader(), null)
|
||||
def request = new DefaultKeyRequest(null, null, key, new DefaultJweHeader(), EncryptionAlgorithms.A128GCM)
|
||||
def result = alg.getEncryptionKey(request)
|
||||
assertSame key, result.getKey()
|
||||
assertEquals 0, Arrays.length(result.getPayload()) //must not have an encrypted key
|
||||
@ -35,7 +38,7 @@ class DirectKeyAlgorithmTest {
|
||||
@Test(expected = IllegalArgumentException)
|
||||
void testGetEncryptionKeyWithNullRequestKey() {
|
||||
def key = new SecretKeySpec(new byte[1], "AES")
|
||||
def request = new DefaultKeyRequest(null, null, key, key, new DefaultJweHeader(), null) {
|
||||
def request = new DefaultKeyRequest(null, null, key, new DefaultJweHeader(), EncryptionAlgorithms.A128GCM) {
|
||||
@Override
|
||||
Key getKey() {
|
||||
return null
|
||||
@ -47,9 +50,12 @@ class DirectKeyAlgorithmTest {
|
||||
@Test
|
||||
void testGetDecryptionKey() {
|
||||
def alg = new DirectKeyAlgorithm()
|
||||
def key = new SecretKeySpec(new byte[1], "AES")
|
||||
def request = new DefaultKeyRequest(null, null, key, key, new DefaultJweHeader(), null)
|
||||
def result = alg.getDecryptionKey(request)
|
||||
DecryptionKeyRequest req = createMock(DecryptionKeyRequest)
|
||||
def key = EncryptionAlgorithms.A128GCM.generateKey()
|
||||
expect(req.getKey()).andReturn(key)
|
||||
replay(req)
|
||||
def result = alg.getDecryptionKey(req)
|
||||
verify(req)
|
||||
assertSame key, result
|
||||
}
|
||||
|
||||
@ -60,13 +66,9 @@ class DirectKeyAlgorithmTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException)
|
||||
void testGetDecryptionKeyWithNullRequestKey() {
|
||||
def key = new SecretKeySpec(new byte[1], "AES")
|
||||
def request = new DefaultKeyRequest(null, null, key, key, new DefaultJweHeader(), null) {
|
||||
@Override
|
||||
Key getKey() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
new DirectKeyAlgorithm().getDecryptionKey(request)
|
||||
DecryptionKeyRequest req = createMock(DecryptionKeyRequest)
|
||||
expect(req.getKey()).andReturn(null)
|
||||
replay(req)
|
||||
new DirectKeyAlgorithm().getDecryptionKey(req)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package io.jsonwebtoken.impl.security
|
||||
import io.jsonwebtoken.io.Encoders
|
||||
import io.jsonwebtoken.security.EcPrivateJwk
|
||||
import io.jsonwebtoken.security.EcPublicJwk
|
||||
import io.jsonwebtoken.security.InvalidKeyException
|
||||
import io.jsonwebtoken.security.SignatureAlgorithms
|
||||
import io.jsonwebtoken.security.UnsupportedKeyException
|
||||
import org.junit.Ignore
|
||||
@ -14,53 +13,31 @@ import java.security.KeyPair
|
||||
import java.security.interfaces.ECPrivateKey
|
||||
import java.security.interfaces.ECPublicKey
|
||||
|
||||
import static org.junit.Assert.assertEquals
|
||||
import static org.junit.Assert.assertNotNull
|
||||
import static org.junit.Assert.assertNull
|
||||
import static org.junit.Assert.assertTrue
|
||||
import static org.junit.Assert.fail
|
||||
import static org.junit.Assert.*
|
||||
|
||||
class DispatchingJwkFactoryTest {
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException)
|
||||
void testNullJwk() {
|
||||
try {
|
||||
new DispatchingJwkFactory().createJwk(null)
|
||||
fail()
|
||||
} catch (InvalidKeyException expected) {
|
||||
assertEquals 'JWK map cannot be null or empty.', expected.message
|
||||
}
|
||||
new DispatchingJwkFactory().createJwk(null)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException)
|
||||
void testEmptyJwk() {
|
||||
try {
|
||||
new DispatchingJwkFactory().createJwk(new DefaultJwkContext<Key>())
|
||||
fail()
|
||||
} catch (InvalidKeyException expected) {
|
||||
assertEquals 'JWK map cannot be null or empty.', expected.message
|
||||
}
|
||||
new DispatchingJwkFactory().createJwk(new DefaultJwkContext<Key>())
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = UnsupportedKeyException)
|
||||
void testUnknownKeyType() {
|
||||
|
||||
def ctx = new DefaultJwkContext();
|
||||
ctx.put('kty', 'foo')
|
||||
|
||||
DispatchingJwkFactory factory = new DispatchingJwkFactory()
|
||||
try {
|
||||
factory.createJwk(ctx)
|
||||
fail()
|
||||
} catch (UnsupportedKeyException e) {
|
||||
assertEquals 'Unrecognized JWK kty (key type) value: foo', e.getMessage()
|
||||
}
|
||||
new DispatchingJwkFactory().createJwk(ctx)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEcKeyPairToKey() {
|
||||
|
||||
def m = [
|
||||
Map<String,String> m = [
|
||||
'kty': 'EC',
|
||||
'crv': 'P-256',
|
||||
"x" : "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0",
|
||||
@ -83,7 +60,7 @@ class DispatchingJwkFactoryTest {
|
||||
assertEquals jwk.d, d
|
||||
|
||||
//remove the 'd' mapping to represent only a public key:
|
||||
m = m.remove(DefaultEcPrivateJwk.D)
|
||||
m.remove(DefaultEcPrivateJwk.D)
|
||||
ctx = new DefaultJwkContext()
|
||||
ctx.putAll(m)
|
||||
|
||||
|
@ -46,7 +46,7 @@ class GcmAesAeadAlgorithmTest {
|
||||
|
||||
def alg = EncryptionAlgorithms.A256GCM
|
||||
|
||||
def req = new DefaultSymmetricAeadRequest(null, null, P, KEY, AAD, IV)
|
||||
def req = new DefaultAeadRequest(null, null, P, KEY, AAD, IV)
|
||||
|
||||
def result = alg.encrypt(req)
|
||||
|
||||
|
@ -5,7 +5,6 @@ import io.jsonwebtoken.security.SignatureException
|
||||
import org.junit.Test
|
||||
|
||||
import javax.crypto.SecretKey
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
import static org.junit.Assert.assertEquals
|
||||
|
||||
@ -18,7 +17,8 @@ class HmacAesAeadAlgorithmTest {
|
||||
void testGenerateKey() {
|
||||
def alg = EncryptionAlgorithms.A128CBC_HS256
|
||||
SecretKey key = alg.generateKey();
|
||||
assertEquals alg.requiredKeyByteLength, key.getEncoded().length
|
||||
int algKeyByteLength = (alg.keyBitLength * 2) / Byte.SIZE
|
||||
assertEquals algKeyByteLength, key.getEncoded().length
|
||||
}
|
||||
|
||||
@Test(expected = SignatureException)
|
||||
@ -30,7 +30,7 @@ class HmacAesAeadAlgorithmTest {
|
||||
|
||||
def plaintext = "Hello World! Nice to meet you!".getBytes("UTF-8")
|
||||
|
||||
def req = new DefaultSymmetricAeadRequest(null, null, plaintext, key, null)
|
||||
def req = new DefaultAeadRequest(null, null, plaintext, key, null)
|
||||
def result = alg.encrypt(req);
|
||||
|
||||
def realTag = result.getDigest();
|
||||
@ -42,46 +42,4 @@ class HmacAesAeadAlgorithmTest {
|
||||
def dreq = new DefaultAeadResult(null, null, result.getPayload(), key, null, fakeTag, result.getInitializationVector())
|
||||
alg.decrypt(dreq)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException)
|
||||
void testGenerateKeyWithWeakSigAlgKey() {
|
||||
final byte[] bytes = new byte[24] // less than 32 bytes/256 bits
|
||||
Randoms.secureRandom().nextBytes(bytes)
|
||||
|
||||
def sigAlg = new MacSignatureAlgorithm('HS256', 'HmacSHA256', 256) {
|
||||
@Override
|
||||
SecretKey generateKey() {
|
||||
return new SecretKeySpec(bytes, 'HmacSHA256')
|
||||
}
|
||||
}
|
||||
def alg = new HmacAesAeadAlgorithm("A128CBC-HS256", sigAlg)
|
||||
alg.generateKey()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateKeyWithLongerThanExpectedSigAlgKey() {
|
||||
final byte[] macKeyBytes = new byte[64] // more than required 32 bytes / 256 bits
|
||||
Randoms.secureRandom().nextBytes(macKeyBytes)
|
||||
|
||||
def sigAlg = new MacSignatureAlgorithm('HS256', 'HmacSHA256', 256) {
|
||||
@Override
|
||||
SecretKey generateKey() {
|
||||
return new SecretKeySpec(macKeyBytes, 'HmacSHA256')
|
||||
}
|
||||
}
|
||||
def alg = new HmacAesAeadAlgorithm("A128CBC-HS256", sigAlg)
|
||||
def key = alg.generateKey()
|
||||
|
||||
def encryptionKeyBytes = key.getEncoded()
|
||||
|
||||
assertEquals 512, encryptionKeyBytes.length * Byte.SIZE
|
||||
|
||||
//per https://tools.ietf.org/html/rfc7518#section-5.2.2.1 ensure the first half of the generated encryption
|
||||
// key is the first 32 bytes of the larger-than-expected mac key
|
||||
byte[] macKeyFirst32Bytes = new byte[32]
|
||||
byte[] encKeyFirst32Bytes = new byte[32]
|
||||
System.arraycopy(macKeyBytes, 0, macKeyFirst32Bytes, 0, 32)
|
||||
System.arraycopy(encryptionKeyBytes, 0, encKeyFirst32Bytes, 0, 32)
|
||||
assert Arrays.equals(macKeyFirst32Bytes, encKeyFirst32Bytes)
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ import io.jsonwebtoken.security.Keys
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class Pbes2HsAkwAlgorithmTest {
|
||||
|
||||
@Ignore // for manual/developer testing only. Takes a long time and there is no deterministic output to assert
|
||||
@ -25,9 +23,9 @@ class Pbes2HsAkwAlgorithmTest {
|
||||
int skip = 6
|
||||
//double scale = 0.5035246727
|
||||
|
||||
def payload = 'hello world'.getBytes(StandardCharsets.UTF_8)
|
||||
def key = Keys.forPbe().setPassword('hellowor').setWorkFactor(iterations).build()
|
||||
def req = new DefaultKeyRequest(null, null, null, key, new DefaultJweHeader(), EncryptionAlgorithms.A128GCM)
|
||||
def password = 'hellowor'.toCharArray()
|
||||
def key = Keys.forPbe().setPassword(password).setIterations(iterations).build()
|
||||
def req = new DefaultKeyRequest(null, null, key, new DefaultJweHeader(), EncryptionAlgorithms.A128GCM)
|
||||
int sum = 0;
|
||||
for(int i = 0; i < tries; i++) {
|
||||
long start = System.currentTimeMillis()
|
||||
|
@ -102,7 +102,7 @@ class RFC7516AppendixA3Test {
|
||||
// https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.8 :
|
||||
|
||||
//ensure that the algorithm reflects the test harness values:
|
||||
SymmetricAeadAlgorithm enc = new HmacAesAeadAlgorithm(128) {
|
||||
AeadAlgorithm enc = new HmacAesAeadAlgorithm(128) {
|
||||
@Override
|
||||
protected byte[] ensureInitializationVector(SecurityRequest request) {
|
||||
return IV;
|
||||
|
@ -304,7 +304,7 @@ class RFC7517AppendixCTest {
|
||||
}
|
||||
}
|
||||
|
||||
PbeKey pbeKey = Keys.forPbe().setPassword(RFC_SHARED_PASSPHRASE).setWorkFactor(RFC_P2C).build()
|
||||
PbeKey pbeKey = Keys.forPbe().setPassword(RFC_SHARED_PASSPHRASE.toCharArray()).setIterations(RFC_P2C).build()
|
||||
|
||||
String compact = Jwts.jweBuilder()
|
||||
.setPayload(RFC_JWK_JSON)
|
||||
|
@ -70,7 +70,7 @@ class RFC7518AppendixB1Test {
|
||||
void test() {
|
||||
|
||||
def alg = EncryptionAlgorithms.A128CBC_HS256
|
||||
def request = new DefaultSymmetricAeadRequest(null, null, P, KEY, A, IV)
|
||||
def request = new DefaultAeadRequest(null, null, P, KEY, A, IV)
|
||||
def result = alg.encrypt(request);
|
||||
|
||||
byte[] ciphertext = result.getPayload()
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.jsonwebtoken.impl.security
|
||||
|
||||
import io.jsonwebtoken.security.AeadRequest
|
||||
import io.jsonwebtoken.security.AeadResult
|
||||
import io.jsonwebtoken.security.EncryptionAlgorithms
|
||||
import io.jsonwebtoken.security.SymmetricAeadRequest
|
||||
import org.junit.Test
|
||||
|
||||
import javax.crypto.SecretKey
|
||||
@ -70,7 +70,7 @@ class RFC7518AppendixB2Test {
|
||||
void test() {
|
||||
|
||||
def alg = EncryptionAlgorithms.A192CBC_HS384
|
||||
SymmetricAeadRequest req = new DefaultSymmetricAeadRequest(null, null, P, KEY, A, IV)
|
||||
AeadRequest req = new DefaultAeadRequest(null, null, P, KEY, A, IV)
|
||||
AeadResult result = alg.encrypt(req)
|
||||
|
||||
byte[] resultCiphertext = result.getPayload()
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.jsonwebtoken.impl.security
|
||||
|
||||
import io.jsonwebtoken.security.AeadRequest
|
||||
import io.jsonwebtoken.security.AeadResult
|
||||
import io.jsonwebtoken.security.EncryptionAlgorithms
|
||||
import io.jsonwebtoken.security.SymmetricAeadRequest
|
||||
import org.junit.Test
|
||||
|
||||
import javax.crypto.SecretKey
|
||||
@ -70,7 +70,7 @@ class RFC7518AppendixB3Test {
|
||||
void test() {
|
||||
|
||||
def alg = EncryptionAlgorithms.A256CBC_HS512
|
||||
SymmetricAeadRequest req = new DefaultSymmetricAeadRequest(null, null, P, KEY, A, IV)
|
||||
AeadRequest req = new DefaultAeadRequest(null, null, P, KEY, A, IV)
|
||||
AeadResult result = alg.encrypt(req)
|
||||
|
||||
byte[] resultCiphertext = result.getPayload()
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.jsonwebtoken.security
|
||||
|
||||
import io.jsonwebtoken.impl.security.DefaultAeadRequest
|
||||
import io.jsonwebtoken.impl.security.DefaultAeadResult
|
||||
import io.jsonwebtoken.impl.security.DefaultSymmetricAeadRequest
|
||||
import io.jsonwebtoken.impl.security.GcmAesAeadAlgorithm
|
||||
import org.junit.Test
|
||||
|
||||
@ -41,11 +41,11 @@ class EncryptionAlgorithmsTest {
|
||||
@Test
|
||||
void testWithoutAad() {
|
||||
|
||||
for (SymmetricAeadAlgorithm alg : EncryptionAlgorithms.values()) {
|
||||
for (AeadAlgorithm alg : EncryptionAlgorithms.values()) {
|
||||
|
||||
def key = alg.generateKey()
|
||||
|
||||
def request = new DefaultSymmetricAeadRequest(PLAINTEXT_BYTES, key, null)
|
||||
def request = new DefaultAeadRequest(PLAINTEXT_BYTES, key, null)
|
||||
|
||||
def result = alg.encrypt(request)
|
||||
|
||||
@ -71,11 +71,11 @@ class EncryptionAlgorithmsTest {
|
||||
@Test
|
||||
void testWithAad() {
|
||||
|
||||
for (SymmetricAeadAlgorithm alg : EncryptionAlgorithms.values()) {
|
||||
for (AeadAlgorithm alg : EncryptionAlgorithms.values()) {
|
||||
|
||||
def key = alg.generateKey()
|
||||
|
||||
def req = new DefaultSymmetricAeadRequest(null, null, PLAINTEXT_BYTES, key, AAD_BYTES)
|
||||
def req = new DefaultAeadRequest(null, null, PLAINTEXT_BYTES, key, AAD_BYTES)
|
||||
|
||||
def result = alg.encrypt(req)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user