Cannot encrypt a long binary using public_key:encrypt_private/2

I referred to Public/Private Key Encryption, Sign and Verification in Erlang and tried encryption with public_key:encrypt_private/2. Then I realized that short binaries would succeed in encryption, but some long binaries would fail.

{ok, RawSKey} = file:read_file("private.pem").
[EncSKey] = public_key:pem_decode(RawSKey).
SKey = public_key:pem_entry_decode(EncSKey).

Msg = <<"hello crypto world">>.
CMsg = public_key:encrypt_private(Msg, SKey).

LongMsg = binary:copy(Msg, 100).
LongCMsg = public_key:encrypt_private(LongMsg, SKey).

The last line causes the following exception:

** exception error: encrypt_failed
     in function  crypto:pkey_crypt/4
        called as crypto:pkey_crypt(rsa,
                                    <<"hello crypto worldhello crypto worldhello crypto worldhello crypto worldhello crypto worldhello crypto world"...>>,
                                    [65537,
                                     12013166307073578189714319781863709192262344791208022582671826551609494662046052114406874549695398804612347737658196791922142412356722632114572140189217511,
                                     9209171540768978870733286934721344428632073520458535705836894669467034069627578972443921802202732743764323119299244338875947126070436456125761061022784513,
                                     111735386800514912841075555964536257540962056269957166859735471011707190234863,
                                     107514428965293720445949038818625972419837889102017266331964615017386497186697,
                                     110944303603611805900595230988300774935731325627583238766857901721849062211471,
                                     81740298421116696140193429790452075953901500868167787848947448126345417227281,
                                     63135687845367402220547698635889059598150016181271026886461042788829056982347],
                                    [{rsa_padding,rsa_pkcs1_padding}])

The version of Erlang/OTP is 24.1.7.0. Please help me.

2 Likes

This is expected (although confusing because reported error makes no sense) behaviour. If you take a closer look, you’ll find that with RSA you can encode a message of up to 245 bytes long. To be precise, the plaintext length cannot exceed length of the public modulus minus 11 bytes.

See a great response on stackexchange here - RSA maximum bytes to encrypt, comparison to AES in terms of security? - Information Security Stack Exchange for longer explanation.

10 Likes

max-au gave complete explanation of the problem.

You should encrypt not your message, but a symmetric key, used to encrypt your message.

2 Likes

And make sure your symmetric key is generated by a really cryptographically safe random algo (this is a lot of fun in embedded systems because good solutions require paying attention during hardware design already)

3 Likes

I haven’t even thought about it =(

2 Likes

This only apply if using PKCS#1 v1.5 padding. PKCS#1 v1.5 is vulnerable to padding oracle attacks so if that is a possibility the encryption is useless. Make sure you don’t leak information about padding failures or perhaps use a different algorithm. If using OAEP which protects against padding oracle you have less bytes to play with (214 if I am not mistaken).

Also for the symmetric crypto make sure you use Encrypt-Then-Authenticate scheme to prevent padding oracle attacks (and a secure-compare algorithm for the mac verification to prevent timing attacks), or use something like AES-GCM.

Alternatively use libsodium which in theory should make mistakes using the standard crypto primitives less error-prone. GitHub - jlouis/enacl: Erlang bindings for NaCl / libsodium seems to be quite reputable.

4 Likes

One more piece of advice: from the problem you posted you might want to take a break and read a book like Practical Cryptography: Ferguson, Niels, Schneier, Bruce: 9780471223573: Amazon.com: Books

As you see in the answers there are quite a bunch of pitfalls here which all compromise security, which you probably want to avoid.

Actually meant the following book, best read both :wink:

3 Likes

And make sure your symmetric key is generated by a really cryptographically safe random algo

How can I generate such a key?

Does crypto:strong_rand_bytes(32) work well?

2 Likes

If your operating system provides a good entropy source and pool for it. I know for sure it works well on FreeBSD and I would assume it works on Linux too.

There is Secure Coding and Deployment Hardening Guidelines | EEF Security WG
for further Erlang specific reading.

3 Likes