I have PHP code, which make RSA encryption. This PHP code give me correct output. I need same result, but using c++. I try make c++ code, but got incorrect RSA encryption result. Not same like if using php code. What i need change in c++ code, for getting same result like on php? Thanks.
PHP code:
<?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 outputs:
#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) code:
#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++ outputs:
#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=
The behavior is actually caused by two counteracting bugs. The first bug always occurs, results in a constant lengthening of the output, and is the cause of the garbage at the end.
The second bug does not always occur, results in a varying shortening of the output and, when it occurs, conceals the first bug.
Bug 1: The modulus 98...b7 consists of 512 hex digits and thus has a size of 256 bytes (2048 bits). Since for RSA the size of the ciphertext is equal to the size of the modulus, crisp
must be only 256 bytes and not 512 bytes as in the current code.
This oversized crisp
is the cause of the lengthened ciphertext. With the reduction to 256 bytes RSA_public_encrypt()
performs a correct RSA encryption with PKCS#1 v1.5 padding and creates ciphertexts with correct length, i.e. 256 bytes.
Bug 2: The string
constructor implicitly used when passing the ciphertext to the base64_encode()
function is only suitable for 0x00 terminated strings, not for binary data like ciphertexts which may contain 0x00 values. As already suspected in the comment, if the ciphertext contains 0x00 values, only the first null-terminated string is passed and the rest is lost.
So that the full size of the data is taken into account, the size of the ciphertext must be specified explicitly. For this, the appropriate string
constructor must be used (see here, (5) from buffer, and here). With this change, the Base64 encoded ciphertexts have the same size, analogous to the PHP code.
The complete changes are:
#define SIZE 256
..
char crip[SIZE]; // fixes bug 1
...
std::cout << "result:\n" + base64_encode(std::string(crip, SIZE)) << std::endl; // fixes bug 2
Example for an output:
result:
LqUnij6tVy+Qprw9nyUeyYgZYwmz/GZ3/A/EVbaDA27ORHzc8tkHWTCVk7DssBSf
LyPRmrBhyUGZMFBjpLH5Iz1VKBacR36UeNif+GzoYdrtmOaSzDs+B74isAToJngJ
0X7hXIOFpMfQylrSFRFoajaBld+edBH9bOQ/U7ogQkoMDHKkTgT07MXj+p7s6dIe
K8E39QIZj5lF85i14MJwEvUBpDKyx3lWjq32d+VJOFHX65g2SQuTugQeAs6+eG7s
e7KDmExvvS+oGA6rInT+icfRN6CKskp4TCto1NgfwtVMVzEfbsHU2aZjcA3EAKSR
Pq3EHfcW3Z2wSy2EjzIbcw==