Astute readers have noticed that our blog posts have decreased in frequency this year. We put a heavy emphasis on quality, not so much on quantity. At the same time, we field a *lot* of questions on social media, where our answers (and, sometimes, the questions themselves) are difficult to locate, especially when people close or lock their accounts. With both of these thoughts in mind, I asked my Twitter followers [if they'd be interested in a Q&A-style blog series](https://twitter.com/CiPHPerCoder/status/1033756295503986689). I expected maybe a 55:45 split on yes/no responses, but the final tally was overwhelmingly "Yes". So with that in mind, I'd like to introduce the pilot for our new series, *Slice of PIE*.

Logo: Slice of PIE

### What Is This All About? Every so often, we'll collate all of the questions we've received from our readers since the last edition, and answer them. In most cases, our answer will be longer and more in-depth than a tweet. Only questions that were clearly marked for inclusion in our series will be included. In the future, we *may* experiment with video responses to some questions, in which case, there will always be a full-text transcript (complete with graphical aids) to accompany each video, and we will ***never* enable autoplay**. ### How to Send in Questions for *Slice of PIE*? * Send an email to `sliceofpie@paragonie.com` with your questions. * Tweet/DM your questions to [@ParagonIE](https://twitter.com/ParagonIE) with the hashtag, `#SliceOfPIE`. Emails and tweets sent to other email addresses and/or without the hashtag will not, by default, be considered for inclusion in this series. ### What sort of questions will you answer? As this is a new idea, we don't have a formal policy written just yet. If you'd like us to answer a question, and your question isn't something that would generally be considered inappropriate in a professional setting, feel free to ask it. If you're not sure about the appropriateness of a question, ask in an email or Twitter DM and tell us up front that you're unsure if it'd be appropriate, and we'll let you know. No judgment, we just want to keep our blog appropriate for all ages as well as respect our clients' confidentiality. ## Inaugural Slice of PIE Question Originally this was going to just be an announcement, but a really good question came in as I was writing the first draft. What better way to kick off a Q&A series than by answering an actual reader's question?

Asymmetric Encryption

Received via [Twitter](https://twitter.com/Devmazee/status/1041429070368522240): > [@CiPHPerCoder](https://twitter.com/CiPHPerCoder) In one of your blog posts you said that RSA shouldn't be used unless it was a hybrid. What would you recommend for asymmetric encryption then? This can be broken into two distinct (albeit related) questions: * Why is hybrid encryption better than direct asymmetric encryption? * What algorithms should developers use? #### Why is hybrid encryption better than direct asymmetric encryption? You can't use RSA to directly encrypt large messages.
<?php

/* Don't actually use this code! It's to demonstrate a concept. */

$public_key = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyaTgTt53ph3p
5GHgwoGWwz5hRfWXSQA08NCOwe0FEgALWos9GCjNFCd723nCHxBtN1qd
74MSh/uN88JPIbwxKheDp4kxo4YMN5trPaF0e9G6Bj1N02HnanxFLW+g
mLbgYO/SZYfWF/M8yLBcu5Y1Ot0ZxDDDXS9wIQTtBE0ne3YbxgZJAZTU
5XqyQ1DxdzYyC5lF6yBaR5UQtCYTnXAApVRuUI2Sd6L1E2vl9bSBumZ5
IpNxkRnAwIMjeTJB/0AIELh0mE5vwdihOCbdV6alUyhKC1+1w/FW6HWc
p/JG1kKC8DPIidZ78Bbqv9YFzkAbNni5eSBOsXVBKG78Zsc8owIDAQAB
-----END PUBLIC KEY-----';

// The letter "A" repeated 246 times:
$msg = str_repeat('A', 246);

// Encrypt
$ciphertext = '';
$encrypted = openssl_public_encrypt($msg, $ciphertext, $public_key); // Note: Insecure padding mode by default
var_dump(bin2hex($ciphertext));
The above script fails. It will print out `string(0) ""` to your console. Now change the `246` to an integer between 1 and 245, and you'll be greeted with a string of 512 hex characters. Some libraries work around this limitation by breaking the input message into distinct blocks and encrypting them separately, similar to [ECB mode](https://blog.filippo.io/the-ecb-penguin). Not only is this *very slow*, it's also dangerous. Since each block is encrypted separately, you can simply reorder ciphertext blocks and the changes will be reflected in the decrypted plaintext. That's the danger of directly encrypting messages with RSA. There are other asymmetric cryptography algorithms that have their own security considerations, but generally, you want a hybrid cryptosystem. **Hybrid encryption** involves encrypting each message with symmetric cryptography (e.g. AES-GCM), then encrypting the key asymmetric cryptography (rather than encrypting the message). Since most symmetric encryption algorithms call for, at most, 256-bit keys (which is 32 bytes, far below the maximum 245 byte message that 2048-bit RSA allows), this tends to work out better for security *and* performance. See, for example, [Zend\Crypt's Hybrid encryption documentation](https://github.com/zendframework/zend-crypt/blob/d67dd451489583966bd606b321fdf43ebddcb580/docs/book/hybrid.md). #### What algorithms should developers use? Avoid RSA, [unless you absolutely must support it](https://paragonie.com/blog/2018/04/protecting-rsa-based-protocols-against-adaptive-chosen-ciphertext-attacks). Our general recommendation is to use [libsodium's crypto_box_seal API](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use#crypto-box-seal). You don't even need to know what libsodium does here in order to use it safely. That's the entire point of libsodium. But for the sake of completeness, the crypto_box_seal algorithm looks roughly like this: 1. Generate a random X25519 secret key and its associated public key. 2. Hash the public key from step 1 with the recipient's public key, using BLAKE2b, to get the nonce. 3. Perform an Elliptic Curve Diffie-Hellman key exchange between the random secret key and the recipient's public key. 4. Encrypt the message with XSalsa20-Poly1305 using the HSalsa20 hash of the ECDH output in step 3 as the message key, and the nonce from step 2. 5. Prepend the public key from step 1 to the ciphertext output from step 4. If it helps, also look at [how `sodium_crypto_box_seal()` is implemented in sodium_compat](https://github.com/paragonie/sodium_compat/blob/aaaf71f3f7713248703c23cfbd1189ce1215f57f/src/Crypto.php#L438-L482).