BadPaddingException RSA Encrypt 然后在 java 中解密

Posted

技术标签:

【中文标题】BadPaddingException RSA Encrypt 然后在 java 中解密【英文标题】:BadPaddingException RSA Encrypt then decrypt in java 【发布时间】:2018-01-17 13:07:56 【问题描述】:

我已获得一个 RSA 公钥和一个带有 OAEP SHA-256 填充的 RSA 私钥。我试图简单地加密一个随机字符串,然后对其进行解密以断言结果等于原始字符串。

这是我得到的公钥:

-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8tiBtDmkeS/ruY3rrkq
dz6Lc6XWFRbI/GjPtIokrtpM+Ujyv6wX8TBqY8e03gzh+eE7VUyEVPapDnceAqgJ
ZQah2h+N5AEQKqNDM4/1to1V0F+m1ISR7CIUU8dvU+bPk67DU5VkEtLxf+mW8/es
hy0u6oSB04WCDPNnh+9GDF7tN7lOzBH1FxKPWIb5Gqg6GoXS+KgvQhYEk0TajIBk
+mefzTv1D4HJlhFYybgY+/p3k4P2kM5HnbEtoVpz/PL9+94YVp5RBHTQHmk/3SAX
RkPP34IjY6LZqTJGWQGxc64Qci54ZJsq4wSTXvfdHgUWz7eX+v1jA+GLjFExNcYZ
nQIDAQAB
-----END RSA PUBLIC KEY-----

这是我得到的私钥:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAUQiHdHuMBCnF
P/7RQoRWrp62dGWQLDLP9l+3KUMlSPheN2R5jHDZ/WEGJGF2WYKxaQvv5XCocdnt
uxVZTNM1PVyduokJaJzrSIj+jGWDd4hTWvVoS3vhds8u6W0jD3M4ayrF6c7NYuHc
tE5YLLIgK1DTn+ZZCr3VGbScISDJ/WPx3+1YTNQDvm+T7MfjhetJqqzWIsunMUiw
nQOQvkdjCVWpk+L10SaMrezixtIS5wfpOTjGIZ0w5VunvtsPxg1TkuvGURa9S3rS
7D3uhDPY+V8UDMpBPso3j7TGD5axlBJcpavWeF8qde3sWztmqUFQ3JDypZWGSAe2
d8e4mY65AgMBAAECggEAal8nwYxbHZnb5L892U7aVfuly7Nbzb+0pzRVwsBu5DuV
LL+kslpMvTYZqUUMJ2LhF/HLaXhVtMWsTYLSDx+gHu1+wbtAOtUDHlxzcaAEMhA2
dix0WqiNr6qAdCkmdWMBTu5vrSJigVW1KdcNElY+e+6ZeUQTK6L2Vt0t+cGVGkM4
K5PdHcGLR1BiAf3k4BguHE4TGGnqN9dF5Rn9nPP6C7QihWzGn15efD2dAXn3Kbho
dMIRgyYiO7uXPm2LrIjtldYb8tPus+V9SWT4hcgnJZrtd9atkqZrJ3dhQf9ZetGs
UwTCzHJ169NNbVyrjCbcy4Uht8Na+t/94Im9hI8n0QKBgQDO6tYnwh1hPg3E+4DY
xCiDAp7v3afJIvC9a1sBtif8KkzZTYH31ww+PRcfDPQUlk/MIDie0u6xIawnBYkC
oN1u9erojcvQbBP0GFylP5hNxYZbI7gPA/7AiGRxyezZPOiVMwdd5fCM7Wv4kucr
c1JCcvtPoDQcFFZOfI+wqqdWnQKBgQDt745Pvckt7/XL7wbfv4BV+cwpLNjc4/3k
ajOLtasgpT8mc0gUH2ejHhpkuhjSUpSTrlFB8EN1kAwmBYy0GOoO9967hm6twmqk
Q5L3OHJ96pYkf1rbyXNE1N7inh5Z3M1H5ONIaliAYLHXOzKsZvI5eUdKAJdSqFLo
uvVCwr4PzQKBgG6W3rzDJ9a4Rr24OgYg2RIkTXQgALQko4xpm2tPwxEoPoiJv2QK
ILYHCpuC3dU+/Qk5U2m3jPFI8OyuLask9RSABPwkBQGxMfztJF8BnVI7tvJxJceI
uBiJDT4v0RHOVvSfIFnUMnvvzRw+z6TObvGq6JyHIDK9v98U/etLWkKVAoGAIIxF
lmjqzUrm/8ep1A+5OYmbQQKug8D4aTeR54mpaCTSt6rLcF0/axPiHmdKn/LF+lG9
MdzxDXLwBn952OUTl4qWwGZKW6Cdv+yyfPkOyGS/tyxovGoZR5ArESr6Eebfefc4
lB5gDuerTDr/2o+WkQAjHV9pU9hMxyNUC5biMv0CgYEAiDlw8lBf3cQs6FxNXs9t
whWpfL0yY7WAONvhfFB0Dpsz52gGDCYRvJekGRz6jOlKDuXJ+Mm1AX4BaufMETI5
QseZxtVPIn+BXm0A1x8w/DifmE1JqQZmPCQPOh3eLx5nSn9LKGIbMgd17mfH3HhU
8WX2mzWjmRA3C/CzdGfCKSk=
-----END PRIVATE KEY-----

