RSA encryption of long strings with Openssl

S

stefko

Hi folks,
I don't know if this is a bug, but it seems to me like this. This is
when PKCS#1 padding is used. I haven't tried it with other types of
paddig.
I'll give an example of what I mean:

------------------------ cut -----------------------------
require 'openssl'
include Openssl
include PKey

p rsa = PKey::RSA.new(512)
str = "a string longer than 53 bytes. a string longer than 53 bytes. a
string longer than 53 bytes.a string longer than 53 bytes."
p enc = rsa.public_encrypt(str)
p dec = rsa.private_decrypt(enc)

------------------------------ cut -----------------------------

And this crashes with the error :
public_encrypt: data too large for key size (Openssl::pKey::RSAError)



I've searched through Ruby CVS for openssl extensions. here is the
problematic line:

buf_len = RSA_public_encrypt(RSTRING(buffer)->len,
RSTRING(buffer)->ptr,
RSTRING(str)->ptr, pkey->pkey.rsa,
pad);

The problem comes from the internal workings of rsa encryption with
PKCS#1 padding. I don't know the details, but the main point is that
one should not give this function more than RSA_size(rsa) - 11 bytes at
once. The input string should be divided into smaller chunks which are
given to the encrypt function.
Here is what I mean in C code :

-------------------------------- cut
-----------------------------------------
int rsa_size = RSA_size(rsa);
int block_size = rsa_size - 12;
int blocks = msg_len/block_size;
int rest = msg_len % block_size;
int enc_len = 0;
unsigned char* enc = 0;
int curr_len = 0;
int i = 0;
if (0 == rest) {
enc = malloc(blocks*rsa_size + 1);
}
else {
enc = malloc((blocks+1)*rsa_size + 1);
}

for (i = 0; i < blocks; i++) {
if (0 > (curr_len = RSA_public_encrypt(block_size , msg +
i*block_size, enc + i*rsa_size, _rsa, RSA_PKCS1_PADDING))) {
goto err;
}
enc_len += curr_len;
}
if (0 != rest) {
if (0 > (curr_len = RSA_public_encrypt(rest , msg + i*block_size, enc
+ i*rsa_size, _rsa, RSA_PKCS1_PADDING))) {
goto err;
}
enc_len += curr_len;
}


-------------------------------- cut ---------------------------------

This code works fine in a C programme.

I suppose a similar issue exists is applicable to the decrypting
functions.
 
E

evanwebb

This is actually an expected behavior. Just as the C function
RSA_public_encrypt can't take a string larger than the key, neither can
the Ruby one. I think you're assuming that the ruby one should have the
logic this C one has built in, but thats not currently true. If you
want to encrypt a string larger that possible by the key size, you have
to split it up yourself in ruby land, just like you have to split it up
in C land.
 
S

stefko

Well, you are probably right.
But this imposes too much knowledge to the users of the library,
because they have to have in mind that for encrypting the max text
length should be RSA_size(rsa) - 11 and for decrypting the chunks of
encrypted data should be RSA_size(rsa). And this is true only for
PKCS#11 padding. If you don't use padding, then you have to feed the
encrypting function with exactly RSA_size(size) bytes.
I don't know. I don't feel quite comfortable with this, it is too low
level.
 
E

evanwebb

Well, you're using the OpenSSL ruby bindings, which are just ways of
getting to the OpenSSL functions from ruby land. They aren't really
supposed to be any higher level than the original. Thats what writing a
highlevel layer that goes on top is for.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top