使用 C++ 进行 RSA 加密(结果不正确)

RSA encryption using c++ (incorrect result)

我有 PHP 代码,可以进行 RSA 加密。这个 PHP 代码给我正确的输出。 我需要相同的结果,但使用 C++。我尝试制作 C++ 代码,但得到的 RSA 加密结果不正确。与使用 php 代码不同。 我需要更改 C++ 代码才能获得与 php 相同的结果?谢谢。

PHP代码:

<?php
    include('Crypt/RSA.php');

    $publickey_mod = "981b4b1e5d0a4db79229c454d091ec76afb1e0b945ea68ee3402ab82450b7fc0b6030641dc8fb098f864f847cdb0fabf7d2f1514ddea140a4d51195cdbbc0ff05eb5bb3a708aed95c6481a6b120c308a577494eec0135cb3dd478c5b9279b95edf8fcd875dfb309a35d2454ba47ce7032961f41ea51dfc3b2a2ee776d2a60edbe33f02a82a4d40c323f4eca0802321d3e163b20ed7e44714c9f476ce51c0010f410cdfa7bb93524550e9e2390b5e470e8450f11a8840ca6eb0a9d343892fb87ae52c17af1720017e82055c3e1ea7e184923b9efce36e910a72886971db9f19eda6d3533de6e3949d92434730691209fc5e0a8f3ac525c7aca900782e6b2244b7";
    $publickey_exp = "010001";
    $password = "password";
        
    $rsa = new Crypt_RSA();
    $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
    $rsa->loadKey(array(
        'n' => new Math_BigInteger($publickey_mod, 16),
        'e' => new Math_BigInteger($publickey_exp, 16)
    ));
        
    echo "result=\"" . base64_encode($rsa->encrypt($password)) . "\"";
?>

PHP 输出:

#1
result="N29/RawYj7rbAc4347axmxlD5vAN2kUWDUURX7ADU1pr9+b9SC7i+TzqXyhI0MumVuQOD6uc/t1uwCbuNjz/X6W5scEBapemO4OZzjBJLrEf1gTA9wJKub5VE3dUhbrTWh30NsrL/ZZgVs9vp9kqCFXpJESU8OGfnfiiMBN0WSEZjSfieDe6hkn+00Hwjl1ZmouKMxpgBjmZlXIK7PkmLs6HBsScgnscCPUUX/vfPy/krpBVjaR3xgky0sbKvpZi6pwh0AjfAVbJk8nYS/5SuXEcORpRRm2PBQAk9/4cDiEsEqODBICzIerBln/3FnsI6OTOLHYkhZ5vQLyp6pTjvw=="

#2
result="U1Wy9TQP5K4DznmvuiLl90aPKIfxrzjAkQKGrp740NEh3mgWWtHPICJFa8ORm0LpJ5ZBoZi04CvHaYS+HAC5HTJn+S6xkp+8lX8xiurxDjAKWNQc5d/la9jNinB45DUQZOEiGg5u+Qpzgt48qNH3Y5PrwIMlDSil1u3YpuL+LMHwGCMD5dg5wsRX23HXJucGWOkRepST3+BLQns0Jp6ivoBOKH6wvFS41hYH3zK9d4vmuu7oKUl2c6G5G1A0f7SzFw2PsbQns/814dLr02vi/WAnD/N0sY221NlS5t9IApO2wCf0k/MmL69GixqPY8/bThJ2nmgYQktkAOCXouSQvA=="

#3
result="SF7o6F7/vVikGSzPl06yMwOc/si7EtMhbLm19/RSmuaFP+GcC6DHYGhk/BUOiwKb+ZzzxoMNFjum8J52z/ScvYEiEM7ieTDrqBnk1p/dTzWfGJ+Rs3+FsEYzrQ/l0Rh4s9TPC3s8V0dhO+eoRlT/8vyZMXe7win8XWbwBxQ6tDcemzjLAiT/c44re6qBidzDGd7kP/Vxd/ocy712/1fFP2Rm5O4YHb/5AulG5ISxDvUa98TQuGWBeV1j5cBzwodFi6sWcVR9LJtpOCjf4GH5GpO5rGEBDMB7DHwrwhTHMulKC2JxdAi+7SJtI1nSlN/AHyrIXPPADsgINH+qPFl+eA=="

