简体   繁体   English

RSA 在 Qt/C++ 中使用 OpenSSL 加密并在 Java 中解密:错误填充异常

[英]RSA encrypt with OpenSSL in Qt/C++ and decrypt in Java: Bad Padding Exception

I am trying out a sample program where I am encrypting a string with RSA public key in C++ Qt Framework (using statically linked OpenSSL C++ library), and decrypting the same ciphertext using javax.crypto library. I am trying out a sample program where I am encrypting a string with RSA public key in C++ Qt Framework (using statically linked OpenSSL C++ library), and decrypting the same ciphertext using javax.crypto library. I am sending this ciphertext through a socket connection using a free port on my PC to the localhost.我正在使用我 PC 上的空闲端口通过套接字连接将这个密文发送到本地主机。

The following are the codes:以下是代码:

My Qt/C++ code:我的 Qt/C++ 代码:

main.cpp:主.cpp:

#include "cipher.h"
#include "assert.h"
#include "string.h"
#include <QApplication>
#include <QTcpSocket>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Cipher *cipher=new Cipher();

    QTcpSocket *qts=new QTcpSocket();
    qts->connectToHost("localhost",11111);

    QByteArray message, enc_key,enc_message;

    message="Elephant";
   
    enc_message=cipher->encryptRSA(cipher->getPublicKey("publickey.pem"),message);

    qDebug()<<message;
    qDebug()<<enc_message;

    if(qts->waitForConnected(300)){
        qts->write(QString::fromStdString(enc_message.toStdString()).toUtf8().constData());
        qts->write("\n");
        qts->flush();
    }

    return a.exec();
}

For the encryptRSA function I used the example from VoidRealms' tutorial.对于 encryptRSA function,我使用了 VoidRealms 教程中的示例。 Here is the GitHub link: https://github.com/voidrealms/Qt-154这是 GitHub 链接: https://github.com/voidrealms/Qt-154

From the above link I used cipher.h and cipher.cpp without any changes.从上面的链接中,我使用cipher.hcipher.cpp没有任何更改。

Java code: Java代码:

package servertest;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.io.FileUtils;

public class ServerTest {
    static int port=11111;
    static ServerSocket ss;
    static Socket s;
    
    public static void main(String[] args) {
        System.out.println("Server Started!");
        try {
            ss = new ServerSocket(port);
            s=ss.accept();
            
            InputStreamReader isr = new InputStreamReader(new BufferedInputStream(s.getInputStream()));
            BufferedReader br = new BufferedReader(isr);
            
            String str=br.readLine();
            
            System.out.println("Received: "+str);
            byte[] encrypted = str.getBytes("UTF-8");
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            PrivateKey privateKey = loadPrivateKey();
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decrypted = cipher.doFinal(encrypted); 
            
            System.out.println("Decrypted: "+new String(decrypted));
            
        } catch (IOException ex) {
            Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public static PrivateKey loadPrivateKey() throws Exception {
        String privateKeyPEM = FileUtils.readFileToString(new File("privatekey-pkcs8.pem"), StandardCharsets.UTF_8);

        // strip off header, footer, newlines, whitespaces
        privateKeyPEM = privateKeyPEM
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replace("-----BEGIN RSA PRIVATE KEY-----", "")
                .replace("-----END RSA PRIVATE KEY-----", "")
                .replaceAll("\\s", "");
        
        //System.out.println(privateKeyPEM);
        
        // decode to get the binary DER representation
        byte[] privateKeyDER = Base64.getDecoder().decode(privateKeyPEM.getBytes("UTF-8"));

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyDER));
        return privateKey;
    }
    
}

Also, I generated these keys using standard OpenSSL commands.此外,我使用标准 OpenSSL 命令生成了这些密钥。 I tried using different keys with different bit lengths but I get the same error.我尝试使用具有不同位长度的不同密钥,但我得到了同样的错误。 I have converted the privatekey.pem to PKCS8 ( privatekey-pkcs8.pem ).我已将privatekey.pem转换为 PKCS8 ( privatekey-pkcs8.pem )。 For generating and using the keys, I followed the link below:为了生成和使用密钥,我点击了下面的链接:

https://adangel.org/2016/08/29/openssl-rsa-java/ https://adangel.org/2016/08/29/openssl-rsa-java/

THE PROBLEM:问题:

I am getting javax.crypto.BadPaddingException: Decryption error in Java.我收到javax.crypto.BadPaddingException: Decryption error What am I doing wrong?我究竟做错了什么?

THINGS I ALREADY TRIED我已经尝试过的事情

  • I am new to encryption and I don't know if I should encode this ciphertext to something like base64 or hex, when I tried this, Java complains that the ciphertext is longer than maximum bits allowed.我是加密新手,我不知道是否应该将此密文编码为 base64 或十六进制,当我尝试此操作时,Java 抱怨密文长于允许的最大位数。
  • At the qts->write() stage, I tried converting between several datatypes and formats including const char*, char[], QByteArray, toUtf8().toconstData(), std::string, converting to QString using both QString::fromUtf8() and QString::fromLocal8bit().在 qts->write() 阶段,我尝试在几种数据类型和格式之间进行转换,包括 const char*、char[]、QByteArray、toUtf8().toconstData()、std::string,同时使用 QString:: 转换为 QString fromUtf8() 和 QString::fromLocal8bit()。 Should I try Utf16 and Latin1?我应该尝试 Utf16 和 Latin1 吗?

Please help me with this one.请帮我解决这个问题。

Okay, I SOLVED this problem, within 20 minutes after posting, by converting the ciphertext to Base64 and passing it through the socket and, of course, on the receiving side, I need to decode it back to bytes.好的,我在发布后的 20 分钟内解决了这个问题,方法是将密文转换为 Base64 并通过套接字传递,当然,在接收端,我需要将其解码回字节。

Previously when I tried this, I forgot to decode the Base64 text back to bytes.以前当我尝试这个时,我忘记将 Base64 文本解码回字节。 Sorry if I wasted somebody's time.对不起,如果我浪费了别人的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM