Error on JWE decryption - Wrong algorithm: AES or Rijndael required

Issue #250 resolved
Derek Meyer created an issue

Using the following code I get a BadJWEException when calling jwtProcessor.process()

Debugging, I ascertained that when decrypting the JWE it obtains the decryption key via the KeyConverter, which strips the algorithm type "AES" when it calls SecretJWK.toSecretKey(). Since the algorithm type is then "NONE" it fails decryption.

String hostId = "subject";

String sharedSecret = "SharedSecret";
byte[] salt = new byte[8];
new SecureRandom().nextBytes(salt);

SecretKey secretKey;
try {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    KeySpec spec = new PBEKeySpec(sharedSecret.toCharArray(), salt, 65536, 256);
    SecretKey tmp = factory.generateSecret(spec);
    secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
} catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
    throw new RuntimeException("couldn't generate key");
}

// create the JWT

JWSSigner signer;
try {
    signer = new MACSigner(secretKey.getEncoded());
} catch(KeyLengthException e) {
    throw new RuntimeException("signing key length issue", e);
}

JWTClaimsSet inputClaimsSet = new JWTClaimsSet.Builder()
        .subject(hostId)
        .expirationTime(new DateTime().plusSeconds(60).toDate())
        .build();

SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), inputClaimsSet);

try {
    signedJWT.sign(signer);
} catch(JOSEException e) {
    throw new RuntimeException("signing issue", e);
}

JWEObject jweObject = new JWEObject(
        new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
                .contentType("JWT")
                .build(),
        new Payload(signedJWT)
);

try {
    jweObject.encrypt(new DirectEncrypter(secretKey.getEncoded()));
} catch (KeyLengthException e) {
    throw new RuntimeException("encryption key length issue", e);
} catch (JOSEException e) {
    throw new RuntimeException("encrypting issue", e);
}

String jweString = jweObject.serialize();

// parse the JWT

JWT jwt;
try {
    jwt = JWTParser.parse(jweString);
} catch(ParseException e) {
    throw new RuntimeException("could not parse token");
}

if (!(jwt instanceof EncryptedJWT)) {
    throw new RuntimeException("encrypted JWT required");
}

ImmutableSecret secret = new ImmutableSecret(secretKey);
ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor();

JWEKeySelector jweKeySelector = new JWEDecryptionKeySelector(JWEAlgorithm.DIR, EncryptionMethod.A256GCM, secret);
jwtProcessor.setJWEKeySelector(jweKeySelector);

JWSKeySelector jwsKeySelector = new JWSVerificationKeySelector(JWSAlgorithm.HS256, secret);
jwtProcessor.setJWSKeySelector(jwsKeySelector);

JWTClaimsSet outputClaimsSet;
try {
    outputClaimsSet = jwtProcessor.process((EncryptedJWT) jwt, null);
} catch(BadJOSEException | JOSEException e) {
    throw new RuntimeException("could not parse");
}

Comments (5)

  1. Vladimir Dzhuvinov

    I'm looking at the snippet right now. There's no need to nest an HMAC JWT inside a JWE because encryption in JWE is always authenticated:

    https://connect2id.com/products/nimbus-jose-jwt/algorithm-selection-guide

    Encryption in JOSE is always authenticated, meaning that ciphertext’s integrity is protected from tampering. Authenticated encryption thus makes nesting an HMAC JWT inside a JSON Web Encryption (JWE) redundant; use just JWE encryption.

    So you could use a simple EncryptedJWT.

  2. Log in to comment