Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/src/main/java/io/jsonwebtoken/Jwts.java
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,7 @@ public static JwtBuilder builder() {
/**
* Returns a new {@link JwtParserBuilder} instance that can be configured to create an immutable/thread-safe {@link JwtParser}.
*
* @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser}.
* @return a new {@link JwtParserBuilder} instance that can be configured create an immutable/thread-safe {@link JwtParser}.
*/
public static JwtParserBuilder parser() {
return JWT_PARSER_BUILDER_SUPPLIER.get();
Expand Down
6 changes: 6 additions & 0 deletions api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ public interface AeadAlgorithm extends Identifiable, KeyLengthSupplier, KeyBuild
*/
void encrypt(AeadRequest req, AeadResult res) throws SecurityException;

default AeadResult encrypt(AeadRequest req, OutputStream out) throws SecurityException {
AeadResult result = AeadResult.with(out);
encrypt(req, result);
return result;
}

/**
* Decrypts ciphertext and authenticates any {@link DecryptAeadRequest#getAssociatedData() associated data},
* writing the decrypted plaintext to the provided {@code out}put stream.
Expand Down
43 changes: 43 additions & 0 deletions api/src/main/java/io/jsonwebtoken/security/AeadRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import javax.crypto.SecretKey;
import java.io.InputStream;
import java.io.OutputStream;

/**
* A request to an {@link AeadAlgorithm} to perform authenticated encryption with a supplied symmetric
Expand All @@ -27,4 +28,46 @@
* @since 0.12.0
*/
public interface AeadRequest extends SecureRequest<InputStream, SecretKey>, AssociatedDataSupplier {

/**
* Named parameters (setters) used to configure an {@link AeadRequest AeadRequest} instance.
*
* @param <M> the instance type returned for method chaining.
* @since JJWT_RELEASE_VERSION
*/
interface Params<M extends Params<M>> extends SecureRequest.Params<InputStream, SecretKey, M> {

/**
* Sets any &quot;associated data&quot; that must be integrity protected (but not encrypted) when performing
* <a href="https://en.wikipedia.org/wiki/Authenticated_encryption">AEAD encryption or decryption</a>.
*
* @param aad the {@code InputStream} containing any associated data that must be integrity protected or
* verified during AEAD encryption or decryption.
* @return the instance for method chaining.
* @see AeadAlgorithm#encrypt(AeadRequest, AeadResult)
* @see AeadAlgorithm#decrypt(DecryptAeadRequest, OutputStream)
*/
M associatedData(InputStream aad);
}

/**
* A builder for creating new immutable {@link AeadRequest} instances used for AEAD encryption via
* {@link AeadAlgorithm#encrypt(AeadRequest, AeadResult)}.
*
* @since JJWT_RELEASE_VERSION
*/
interface Builder extends Params<Builder>, io.jsonwebtoken.lang.Builder<AeadRequest> {
}

/**
* Returns a new {@link AeadRequest.Builder} for creating immutable {@link AeadRequest}s used for AEAD encryption
* via {@link AeadAlgorithm#encrypt(AeadRequest, AeadResult)}.
*
* @return a new {@link AeadRequest.Builder} for creating immutable {@link AeadRequest}s used for AEAD encryption
* via {@link AeadAlgorithm#encrypt(AeadRequest, AeadResult)}.
* @since JJWT_RELEASE_VERSION
*/
static AeadRequest.Builder builder() {
return Suppliers.AEAD_REQUEST_BUILDER.get();
}
}
16 changes: 15 additions & 1 deletion api/src/main/java/io/jsonwebtoken/security/AeadResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*
* @since 0.12.0
*/
public interface AeadResult {
public interface AeadResult extends DigestSupplier, IvSupplier {

/**
* Returns the {@code OutputStream} the AeadAlgorithm will use to write the resulting ciphertext during
Expand All @@ -50,4 +50,18 @@ public interface AeadResult {
* @return the AeadResult for method chaining.
*/
AeadResult setIv(byte[] iv);

/**
* Returns a new {@link AeadResult} with the specified {@link OutputStream} that will be used to write the
* resulting ciphertext during encryption or plaintext during decryption.
*
* @param out the {@link OutputStream} that will be used to write the resulting ciphertext during encryption
* @return a new {@link AeadResult} with the specified {@link OutputStream} that will be used to write the
* resulting ciphertext during encryption.
* @since JJWT_RELEASE_VERSION
*/
static AeadResult with(OutputStream out) {
return Suppliers.AEAD_RESULT_FACTORY.apply(out);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,61 @@
package io.jsonwebtoken.security;

import javax.crypto.SecretKey;
import java.io.OutputStream;

/**
* A request to an {@link AeadAlgorithm} to decrypt ciphertext and perform integrity-protection with a supplied
* A request to an {@link AeadAlgorithm} to decrypt ciphertext with integrity verification with a supplied
* decryption {@link SecretKey}. Extends both {@link IvSupplier} and {@link DigestSupplier} to
* ensure the respective required IV and AAD tag returned from an {@link AeadResult} are available for decryption.
*
* @since 0.12.0
*/
public interface DecryptAeadRequest extends AeadRequest, IvSupplier, DigestSupplier {

/**
* Named parameters (setters) used to configure an {@link AeadRequest AeadRequest} instance.
*
* @param <M> the instance type returned for method chaining.
* @since JJWT_RELEASE_VERSION
*/
interface Params<M extends Params<M>> extends AeadRequest.Params<M> {

/**
* Sets the required initialization vector used during AEAD decryption.
*
* @param iv the required initialization vector used during AEAD decryption.
* @return the instance for method chaining.
*/
M iv(byte[] iv);

/**
* Sets the required AEAD Authentication Tag used to verify message authenticity during AEAD decryption.
*
* @param digest the required AEAD Authentication Tag used to verify message authenticity during AEAD decryption.
* @return the instance for method chaining.
*/
M digest(byte[] digest);
}

/**
* A builder for creating new immutable {@link DecryptAeadRequest}s used for AEAD decryption via
* {@link AeadAlgorithm#decrypt(DecryptAeadRequest, OutputStream)}.
*
* @since JJWT_RELEASE_VERSION
*/
interface Builder extends io.jsonwebtoken.lang.Builder<DecryptAeadRequest>, Params<Builder> {
}

/**
* Returns a new {@link DecryptAeadRequest.Builder} for creating immutable {@link DecryptAeadRequest}s used for
* AEAD decryption via {@link AeadAlgorithm#decrypt(DecryptAeadRequest, OutputStream)}.
*
* @return a new {@link DecryptAeadRequest.Builder} for creating immutable {@link DecryptAeadRequest}s used for
* AEAD decryption via {@link AeadAlgorithm#decrypt(DecryptAeadRequest, OutputStream)}.
* @since JJWT_RELEASE_VERSION
*/
static DecryptAeadRequest.Builder builder() {
return Suppliers.DECRYPT_AEAD_REQUEST_BUILDER.get();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,46 @@
* {@code JWE Encrypted Key} (such as an initialization vector, authentication tag, ephemeral key, etc) is expected
* to be available in the JWE protected header, accessible via {@link #getHeader()}.</p>
*
* @param <K> the type of {@link Key} used during the request to obtain the resulting decryption key.
* @param <K> the type of key used by the {@link KeyAlgorithm} to obtain the JWE Content Encryption Key (CEK).
* @see KeyAlgorithm#getDecryptionKey(DecryptionKeyRequest)
* @since 0.12.0
*/
public interface DecryptionKeyRequest<K extends Key> extends SecureRequest<byte[], K>, KeyRequest<byte[]> {

/**
* Named parameters (setters) used to configure a {@link DecryptionKeyRequest DecryptionKeyRequest}
* instance.
*
* @param <K> the type of key used by the {@link KeyAlgorithm} to obtain the JWE Content Encryption Key (CEK).
* @param <M> the instance type returned for method chaining.
* @since JJWT_RELEASE_VERSION
*/
interface Params<K extends Key, M extends Params<K, M>> extends KeyRequest.Params<byte[], M>,
SecureRequest.Params<byte[], K, M> {
}

/**
* A builder for creating new immutable {@link DecryptionKeyRequest} instances used to get a JWE
* decryption key via {@link KeyAlgorithm#getDecryptionKey(DecryptionKeyRequest)}.
*
* @param <K> the type of key used by the {@link KeyAlgorithm} to obtain the JWE Content Encryption Key (CEK).
* @since JJWT_RELEASE_VERSION
*/
interface Builder<K extends Key> extends Params<K, Builder<K>>, io.jsonwebtoken.lang.Builder<DecryptionKeyRequest<K>> {
}

/**
* Returns a new {@link DecryptionKeyRequest.Builder} for creating immutable {@link DecryptionKeyRequest}s used to
* get a JWE decryption key via {@link KeyAlgorithm#getDecryptionKey(DecryptionKeyRequest)}.
*
* @param <K> the type of key used to obtain the JWE decryption key via
* {@link KeyAlgorithm#getDecryptionKey(DecryptionKeyRequest)}.
* @return a new {@link DecryptionKeyRequest.Builder} for creating immutable {@link DecryptionKeyRequest}s used to
* get a JWE decryption key via {@link KeyAlgorithm#getDecryptionKey(DecryptionKeyRequest)}.
* @since JJWT_RELEASE_VERSION
*/
@SuppressWarnings("unchecked")
static <K extends Key> DecryptionKeyRequest.Builder<K> builder() {
return (DecryptionKeyRequest.Builder<K>) Suppliers.DECRYPTION_KEY_REQUEST_BUILDER.get();
}
}
80 changes: 80 additions & 0 deletions api/src/main/java/io/jsonwebtoken/security/HashAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
package io.jsonwebtoken.security;

import io.jsonwebtoken.Identifiable;
import io.jsonwebtoken.lang.Assert;

import java.io.InputStream;
import java.util.function.Consumer;

/**
* A {@link DigestAlgorithm} that computes and verifies digests without the use of a cryptographic key, such as for
Expand All @@ -42,4 +44,82 @@
* @since 0.12.0
*/
public interface HashAlgorithm extends DigestAlgorithm<Request<InputStream>, VerifyDigestRequest> {

/**
* Computes a digest of a request {@link Request#getPayload() payload} {@code InputStream} using configured
* parameters. This is a lambda-style method to execute the request in-line instead of requiring the caller to
* first use a {@link Request.Builder} to construct the request.
*
* <p>Callers are expected to {@link InputStream#close() close} or {@link InputStream#reset() reset} the request
* payload stream if necessary after calling this method.</p>
*
* @param c consumer supporting lambda-style specification of digest {@link Request.Params}.
* @return the computed digest of the request {@link Request#getPayload() payload}.
* @since JJWT_RELEASE_VERSION
*/
default byte[] digest(Consumer<Request.Params<InputStream, ?>> c) {
Assert.notNull(c, "Consumer cannot be null");
Request.Builder<InputStream> b = Request.builder();
c.accept(b);
Request<InputStream> r = b.build();
return digest(r);
}

/**
* Computes a digest of the specified {@code is} input stream.
*
* <p>Callers are expected to {@link InputStream#close() close} or {@link InputStream#reset() reset} the payload
* stream if necessary after calling this method.</p>
*
* @param is the {@code InputStream} that will be consumed to compute the digest. Callers are expected to
* {@link InputStream#close() close} or {@link InputStream#reset() reset} the payload stream if necessary
* after calling this method.
* @return the computed digest of the specified {@code is} input stream.
* @since JJWT_RELEASE_VERSION
*/
default byte[] digest(InputStream is) {
return digest(c -> c.payload(is));
}

/**
* Returns {@code true} if the request's specified {@link VerifyDigestRequest#getDigest() digest} matches (equals)
* the algorithm's computed digest of the request {@link VerifyDigestRequest#getPayload() payload}, {@code false}
* otherwise. This is a lambda-style method to execute the request in-line instead of requiring the caller to first
* use a {@link VerifyDigestRequest.Builder} to construct the request.
*
* <p>Callers are expected to {@link InputStream#close() close} or {@link InputStream#reset() reset} the request
* payload stream if necessary after calling this method.</p>
*
* @param c consumer supporting lambda-style specification of {@link VerifyDigestRequest.Params}.
* @return {@code true} if the request's specified {@link VerifyDigestRequest#getDigest() digest} matches (equals)
* the algorithm's computed digest of the request {@link VerifyDigestRequest#getPayload() payload}, {@code false}
* otherwise.
* @since JJWT_RELEASE_VERSION
*/
default boolean verify(Consumer<VerifyDigestRequest.Params<?>> c) {
Assert.notNull(c, "Consumer cannot be null");
VerifyDigestRequest.Builder b = VerifyDigestRequest.builder();
c.accept(b);
VerifyDigestRequest r = b.build();
return verify(r);
}

/**
* Returns {@code true} if the specified {@code digest} matches (equals) the algorithm's computed digest of the
* specified {@code is} input stream, {@code false} otherwise.
*
* <p>Callers are expected to {@link InputStream#close() close} or {@link InputStream#reset() reset} the payload
* stream if necessary after calling this method.</p>
*
* @param is the {@code InputStream} that will be consumed to compute the digest. Callers are expected to
* {@link InputStream#close() close} or {@link InputStream#reset() reset} the payload stream if
* necessary after calling this method.
* @param digest the previously-computed digest to compare with the algorithm's computed digest of {@code is}.
* @return {@code true} if the specified {@code digest} matches (equals) the algorithm's computed digest of the
* specified {@code is} input stream, {@code false} otherwise.
* @since JJWT_RELEASE_VERSION
*/
default boolean verify(InputStream is, byte[] digest) {
return verify(c -> c.payload(is).digest(digest));
}
}
25 changes: 25 additions & 0 deletions api/src/main/java/io/jsonwebtoken/security/KeyAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
package io.jsonwebtoken.security;

import io.jsonwebtoken.Identifiable;
import io.jsonwebtoken.JweHeader;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.lang.Assert;

import javax.crypto.SecretKey;
import java.security.Key;
import java.util.function.Consumer;

/**
* A {@code KeyAlgorithm} produces the {@link SecretKey} used to encrypt or decrypt a JWE. The {@code KeyAlgorithm}
Expand Down Expand Up @@ -65,6 +68,17 @@ public interface KeyAlgorithm<E extends Key, D extends Key> extends Identifiable
*/
KeyResult getEncryptionKey(KeyRequest<E> request) throws SecurityException;

default KeyResult getEncryptionKey(Consumer<KeyRequest.Params<E, ?>> p) throws SecurityException {
Assert.notNull(p, "Consumer cannot be null");
KeyRequest.Builder<E> builder = KeyRequest.builder();
p.accept(builder);
return getEncryptionKey(builder.build());
}

default KeyResult getEncryptionKey(E key, JweHeader header, AeadAlgorithm enc) throws SecurityException {
return getEncryptionKey(p -> p.payload(key).header(header).encryptionAlgorithm(enc));
}

/**
* Return the {@link SecretKey} that should be used to decrypt a JWE via the request's specified
* {@link DecryptionKeyRequest#getEncryptionAlgorithm() AeadAlgorithm}.
Expand All @@ -81,4 +95,15 @@ public interface KeyAlgorithm<E extends Key, D extends Key> extends Identifiable
* @throws SecurityException if there is a problem obtaining or decrypting the AEAD {@code SecretKey}.
*/
SecretKey getDecryptionKey(DecryptionKeyRequest<D> request) throws SecurityException;

default SecretKey getDecryptionKey(Consumer<DecryptionKeyRequest.Params<D, ?>> p) throws SecurityException {
Assert.notNull(p, "Consumer cannot be null");
DecryptionKeyRequest.Builder<D> builder = DecryptionKeyRequest.builder();
p.accept(builder);
return getDecryptionKey(builder.build());
}

default SecretKey getDecryptionKey(byte[] cekCiphertext, D decryptionKey, JweHeader header, AeadAlgorithm enc) throws SecurityException {
return getDecryptionKey(p -> p.payload(cekCiphertext).key(decryptionKey).header(header).encryptionAlgorithm(enc));
}
}
Loading