#4
result="lIduaeOFDnOb1ddXJQ29RD/4j2iQsrcWgZUsLPrz+B51Xw4VSkO4fZJngqUkBw1mxaG9lvCGeID5j1v2Bv9ki9sfmApcGqV7aAPjHkiTBPvDjpWscGJlZXaHJfg1L/oBheF9mJ08uJzI5KAy6+TtByLrMhcLi077tj0rHvM92zqQhHHooGWaqbnWFzBlLT3Ham5ZcpHXbAnSYwWVc7ILno0Y/poCm+TGG8taXZXFZqEzYvKhDgm+LVHqZfpEE8rnQNfwLgJAZLsE/dWQvtFa/rHjcCA+O6qO2mFnVjg8i3iIzy4gHs12wb+BlLglrWvV1cl6XvNc1mGfDy4H324ptA=="

#5
result="KEgbzIA91SUS7c6sI3Zt4fx4LAcBZs6vth8iYqkZWPMjY+irb5oN4EihbZeR+9DbzTH4RidQBIj8Woj8cqo5tGSka29Bg+eBjIRjQozMlclEiCPg5YG1im5ozCOsTG/rHJr4IZZq1O2Qkh+uV4wvtJaym3H977qgfeHhwhSYbsQeqeyHZy5ieiVKdqAF1WvgHuBfEu6u2eXRoJt6JhmZA+4lZ5zGj6+Efj8njW+4cP+FBArdKZbkj+9UUMtiauYzX3nmVKAiMaVIkQidI+lTeaqOZzANGuqp9Ex8sYkeGLcpDELvC6wdBRaWr+dX9cuEtgeBIT24MkFGmiyc6CmLOA=="

c++ (openssl) 代码:

#include <string.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/opensslconf.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/rc4.h>
#include <openssl/bio.h>
#include <openssl/evp.h>

std::string base64_encode(const std::string& input)
{
    const auto base64_memory = BIO_new(BIO_s_mem());
    auto base64 = BIO_new(BIO_f_base64());
    base64 = BIO_push(base64, base64_memory);
    BIO_write(base64, input.c_str(), static_cast<int>(input.length()));
    BIO_flush(base64);
    BUF_MEM* buffer_memory{};
    BIO_get_mem_ptr(base64, &buffer_memory);
    auto base64_encoded = std::string(buffer_memory->data, buffer_memory->length - 1);
    BIO_free_all(base64);
    return base64_encoded;
}

int main()
{
    char key[] = "981b4b1e5d0a4db79229c454d091ec76afb1e0b945ea68ee3402ab82450b7fc0b6030641dc8fb098f864f847cdb0fabf7d2f1514ddea140a4d51195cdbbc0ff05eb5bb3a708aed95c6481a6b120c308a577494eec0135cb3dd478c5b9279b95edf8fcd875dfb309a35d2454ba47ce7032961f41ea51dfc3b2a2ee776d2a60edbe33f02a82a4d40c323f4eca0802321d3e163b20ed7e44714c9f476ce51c0010f410cdfa7bb93524550e9e2390b5e470e8450f11a8840ca6eb0a9d343892fb87ae52c17af1720017e82055c3e1ea7e184923b9efce36e910a72886971db9f19eda6d3533de6e3949d92434730691209fc5e0a8f3ac525c7aca900782e6b2244b7";

    char palavra[] = "password";
    char crip[512];
    RSA* pubkey = RSA_new();
    BIGNUM* modul = BN_new();
    BIGNUM* expon = BN_new();

    BN_hex2bn(&modul, (const char*)key);
    BN_hex2bn(&expon, "010001");

    RSA_set0_key(pubkey, modul, expon, NULL);

    RSA_public_encrypt(strlen((const char*)palavra), (const unsigned char*)palavra, (unsigned char*)crip, pubkey, RSA_PKCS1_PADDING);

    //std::cout << "result: " +  base64_encode(crip) << std::endl;
    std::cout << "result: " << crip << std::endl;

    return 0;
}

