tags:

views:

330

answers:

2

I'm trying to encrypt some date using a public key derived form the exchange key pair made with the CALG_RSA_KEYX key type. I determined the block size was 512 bits using cryptgetkeyparam KP_BLOCKLEN. It seems the maximum number of bytes I can feed cryptencrypt in 53 (424 bits) for which I get an encrypted length of 64 back. How can I determine how many bytes I can feed into cryptencrypt? If I feed in more than 53 bytes, the call fails.

+2  A: 

EDIT: Although this response is marked as accepted by the OP, please see Rasmus Faber response instead, as this is a much better response. Posted 24 hours later, Rasmus's response corrects factual errors,in particular a mis-characterization of OAEP as a block cipher; OAEP is in fact a scheme used atop PKCS-1's Encoding Primitive for the purpose of key-encryption. OAEP is more secure and puts an even bigger limit on the maximum message length, this limit is also bound to a hash algorithm and its key length.

Another shortcoming of the following reply is its failure to stress that CALG_RSA_KEYX should be used exclusively for the key exchange, after which transmission of messages of any length can take place with whatever symmetric key encryption algorithm desired. The OP was aware of this, he was merely trying to "play" with the PK, and I did cover that much, albeit deep in the the long remarks thread.

Fore the time being, I'm leaving this response here, for the record, and also as Mike D may want to refer to it, but do remark-me-in, if you think that it would be better to remove it altogether; I don't mind doing so for sake of clarity!
   -mjv- Sept 29, 2009

Original reply:

Have you check the error code from GetLastError(), following cryptencrypt()'s false return? I suspect it might be NTE_BAD_LEN, unless there's be some other issue.

Maybe you can post the code that surrounds your calling criptencryt().

Bingo, upon seeing the CryptEncrypt() call.

You do not seem to be using the RSAES w/ OAEP scheme, since you do not have the CRYPT_OAEP flag on. This OAEP scheme is a block cipher based upon RSAES. This latter encryption algorihtm, however, can only encrypt messages slightly less than its key size (expressed in bytes). This is due to the minimum padding size defined in PKCS#1; such padding helps protect the algorithm from some key attacks, I think the ones based on known cleartext).

Therefore you have three options:

  • use the CRYPT_OAEP in the Flag parameter to CryptEncrypt()
  • extend the key size to say 1024 (if you have control over it, beware that longer keys will increase the time to encode/decode...)
  • Limit yourself to clear-text messages shorter than 54 bytes.

For documentation purposes, I'd like to make note of a few online resources.

 - The [RSA Labs][1] web site which is very useful in all things crypto. 
 - Wikipedia articles on the subject are also quite informative, easier to read
   and yet quite factual (I think).

When in doubt, however, do consult a real crypto specialist, not someone like me :-)

