Hello, guys.
I'm trying to use RSA in my software and I found strange behavior. For the serialization of the key we use rsa_export, and rsa_import for the deserialization.
But I have the key that takes exactly 160 bytes of memory when it is serialized. I use rsa_import and then rsa_export on that key. And after second rsa_export the size is reduced to 138 bytes. N is 128 bytes (1024 bit), e is 17. It is a public key, of course.
Could you please explain how it is possible and how I can craft the keys with the same size?
Here is the strange key:
const std::array<uint8_t, 160> publicOldKey
{
0x30, 0x81, 0x9D, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
0x05, 0x00, 0x03, 0x81, 0x8B, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0xD8, 0x7B, 0xA2,
0x45, 0x62, 0xF7, 0xC5, 0xD1, 0x4A, 0x0C, 0xFB, 0x12, 0xB9, 0x74, 0x0C, 0x19, 0x5C, 0x6B, 0xDC,
0x7E, 0x6D, 0x6E, 0xC9, 0x2B, 0xAC, 0x0E, 0xB2, 0x9D, 0x59, 0xE1, 0xD9, 0xAE, 0x67, 0x89, 0x0C,
0x2B, 0x88, 0xC3, 0xAB, 0xDC, 0xAF, 0xFE, 0x7D, 0x4A, 0x33, 0xDC, 0xC1, 0xBF, 0xBE, 0x53, 0x1A,
0x25, 0x1C, 0xEF, 0x0C, 0x92, 0x3F, 0x06, 0xBE, 0x79, 0xB2, 0x32, 0x85, 0x59, 0xAC, 0xFE, 0xE9,
0x86, 0xD5, 0xE1, 0x5E, 0x4D, 0x17, 0x66, 0xEA, 0x56, 0xC4, 0xE1, 0x06, 0x57, 0xFA, 0x74, 0xDB,
0x09, 0x77, 0xC3, 0xFB, 0x75, 0x82, 0xB7, 0x8C, 0xD4, 0x7B, 0xB2, 0xC7, 0xF9, 0xB2, 0x52, 0xB4,
0xA9, 0x46, 0x3D, 0x15, 0xF6, 0xAE, 0x6E, 0xE9, 0x23, 0x7D, 0x54, 0xC5, 0x48, 0x1B, 0xF3, 0xE0,
0xB0, 0x99, 0x20, 0x19, 0x0B, 0xCF, 0xB3, 0x1E, 0x5B, 0xE5, 0x09, 0xC3, 0x3B, 0x02, 0x01, 0x11
};
Here is the code for investigation:
std::cout << "Old key size is: " << theKey.size() << std::endl;
if (auto res = rsa_import(theKey.data(),
static_cast<unsigned long> (theKey.size()),
&key) == CRYPT_OK)
{
auto e = (const mp_int*)(key.e);
auto N = (const mp_int*)(key.N);
auto d = (const mp_int*)(key.d);
auto e_size = mp_unsigned_bin_size(e);
auto N_size = mp_unsigned_bin_size(N);
auto d_size = mp_unsigned_bin_size(d);
std::cout << "E size: " << e_size << std::endl;
std::cout << "N size: " << N_size << std::endl;
std::cout << "d size: " << d_size << std::endl;
std::cout << "E is : " << *(e->dp) << std::endl;
std::cout << "key type is: " << key.type << std::endl;
std::vector<uint8_t> result(1024);
unsigned long outlen = result.size();
if (rsa_export(reinterpret_cast<unsigned char*> (result.data()),
&outlen, PK_PUBLIC, &key) != CRYPT_OK)
{
throw std::exception("Unable to save public key");
}
result.resize(outlen);
std::cout << "New key size is: " << result.size() << std::endl;
And here is the printed output:
Old key size is: 160
E size: 1
N size: 128
d size: 0
E is : 17
key type is: 0
New key size is: 138
Why they are different and how can I craft the first type of key (160 bytes)?