You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现RSA/OAEP-SHA256加密后Java后端解密失败求助

RSA OAEP加密PHP与Java兼容问题解决

问题描述

使用phpseclib3编写的RSA OAEP加密代码,生成的密文在Java后端解密时抛出javax.crypto.BadPaddingException: Decryption error,但Java自身实现的加密代码可正常解密。已确认Base64URL编解码环节无问题。

代码示例

PHP加密代码(原问题代码)

function encryptSecretKeyWithCertificate($plainKey, $certFilePath) {
    $certContent = file_get_contents($certFilePath);
    if (!$certContent) {
        throw new Exception("can't load certificate: $certFilePath");
    }
    
    $rsa = PublicKeyLoader::load($certContent)
    ->withHash('sha256')
    ->withMGFHash('sha256')
    ->withPadding(RSA::ENCRYPTION_OAEP);
    return rtrim(strtr(base64_encode($rsa->encrypt($plainKey)), '+/', '-_'), '=');
}

Java解密代码

private static byte[] decryptSecretKey(PrivateKey privKey, byte[] encKey)  {
    try {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
        OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
                PSource.PSpecified.DEFAULT);
        cipher.init(Cipher.DECRYPT_MODE, privKey, oaepParams);
        return cipher.doFinal(encKey, 0, encKey.length);
    }catch (Exception ex){
        ex.printStackTrace();
        return  null;
    }
}

Java正常加密代码

public static String encryptSecretKeyAsymmetric(byte[] key, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
    final OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
            PSource.PSpecified.DEFAULT);
    cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
    byte[] cipherText = cipher.doFinal(key);
    String encodedCipher =  doEncode(cipherText);
    return encodedCipher;
}

异常信息

javax.crypto.BadPaddingException: Decryption error
at java.base/sun.security.rsa.RSAPadding.unpadOAEP(RSAPadding.java:488)
at java.base/sun.security.rsa.RSAPadding.unpad(RSAPadding.java:284)
at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:366)
at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:400)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2303)
at org.example.CryptoUtil.decryptSecretKey(CryptoUtil.java:264)
at org.example.CryptoUtil.symmetricDecryptResponse(CryptoUtil.java:224)
at org.example.Main.main(Main.java:40)

问题根源

phpseclib3中,withMGFHash()方法仅用于PSS签名的MGF哈希配置,对OAEP加密的MGF哈希不生效。原代码虽设置了withHash('sha256')和withMGFHash('sha256'),但OAEP加密的MGF哈希仍使用默认的SHA-1,与Java端配置的SHA-256不一致,导致解密时填充校验失败。

解决方案

修改PHP代码,通过withPadding()参数或withOAEPParameters()方法,显式指定OAEP加密的哈希算法和MGF哈希算法:

方案一:使用withPadding()传递参数

function encryptSecretKeyWithCertificate($plainKey, $certFilePath) {
    $certContent = file_get_contents($certFilePath);
    if (!$certContent) {
        throw new Exception("can't load certificate: $certFilePath");
    }
    
    // 依次指定OAEP哈希、MGF哈希、空标签(对应Java的PSource.PSpecified.DEFAULT)
    $rsa = PublicKeyLoader::load($certContent)
        ->withPadding(RSA::ENCRYPTION_OAEP, 'sha256', 'sha256', '');
    return rtrim(strtr(base64_encode($rsa->encrypt($plainKey)), '+/', '-_'), '=');
}

方案二:使用withOAEPParameters()方法

function encryptSecretKeyWithCertificate($plainKey, $certFilePath) {
    $certContent = file_get_contents($certFilePath);
    if (!$certContent) {
        throw new Exception("can't load certificate: $certFilePath");
    }
    
    $rsa = PublicKeyLoader::load($certContent)
        ->withOAEPParameters('', RSA::ENCRYPTION_OAEP, 'sha256', 'sha256');
    return rtrim(strtr(base64_encode($rsa->encrypt($plainKey)), '+/', '-_'), '=');
}

结论

PHP通过phpseclib3完全可以实现符合RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING规范的加密,关键是要正确配置OAEP加密的哈希和MGF哈希参数,避免混淆签名与加密的配置方法。

内容的提问来源于stack exchange,提问作者Morpheus.47

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 21:25:07