[pycrypto] RSA / OAEP - ValueError: Plaintext is too long.

Lorenz Quack don at amberfisharts.com
Fri Apr 20 14:35:12 EDT 2012

Hey Antonio,

first of all I want to point out that Cryptography is *hard*! There are innumerable things you can get wrong.
So if you are trying to implement crypto stuff for a production system I would suggest: Don't! Use existing established 
software instead.
I consider PyCrypto to be a rather lowlevel crypto library which only provides the primitives to crypto. Getting this 
stuff right is of course paramount but still you can do a lot wrong in combining these primitives in the wrong way.
One example would be padding which at first seems trivial but can lead to disastrous results if done wrong.

If on the other hand you are doing this out of pure interest in order to educate yourself: Go ahead. I find crypto to be 
very fascinating.

In crypto you need to clearly state what your goal is. In my experience the most often desired goals are:
  - authentisity (the receiver of a message can be sure the message really comes the sender)
  - integrity (the receiver can be sure he received the message as it was originally written)
  - confidentiallity (nobody but the receiver can read the message)
  - a combination of the above
So depending on what your goal is you need to do different things.
Broadly speeking you use signing (Hash+RSA) for authentisity, Hash functions for integrity and AES+RSA for confidentiallity.
But appling and combining these is really tricky.

For example it makes a difference if you first sign a message and then encrypt or if you first encrypt it and then sign 
it. Depending on the case it might be neccessary to do encrypt-sign-encrypt or sign-encrypt-sign.

so what you seem to try to do is confidentiallity only.
to reiterate what others have already said you need to do the following:
  1) create a cryptografically strong random private and public keypair k_priv and k_pub
  2) distrubute your public key.
Then for every message/session do:
  3) create a random key "k_aes"
  4) pad your message to the block length (typically 16 bytes for AES). use an appropriate padding scheme!:
     "m_padded = pad(m)"
  5) encrypt the padded message using a symetric cipher (e.g. AES) using k_aes:
     "e_m = sym_encrypt(m_padded, k_aes)"
  6) pad the message/session key. use an appropriate padding scheme (e.g. OEAP):
     "k_aes_padded = pad(k_aes)"
  7) encrypt the padded random key k_ase_padded using an asymetric cipher (e.g. RSA) using your private key k_priv:
     "e_k = asym_encrypt(k_aes_padded, k_priv)"
  8) send both e_m and e_k to the recipiant

the receiver can then:
  1) knowing the message comes from you, decrypt the padded message/session key k_aes_padded by using your public key:
     "k_aes_padded = asym_decrypt(e_k, k_pub)"
  2) unpad the message/session key:
     "k_aes = unpad(k_aes_padded)"
  3) decrypt the message using the retrieved message/session key:
     "m_padded = sym_decrypt(e_m, k_aes)"
  4) retrieve the message by removing the known padding scheme:
     "m = unpad(m_padded)"

A few notes on the above:
  * The message/session key can be different every message or be the same for more than one message (a session).
    This depends on your implmentation ("the protokol"). So if you use a new k_aes for every message then there
    is no shared state but you need more bandwith (you need to send e_k for every message and not only for a
     session) and more CPU power (you need to create, encrypt and decrypt the k_aes for every message).
  * There is a theoretical limit on howmany bytes you can safly encrypt with a session key. However, I don't
    have the numbers right now.
  * The padding for k_aes and the message doesn't have to be the same. I don't know if there is a standard way
    of doing both.

I hope this helps!


PS: full disclosure: I'm by no means a crypto expert myself and the above message might (and probably will) contain 
inaccuracies and maybe even falshoods (these would then be unintentionally of course). I did contribute to pycrypto 
though (namely work on the sha-2 implementation and the getStrongPrime and isPrime functions).

On 04/20/2012 06:48 PM, Antonio Teixeira wrote:
> Hello Legrandin & Others.
> I'm currently trying to implement the following :
> The "proper" way to do encryption would be to create a random AES
> session key (16 bytes), encrypt it with RSA (hopefully at least 2048
> bit long), send it, pad the data, encrypt it with AES, send it.
> Ok So ..
>   - Create A Random AES 16 Bytes ( I'm assuming this will be the "secret")
> - Pad The Payload
> - Encrypt Using AES
> - Encrypt The Secret +  Payload With the RSA Key
> - Make A Signature Of The Entire "Encrypted Payload"
> - Append it to the "Encrypted Payload"
> Send it ....
> Recv it ..
> Make the reverse process.
> One thing i can't use the Normal SSL/TLS type of "session key" since there is no state across requests or during the
> handshake.
> Meaning "one worker can receive the request but another one can answer it and there is no shared memory between the two."
> 2012/4/12 Antonio Teixeira <eagle.antonio at gmail.com <mailto:eagle.antonio at gmail.com>>
>     Legrandin thank you for your help.
>     When i have time i will put something on pastebin so it can serve as example for future members that require this
>     type of solution :)
>     Regards
>     A/T
>     2012/4/11 Legrandin <gooksankoo at hoiptorrow.mailexpire.com <mailto:gooksankoo at hoiptorrow.mailexpire.com>>
>          > So after a small search i found out that if i increase the RSA Modulus i'm
>          > able to encrypt larger number of bits ( makes sense )  but this feels dirty.
>          >
>          > What do your guys recommend ?
>          >
>          > Breaking the data in chunks and encrypting part by part joining it all in a
>          > buffer and send it down the socket all in one with the other server
>          > decrypting part by part and merging the data again ?
>          >
>          > P.S - I dont mind fishing by myself just trying to understand the best "way
>          > / more correct way " to do it :)
>         Hi Antonio,
>         Increasing the RSA key length is not "dirty": it simply increases
>         security (and incidentally useful payload size) at the expense of
>         decryption speed.
>         If decryption speed is not that important to you, and you have a clear
>         idea on how long you data can be at most, go ahead and increase the
>         key size. The time you gain by taking this approach can be spent on
>         important tasks like making the private key secure, or adding some
>         form of authentication to your protocol.
>         The "proper" way to do encryption would be to create a random AES
>         session key (16 bytes), encrypt it with RSA (hopefully at least 2048
>         bit long), send it, pad the data, encrypt it with AES, send it.
>         Additionally, you should also sign the data and send the signature
>         along.
>         At the receiving end, you decrypt the session key with RSA, decrypt
>         the data with AES, unpad the data, and verify its signature.

More information about the pycrypto mailing list