Majid Q.
Majid Q.

Reputation: 798

RSA variable encrypted length

I have sample program (taken from online samples) that creates RSA encryption.

#include <cstring>
#include <iostream>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>

RSA * createPublicRSA(unsigned char * key)
{
    RSA * rsa= NULL;
    BIO * keybio = BIO_new_mem_buf(key, -1);
    rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
    return rsa;
}

int public_encrypt(unsigned char * data, int data_len, unsigned char * key, unsigned char * encrypted)
{
    RSA * rsa = createPublicRSA(key);
    int result = RSA_public_encrypt(data_len, data, encrypted, rsa, RSA_PKCS1_PADDING);
    return result;
}

int main(int argc, char* argv[]) {
    unsigned char publicKey[]="-----BEGIN PUBLIC KEY-----\n"\
                              "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8Dbv8prpJ/0kKhlGeJY\n"\
                              "ozo2t60EG8L0561g13R29LvMR5hyvGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+\n"\
                              "vw1HocOAZtWK0z3r26uA8kQYOKX9Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQAp\n"\
                              "fc9jB9nTzphOgM4JiEYvlV8FLhg9yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68\n"\
                              "i6T4nNq7NWC+UNVjQHxNQMQMzU6lWCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoV\n"\
                              "PpY72+eVthKzpMeyHkBn7ciumk5qgLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUy\n"\
                              "wQIDAQAB\n"\
                              "-----END PUBLIC KEY-----\n";

    unsigned char plainText[2048/8] = "plain text"; //key length : 2048
    size_t length = strlen(reinterpret_cast<const char*>(plainText));
    unsigned char encrypted[4098]= {};
    int encrypted_length = public_encrypt(plainText, length, publicKey, encrypted);
    if (argc > 1) {
        printf("Encrypted length: %d (Actual length: %lu)\n", encrypted_length, strlen(const_cast<const char*>(reinterpret_cast<char*>(encrypted))));
    } else {
        std::cout << encrypted;    
    }
}

And private key is:

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAy8Dbv8prpJ/0kKhlGeJYozo2t60EG8L0561g13R29LvMR5hy
vGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+vw1HocOAZtWK0z3r26uA8kQYOKX9
Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQApfc9jB9nTzphOgM4JiEYvlV8FLhg9
yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68i6T4nNq7NWC+UNVjQHxNQMQMzU6l
WCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoVPpY72+eVthKzpMeyHkBn7ciumk5q
gLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUywQIDAQABAoIBADhg1u1Mv1hAAlX8
omz1Gn2f4AAW2aos2cM5UDCNw1SYmj+9SRIkaxjRsE/C4o9sw1oxrg1/z6kajV0e
N/t008FdlVKHXAIYWF93JMoVvIpMmT8jft6AN/y3NMpivgt2inmmEJZYNioFJKZG
X+/vKYvsVISZm2fw8NfnKvAQK55yu+GRWBZGOeS9K+LbYvOwcrjKhHz66m4bedKd
gVAix6NE5iwmjNXktSQlJMCjbtdNXg/xo1/G4kG2p/MO1HLcKfe1N5FgBiXj3Qjl
vgvjJZkh1as2KTgaPOBqZaP03738VnYg23ISyvfT/teArVGtxrmFP7939EvJFKpF
1wTxuDkCgYEA7t0DR37zt+dEJy+5vm7zSmN97VenwQJFWMiulkHGa0yU3lLasxxu
m0oUtndIjenIvSx6t3Y+agK2F3EPbb0AZ5wZ1p1IXs4vktgeQwSSBdqcM8LZFDvZ
uPboQnJoRdIkd62XnP5ekIEIBAfOp8v2wFpSfE7nNH2u4CpAXNSF9HsCgYEA2l8D
JrDE5m9Kkn+J4l+AdGfeBL1igPF3DnuPoV67BpgiaAgI4h25UJzXiDKKoa706S0D
4XB74zOLX11MaGPMIdhlG+SgeQfNoC5lE4ZWXNyESJH1SVgRGT9nBC2vtL6bxCVV
WBkTeC5D6c/QXcai6yw6OYyNNdp0uznKURe1xvMCgYBVYYcEjWqMuAvyferFGV+5
nWqr5gM+yJMFM2bEqupD/HHSLoeiMm2O8KIKvwSeRYzNohKTdZ7FwgZYxr8fGMoG
PxQ1VK9DxCvZL4tRpVaU5Rmknud9hg9DQG6xIbgIDR+f79sb8QjYWmcFGc1SyWOA
SkjlykZ2yt4xnqi3BfiD9QKBgGqLgRYXmXp1QoVIBRaWUi55nzHg1XbkWZqPXvz1
I3uMLv1jLjJlHk3euKqTPmC05HoApKwSHeA0/gOBmg404xyAYJTDcCidTg6hlF96
ZBja3xApZuxqM62F6dV4FQqzFX0WWhWp5n301N33r0qR6FumMKJzmVJ1TA8tmzEF
yINRAoGBAJqioYs8rK6eXzA8ywYLjqTLu/yQSLBn/4ta36K8DyCoLNlNxSuox+A5
w6z2vEfRVQDq4Hm4vBzjdi3QfYLNkTiTqLcvgWZ+eX44ogXtdTDO7c+GeMKWz4XX
uJSUVL5+CVjKLjZEJ6Qc2WZLl94xSwL71E41H4YciVnSCQxVc4Jw
-----END RSA PRIVATE KEY-----