我正在从 pem 文件“crypt_pkcs8.pem”中读取此密钥,但从 gRPC 调用中将公钥作为字节数组接收。

这是我的 Java 代码:

public class Encryption
public static void main(String args)
    ByteString publicKey = client.getPublicKey(nonce).getRSAEncryptionKey();

    String strKeyPEM = "";
    BufferedReader br = new BufferedReader(new FileReader("crypt_pkcs8.pem"));
    String line;
    while ((line = br.readLine()) != null) 
        strKeyPEM += line+"\n";
    
    br.close();
    byte[] pt;
    try 
        pt = "h".getBytes("UTF-8");
        byte[] ct =encrypt(publicKey, pt);
        byte[] response= decrypt(strKeyPEM, ct);

        assertEquals(pt, response);
     catch (UnsupportedEncodingException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    

public static byte[] encrypt(ByteString rawKey ,byte[] message)
    String strippedKey=stripKey(rawKey.toStringUtf8());

    byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
    System.out.println(keyBytes.length);

    Cipher cipher_RSA;
    try 
        cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        PublicKey pk = keyFactory.generatePublic(spec);
        System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());

        cipher_RSA.init(Cipher.ENCRYPT_MODE, pk); 
        return cipher_RSA.doFinal(message);
     catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
            BadPaddingException | InvalidKeyException | InvalidKeySpecException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    



public static byte[] decrypt(String rawKey ,byte[] message)
    String strippedKey=stripPrivateKey(rawKey);

    byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
    System.out.println(keyBytes.length);

    Cipher cipher_RSA;
    try 
        cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey pk = keyFactory.generatePrivate(spec);
        System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());

        cipher_RSA.init(Cipher.DECRYPT_MODE, pk); 
        return cipher_RSA.doFinal(message);
     catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
            BadPaddingException | InvalidKeyException | InvalidKeySpecException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    

public static String stripKey(String key)
    key = key.replace("-----BEGIN RSA PUBLIC KEY-----\n", "");
    key = key.replace("-----END RSA PUBLIC KEY-----", "");
    key = key.replace("\n", "");
    return key;


public static String stripPrivateKey(String key)
    key = key.replace("-----BEGIN PRIVATE KEY-----", "");
    key = key.replace("-----END PRIVATE KEY-----", "");
    key = key.replace("\n", "");
    return key;




我没有发现我的实际代码有任何明显错误,所以我相信这与键不匹配有关。

我还注意到公钥和私钥的页眉/页脚不同。从网上看,这是因为公钥是 PKCS#8 格式。

我还需要将公钥更改为 pkcs#8 格式吗?如果是这样,最简单的方法是什么?

我还被告知我应该能够从上面给出的私钥中提取公钥(pkcs8 格式)。这很容易做到吗?

【问题讨论】:

您的公钥不是 pkcs8 格式。你有 pkcs1 格式的。使用 openssl 将其转换为 pkcs8。 【参考方案1】:

如果您可以获得有效的公钥,则该密钥不是 PKCS#8 格式,而是 Java 期望的 X.509 (SubjectPublicKeyInfo) 格式。 但是,您的公钥和私钥确实匹配。您可以使用答案here 从私钥文件中创建正确的公钥文件。


Java 不直接包含在没有 CRT 参数的情况下从 RSAPrivateKey 检索公共指数的代码。但是,如果您想要一个仅限 Java 的解决方案,您可以将 PrivateKey 更进一步地转换为 RSAPrivateCrtKey,其中确实包含一个 getPublicExponent 方法来检索公共指数。然后您可以使用 RSA KeyFactory 生成使用 RSAPublicKeySpec 的公钥。


您还可以使用例如解析 PEM 文件以检索 Java 中的公钥。充气城堡 API。但是,如果你这样做,预计会有一个陡峭的学习曲线。

【讨论】:

别忘了给詹姆斯的this answer点赞!

以上是关于BadPaddingException RSA Encrypt 然后在 java 中解密的主要内容,如果未能解决你的问题,请参考以下文章

java rsa 解密报:javax.crypto.BadPaddingException: Decryption error

BadPaddingException RSA Encrypt 然后在 java 中解密

关于javax.crypto.BadPaddingException: Blocktype错误的几种解决方法

BadPaddingException : 数据必须从零开始

java加密算法--RSA

RSA---应用最广泛的非对称加密算法