mjv
Mike D
I found something more at http://msdn.microsoft.com/en-us/library/ms867086.aspx that has left me more confused than ever. Look about 3/4 of the way to the end under the heading "Encrypting and Decrypting Data: CryptEncrypt, CryptDecrypt". CONTINUED IN NEXT COMMENT
Mike D
There you will find an example of call cryptencrypt with a NULL pbData parameter in order to find the required buffer size. My confusion arises because 1) we originally had the length of the data in DwSize. After the first call dwSize may have been increased so the second call will actually encrypt more data than intended. 2) the data being encrpyted is whatever junk was left in the buffer acquired with new() but maybe the author simply negelected to copy it?
Mike D
@Mike: you are right, on both counts, this MS example is flawed. I guess the author was focused on this ciphtext length discovery technique and failed to properly set the stage for the 2nd call, which as you noted should have 1) the cleartext be copied to the buffer and b) the dwSize set to the length of cleartext.
mjv
I created the keys in a container with PROV_RSA_FULL. I created the key as CALG_RSA_KEYX. I'm just playing here. I naively assumed I'd be able to encrypt a arbitrary amount of data with the public key. Are you saying that I can only encrypt data of a certain length namely keys with this key? Or can I encrypt a large amount of data if the last block is only 53 bytes? I don't know what RSAES/OAEP you mention means. I do understand that this public key is usually used to encrypt a session key. What type of key would you suggest for that purpose?
Mike D
@Mike:check my edits. I rushed through earlier and didn't explain it well, indeed wrongly... Basically you _need_ to use the OAEP scheme (a block cipher, basically) to break the 53 bytes barrier. (or 117 bytes limits with 1024 bit keys)
mjv
@Mike, now, changing the topic. What is the purpose for you to use CALG_RSA_KEYX if you're going to encrypt "regular" messages with the host's public key? I forgot the details but the RSA Key Exchange algo uses a PK only for the purpose of sending a symetris cipher algoritym (such as say AES) to the other party. The exchange for that session are then based on that symetric cipher.
mjv
Thanks! Since I'm just playing here (actually I'm writing a little application to exchange encrypted and signed msgs with others) I think I will use the public key simply to encrypt a session key as I suppose the designers intended. My msg will then consist of the public key encrypted session key and the session key encrypted plain text. There is an example of this in the MSDN under cryprdecrypt (hopefully higher quality than the other thing I found). That example uses a block mode CALG_RC2 session key. Wouldn't stream mode RC4 make just as much sense?
Mike D
Understand I'm just playing and know very little about this. Playing is my way of learning. Thanks again!
Mike D
@Mike I understand. t'is cool/ok to use the PK obtained as part of the Key Exchange protocol, for transmitting whatever. I think that PKs for key exchanges tend to be bigger since the PK encoding is only needed once for a relatively small payload, so there is no real penalty to use a more CPU intensive key. Whatever you use for the symmetric session depends on your application. I [intuitively] favor bloc ciphers but that's not based on any scientific cryptanalisis... RC2 or RC4 (for stream) are "ok", I'd move to some' stronger if security is an issue (again AES or blowfish for ex.)
mjv
@Mike: one last questions, to close this item. You were able to encrypt any size of message with the OAEP flag, right ?
mjv
@mjv I didn't try adding the OAEP flag, it's not even mentioned in the old MSDN info I keep on my PC. I did see it in the online MSDN but it said I needed the enhanced or next generation crypto which I probably don't have. I've got everything working. I used a session key for the bulk of the encryption. I now see how all the crypto functions mesh together Eg. the hExpKey key handle on the export key call for the session key. Really quite nice. So it turns out you can teach an old dog new tricks! Thanks for the help :-)
Mike D
OAEP is not a block cipher. In fact it usually supports shorter messages for a given modulus size compared to PKCS#1 v.1.5.
Rasmus Faber
+2  A: 

RSA using the usual PKCS#1 v.1.5 mode can encrypt a message that is at most k-11 bytes, where k is the length of the modulus in bytes. So a 512 bit key can encrypt up to 53 bytes and a 1024 bit key can encrypt up to 117 bytes.

RSA using OAEP can encrypt a message up to k-2*hLen-2, where k is the modulus byte-length and hLen is the length of the output of the underlying hash-function. So using SHA-1, a 512 bit key can encrypt up to 22 bytes and a 1024 bit key can encrypt up to 86 bytes.

You should not normally use a RSA key to encrypt your message directly. Instead you should generate a random symmetric key (f.x. an AES key), encrypt your message with the symmetric key, encrypt the key with the RSA key and transmit both encryptions to the recipient. This is usually called hybrid encryption.

Rasmus Faber
Thank you Rasmus, for correcting my inaccurate statements and for stressing that RSA=OAEP should exclusively be use as a key exchange protocol. Although I made this point deep into the remarks, it is important to bring this to front lest future readers loose time and produce flawed implementations based on my overall confusing -and inaccurate- response. I was merely humoring the OP (whom I believe was also aware of the intended use of RSA Key Exchange) in his attempt to "play with the PK". My response now "redirects" to yours along with my +1 it may eventually float up top.
mjv
@Rasmus: do advise if you think I should delete my response altogether.
mjv
I think it would be a shame if you deleted it. You fixed the response to show the correct answer and the discussion in the comments is interesting.
Rasmus Faber