C++ 输出:

#1
result: SNpRW2q1crBPVLPYJ3ZmRm+OaVJkXeHYhQgHZ3Oo+eKe/A==

#2
result: OO7UtCuhjtuh1CkiJyw//5iyKrCMjvHSQOfD3XM3IPIRxFwRfYm1vUoOQZdiJcNs6zdSkcBaHrvnQ/+vwtSmqKkv35NOacoK7cXNpG/i+L+zqYtFRc4/ryPHE5gLo25tHO5g+xHnls5yZc+AD0+IKJ1NJYL20Z5RzXUNYVOEG2zkUa8=

#3
result: IaHXTdFcrWF6eWA2fKsRf/7wEf87Rn0n9zld4jzCySX2msvE9MFPwaaD3eqlfpR3x8wcVyKBVhxaqSDPacBMqpCQOTJI5z9k78E8dkdUtbysfM/jdqVNv+ClSAFAN9R2mtKLaHCPBuYQzvHomwuhxagHLULOGfqKGVSM+hRmL+MK8Eux4xcUvTrarY4YGUbBiJk21m6aYELfpxls/yT1pxI1U3j3odIM4F/RkO3iJ03kVMFSItc3k81E9iZPPC1DowpaD81iZrMCmQbh9PH3U8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzHBhc3N3b3Jk

#4
result: BjuGPZe7QHOBMKKXMh8pDlddIbT9NOynRYOi9lGTDVb9YTZ8/X+YIHJKSGWdQ1/OCYgW

#5
result: B4wPPRrrAe5zplMoCcxtf3tzP3y7eC/fkE4cBHRL26clYjzEVyjMzPst/f1zWH++NQcEu8w8m3Fb1OSKdhGkn8gebFxPPZpautAquGDImfl0ftWYtnj2FrNDER4=

模数 98...b7 由 512 个十六进制数字组成,因此大小为 256 字节(2048 位)。因此 crip 必须只有 256 字节(而不是 512)。通过此更改,RSA_public_encrypt() 在我的机器上使用 PKCS#1 v1.5 填充执行正确的 RSA 加密,并生成与模数大小相同的密文,即 256 字节。

发布的 base64 结果大小不同是由于将密文传递给 base64_encode() 函数时出现的第二个错误。正如评论中已经怀疑的那样,密文中出现的 0x00 值是原因。为了考虑数据的完整大小,必须明确指定密文的大小(s. here,ctor(5))。通过此更改,base64 编码的密文具有相同的大小,类似于 PHP 代码。

完整的变化是:

char crip[256];
...
std::cout << "result:\n" + base64_encode(std::string(crip, 256)) << std::endl; 

输出示例:

result:
LqUnij6tVy+Qprw9nyUeyYgZYwmz/GZ3/A/EVbaDA27ORHzc8tkHWTCVk7DssBSf
LyPRmrBhyUGZMFBjpLH5Iz1VKBacR36UeNif+GzoYdrtmOaSzDs+B74isAToJngJ
0X7hXIOFpMfQylrSFRFoajaBld+edBH9bOQ/U7ogQkoMDHKkTgT07MXj+p7s6dIe
K8E39QIZj5lF85i14MJwEvUBpDKyx3lWjq32d+VJOFHX65g2SQuTugQeAs6+eG7s
e7KDmExvvS+oGA6rInT+icfRN6CKskp4TCto1NgfwtVMVzEfbsHU2aZjcA3EAKSR
Pq3EHfcW3Z2wSy2EjzIbcw==