phpdecodingjwe

Decoding JWE with web-token/jwt-framework in PHP takes too much time


I need to solve how to decode a JWE encrypted with our public key in PHP. The case is that the userinfo of Oauth2 is encrypted and needs to be decrypted for the login to go through. With the current code the userifo is decrypted but it takes up to 13 minutes which is not acceptable for logging in.

This is done in Totara 15 (based on Moodle) and with a hook and a local plugin so as not to have too much core changes.

The code I have now is using "web-token/jwt-framework": "2.2.11" as T15 does not support PHP 8.1 which is required for the latest version.

As far as I can tell web-token/jwt-framework should be able to do this efficiently. However if anyone has other suggestions then I am ready to test other frameworks as well.

As I have not worked with web-token/jwt-framework any suggestions are helpful.

So here is what I have at the moment. It's a function that takes the encoded JWE, a keyid and the path to our private key and returns the decoded payload.

I have debugged the code and it's only the line:

$jwe = $jweLoader->loadAndDecryptWithKey($token, $jwk, $recipient);

That takes time, everything else takes fractions of seconds.

<?php

namespace local_oauth2_extension;

require_once(__DIR__ . '/../vendor/autoload.php');

use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A256KW;
use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEDecrypter;
use Jose\Component\Core\JWK;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\Encryption\Serializer\CompactSerializer;
use Jose\Component\Encryption\JWELoader;
use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Signature\JWSTokenSupport;

class jwe_helper
{
    public static function decode_response($token, $kid, $pem_path)
    {
        try{
            $jwk = JWKFactory::createFromKeyFile(
                $pem_path, // The filename
                null,
                [
                    'use' => 'enc',         // Additional parameters
                    'kid' => $kid
                ]
            );

            // The key encryption algorithm manager with the A256KW algorithm.
            $keyEncryptionAlgorithmManager = new AlgorithmManager([
                new RSAOAEP()
            ]);

            // The content encryption algorithm manager with the A256CBC-HS256 algorithm.
            $contentEncryptionAlgorithmManager = new AlgorithmManager([
                new A128CBCHS256()
            ]);

            // 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
            );

            // The serializer manager. We only use the JWE Compact Serialization Mode.
            $serializerManager = new JWESerializerManager([
                new CompactSerializer(),
            ]);

            $jweLoader = new JWELoader(
                $serializerManager,
                $jweDecrypter,
                null
            );
     
            $jwe = $jweLoader->loadAndDecryptWithKey($token, $jwk, $recipient);
            $payload = $jwe->getPayload();
            $payload = base64_decode($payload);
            $userinfo = self::extract_userinfo($payload);
        
            return $userinfo;
        } catch (\Exception $exception) {
            return $token;
        }
        return $token;
    }
    ........
}

Solution

  • As per the documentation

    For RSA-based encryption algorithms, it is highly recommended to install GMP or BCMath extension.

    It is also mentioned after composer install

    GMP or BCMath is highly recommended to improve the library performance

    You should make sure either GMP or BCMath is installed on your platform.