使用PHP JWT Framework v2.2加密Payload时触发RangeException错误
问题解决:JWT Framework v2.2加密时Base64解码错误
问题重现
使用JWT Framework v2.2构建JWE时,触发以下致命错误:
RangeException: Base64::decode() only expects characters in the correct base64 alphabet in ...\jwt-framework-2.2.x\vendor\paragonie\constant_time_encoding\src\Base64.php on line 229
经排查,错误发生在解码包含斜杠字符(如fbf/)的公钥4字符块时。
根本原因
JWK标准中,RSA类型的n(公钥模数值)要求使用**Base64URL编码(无填充)**格式,而你传入的$public_key_plain大概率是普通Base64编码(含/、+和=填充),甚至是完整的PEM格式公钥,不符合JWK的编码规范,导致解码时识别到非法字符。
解决方案
1. 正确提取并编码RSA公钥的核心参数
不能直接把PEM公钥或普通Base64公钥传入JWK的n字段,需要先解析PEM公钥,提取模(n)和指数(e),再转成Base64URL无填充格式:
// 假设你的公钥是PEM格式字符串 $pem_public_key = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----"; // 解析PEM公钥 $pkey = openssl_pkey_get_public($pem_public_key); $key_details = openssl_pkey_get_details($pkey); if (!$key_details || !isset($key_details['rsa'])) { throw new Exception("无效的RSA公钥"); } // 对n和e进行Base64URL无填充编码 use ParagonIE\ConstantTime\Base64UrlSafe; $jwk_n = Base64UrlSafe::encodeUnpadded($key_details['rsa']['n']); $jwk_e = Base64UrlSafe::encodeUnpadded($key_details['rsa']['e']);
2. 修正JWK实例创建
使用编码后的参数创建JWK,注意JWK必须包含e字段(公钥指数):
$jwk = new JWK([ 'kty' => 'RSA', 'n' => $jwk_n, 'e' => $jwk_e, 'kid' => $kid ]);
3. 修复代码中的其他疏漏
- 删除重复创建的
$keyEncryptionAlgorithmManager实例; - 补充初始化
$contentEncryptionAlgorithmManager(原代码未定义):
$contentEncryptionAlgorithmManager = new AlgorithmManager([ new A256GCM(), ]);
最终修正后的核心代码片段
$jws_payload = "sdvsd....."; $kid = "AH1111"; $aad = "你的AAD内容"; // 初始化算法管理器 $keyEncryptionAlgorithmManager = new AlgorithmManager([ new RSAOAEP256(), ]); $contentEncryptionAlgorithmManager = new AlgorithmManager([ new A256GCM(), ]); $compressionMethodManager = new CompressionMethodManager([]); $jweBuilder = new JWEBuilder( $keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager, $compressionMethodManager ); // 处理公钥并创建JWK $pem_public_key = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----"; $pkey = openssl_pkey_get_public($pem_public_key); $key_details = openssl_pkey_get_details($pkey); use ParagonIE\ConstantTime\Base64UrlSafe; $jwk_n = Base64UrlSafe::encodeUnpadded($key_details['rsa']['n']); $jwk_e = Base64UrlSafe::encodeUnpadded($key_details['rsa']['e']); $jwk = new JWK([ 'kty' => 'RSA', 'n' => $jwk_n, 'e' => $jwk_e, 'kid' => $kid ]); // 构建JWE $jwe = $jweBuilder ->create() ->withPayload($jws_payload) ->withSharedProtectedHeader([ 'alg' => 'RSA-OAEP-256', 'enc' => 'A256GCM', 'kid' => $kid ]) ->addRecipient($jwk) ->withAAD($aad) ->build();
内容的提问来源于stack exchange,提问作者Salman
相关产品推荐
相关产品推荐