When I build it

g++ encr.cpp -o encr -lcrypto -I/opt/local/include/

and run it several times, I get variable "Actual length"

$ ./encr show-length
Encrypted length: 256 (Actual length: 256) <--- Correct
$ ./encr show-length
Encrypted length: 256 (Actual length: 79)
$ ./encr show-length
Encrypted length: 256 (Actual length: 215)
$ ./encr show-length
Encrypted length: 256 (Actual length: 52)
$ ./encr show-length
Encrypted length: 256 (Actual length: 256) <--- Correct
$ ./encr show-length
Encrypted length: 256 (Actual length: 48)

You may also do ./encr | wc | awk '{print $3;}' to get sizes

Whereever I mentioned "correct" it will decrypt fine otherwise I get errors (here are sample)

$ ./encr | openssl rsautl -decrypt -inkey private.pem
RSA operation error
140735156518992:error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error:rsa_pk1.c:273:
140735156518992:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:rsa_eay.c:602:
$ ./encr | openssl rsautl -decrypt -inkey private.pem <---------------------------------- CORRECTLY PADDED
plain text$ ./encr | openssl rsautl -decrypt -inkey private.pem
RSA operation error
140735156518992:error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error:rsa_pk1.c:273:
140735156518992:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:rsa_eay.c:602:
$ ./encr | openssl rsautl -decrypt -inkey private.pem <---------------------------------- CORRECTLY PADDED
plain text$ ./encr | openssl rsautl -decrypt -inkey private.pem <---------------------------------- CORRECTLY PADDED
plain text$ ./encr | openssl rsautl -decrypt -inkey private.pem
RSA operation error
140735156518992:error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error:rsa_pk1.c:273:
140735156518992:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:rsa_eay.c:602:

What is it that I'm doing wrong in my usage of RSA_public_encrypt?

Upvotes: 1

Views: 1346

Answers (1)

bartonjs
bartonjs

Reputation: 33266

In C/C++ char* and unsigned char* can either mean "a string" or "some bytes", and it's up to the developer to know which is which (though unsigned char* usually means "some bytes", the "unsigned" being the clue).

RSA, like almost all computer-designed cryptographic routines, operates on bytes. Sometimes the input bytes are text, but the output bytes are almost always not.

If you had a 40-bit RSA key, it could produce as an answer 21 74 65 78 74. strlen on a pointer to that location will return... some number that is at least 5. If it returns exactly 5 it means that we got lucky and the next segment of memory was already assigned as 0x00. And in this lucky case we could printf (%s) the pointer and it will emit !text.

It could have just as likely produced 25 00 F2 1B D5, which will strlen as 1 because the second byte being 0x00 is how strlen interprets "end of string".

If you need your output to be text, you'll need to convert it to a textual form. Hexadecimal is a common way for short values, but RSA-2048 produces a 256-byte answer. That would be 512 hex characters, or in Base64 it would only be 344, which is why Base64 encoding tends to be used in these situations.

Upvotes: 2

Related Questions