I have a jwe with RSA-OAEP-256 as key encryption algorithm and AES256GCM as content encryption algorithm, which is built with Spomky-Lab web-token/jwt-framework. I can decrypt it with a private key. But when AAD is added to jwe, I can not decrypt it.
I am using the following code for decryption:
// The key encryption algorithm manager with the A256KW algorithm. $keyEncryptionAlgorithmManager = new AlgorithmManager([
new RSAOAEP256()
]);
// The content encryption algorithm manager with the A256CBC-HS256 algorithm.
$contentEncryptionAlgorithmManager = new AlgorithmManager([
new A256GCM(),
]);
// The compression method manager with the DEF (Deflate) method.
$compressionMethodManager = new CompressionMethodManager([
new Deflate(),
]);
// We instantiate our JWE Decrypter.
$jweDecrypter = new JWEDecrypter(
$keyEncryptionAlgorithmManager,
$contentEncryptionAlgorithmManager,
$compressionMethodManager
);
// Our key.
$jwk = JWKFactory::createFromKeyFile(
'./key/private.pem', // The filename
null, // Secret if the key is encrypted, otherwise null
[
'use' => 'enc', // Additional parameters
]
);
// The serializer manager. We only use the JWE Compact Serialization Mode.
$serializerManager = new JWESerializerManager([
new CompactSerializer()
]);
// We try to load the token.
$jwe = $serializerManager->unserialize($token);
// We decrypt the token. This method does NOT check the header.
$success = $jweDecrypter->decryptUsingKey($jwe, $jwk, 0);
As i have dived in the codes, I found that openssl_decrypt() is returning null, in the following class:
Jose\Component\Encryption\Algorithm\ContentEncryption\AESGCM
You are using the wrong serialization. AAD are normally only allowed in combination with the JWE JSON serialization, see RFC 7516, JWE AAD:
JWE AAD
Additional value to be integrity protected by the authenticated encryption operation. This can only be present when using the JWE JSON Serialization.
Here, the AAD are added during encryption as follows:
...
use Jose\Component\Encryption\Serializer\JSONGeneralSerializer;
...
$jwe = $jweBuilder
->create()
->withPayload($payload)
->withSharedProtectedHeader([
'alg' => 'RSA-OAEP-256',
'enc' => 'A256GCM'
])
->addRecipient($jwk)
->withAAD('any additional authenticated data') // add AAD
->build();
$serializer = new JSONGeneralSerializer();
$token = $serializer->serialize($jwe, 0);
...
However, your posted code snippet uses the Compact serialization, which is probably the cause of the problem.
If I run your code for an encrypted token with AAD with the JSON serialization instead of the Compact serialization:
use Jose\Component\Encryption\Serializer\JSONGeneralSerializer;
...
$serializerManager = new JWESerializerManager([
new JSONGeneralSerializer()
]);
$jwe = $serializerManager->unserialize($token);
$success = $jweDecrypter->decryptUsingKey($jwe, $jwk, 0);
print("Payload: " . $jwe->getPayload() . "<br>");
print("AAD: " . $jwe->getAAD()); // get AAD
...
decryption works.
Note that there is a workaround for using the AAD in combination with the Compact serialization. This can be found in the RFC in the follow-up remark:
(Note that this can also be achieved when using either the JWE Compact Serialization or the JWE JSON Serialization by including the AAD value as an integrity-protected Header Parameter value, but at the cost of the value being double base64url encoded.)
Edit:
As stated in the comments, the OP mandatorily requires the AAD in conjunction with the Compact serialization.
According to the RFC, this is possible by a workaround, namely by embedding the AAD in the protected header (as mentioned in the note above). Keep in mind that elements of the protected header are integrity protected by the authenticated encryption operation, which corresponds exactly to the requirement for the AAD.
However, the workaround must be implemented accordingly during encryption:
...
use Jose\Component\Encryption\Serializer\CompactSerializer;
...
$jwe = $jweBuilder
->create()
->withPayload($payload)
->withSharedProtectedHeader([
'alg' => 'RSA-OAEP-256',
'enc' => 'A256GCM',
'aad' => 'additional authenticated data via workaround' // workaround: add AAD to protected header
])
->addRecipient($jwk)
->build();
$serializer = new CompactSerializer();
$token = $serializer->serialize($jwe, 0);
...
When decrypting, simply retrieve the AAD as follows:
...
$success = $jweDecrypter->decryptUsingKey($jwe, $jwk, 0);
print("Payload: " . $jwe->getPayload() . "<br>");
print("AAD - workaround: " . $jwe->getSharedProtectedHeader()['aad']); // get AAD
...