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"...>>,

The version of Erlang/OTP is Please help me.


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.


max-au gave complete explanation of the problem.

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


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)


I haven’t even thought about it =(


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.


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: 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:


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?


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.