3

openssl_public_encrypt apparently can't handle arbitrary plaintexts.

<?php

$msg = '{"args":["argxx","argyy"],"data":"xx\nyyy\n","symkey":"0a6e860640413acfe6e4e461a28fab3fad3aff78ef95c962c5e63bef7e2b3439"}';

# If you uncomment this line, the function succeeds.
# $msg = 'test';

$pub = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC80g7AA5XexMCiJW3tKr/eeN8Q
EMNfGYG0qiUuLS/dtir7c3c1MmpNzrE8R+xqleOLNVkbbSZqqQ2qUJtPhwbLhQyL
yilRH5WMz9Pabx62v7k+vm81/6Xa9fnIV7DE0DZhMO5vQvBE3+5jkXbfU4yBZRv5
UOty5gqGXXaR6bim4QIDAQAB
-----END PUBLIC KEY-----';


if (openssl_public_encrypt ($msg, $enc, $pub))
{
    print bin2hex ($enc);

    exit (0);
}
else
{
    print "Could not encrypt message.\n";
}
?>

This outputs Could not encrypt message. on Ubuntu PHP 7.

Why is it failing on this $msg?

jww
  • 97,681
  • 90
  • 411
  • 885
spraff
  • 32,570
  • 22
  • 121
  • 229
  • It also fails on 5.6. Relevant comment: http://php.net/manual/en/function.openssl-public-encrypt.php#95307 – scrowler Nov 21 '16 at 00:02
  • Are you sure it's the `$msg`? This works with other messages? – ChrisGPT was on strike Nov 21 '16 at 00:54
  • Is the message longer than the RSA key? – zaph Nov 21 '16 at 01:24
  • 1
    Because the length of the message cannot be bigger than (size_t)INT_MAX: https://github.com/php/php-src/blob/b98357823a816a55097fc7f6f833db88722efeea/ext/openssl/openssl.c#L5499 https://github.com/php/php-src/blob/master/Zend/zend_range_check.h#L54 – Axalix Nov 21 '16 at 04:52

2 Answers2

2

If we test this situation empirically, we will see, that everything longer than 117 bytes will fail:

$msg = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm';

The line above represents 117 characters and 117 bytes in total. This works when encrypting with the public key you provided.

If I add another character, n, encryption fails:

$msg = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn';

Same thing goes with other unicode characters. Let's say I try to encrypt this, which is 85 characters long, but exactly 117 bytes in length:

$msg = ' i ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui  u';

This gets encrypted perfectly. But if I add another byte, it fails (86 characters, 118 bytes):

$msg = ' i ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui ♥ ui  uZ';

.. the openssl_public_encrypt() function will fail by design if you pass it more than 117 characters to encrypt.

Snyder, Chris, Myer, Thomas, Southwell, Michael, ISBN 978-1-4302-3318-3

Further, in the book it says:

Because RSA is expensive, and was never intended for encrypting quantities of data, if you are encrypting something that is routinely longer than 56 characters, you should be planning to encrypt your data using a fast and efficient symmetric algorithm like AES with a randomly generated key.

Kevin Kopf
  • 13,327
  • 14
  • 49
  • 66
  • Just a small addition: https://books.google.ca/books?id=lVXnmsCCd3wC&pg=PA87&lpg=PA87&dq=%22-+Because+RSA+is+expensive,+and+was+never+intended+for+encrypting+quantities+of+data%22&source=bl&ots=yAXeceGeMY&sig=c17Tpfx63l3yLW4DjZDnp0cleEg&hl=en&sa=X&ved=0ahUKEwjNlO3Fi7nQAhVC5YMKHa8qDMgQ6AEIHTAA#v=onepage&q=%22-%20Because%20RSA%20is%20expensive%2C%20and%20was%20never%20intended%20for%20encrypting%20quantities%20of%20data%22&f=false – Axalix Nov 21 '16 at 05:17
  • 1
    The choice of using the excerpt from PHP is really poor, it is too old and has not been updated: RC4 is completely insecure, should, it, not be used and TripleDES should not be used in new work. The current symmetric encryption of choice is AES (Advanced Encryption Standard). Further the answer does not address *why* the message length is limited to 117 bytes. – zaph Nov 21 '16 at 12:15
  • @zaph you are correct, I completely ignored this fact. So I removed the comment reference and added something else. – Kevin Kopf Nov 21 '16 at 15:20
  • @zaph I don't know why it's exactly 117 in PHP, but the idea of limit comes from here: http://crypto.stackexchange.com/a/15184 https://linux.die.net/man/3/rsa_public_encrypt http://info.townsendsecurity.com/bid/29195/how-much-data-can-you-encrypt-with-rsa-keys – Axalix Nov 21 '16 at 16:00
  • 1
    @Axalix See the naswer I added. This answser is just a few emperical tests to determine the data length, not why. – zaph Nov 21 '16 at 18:40
  • @Nordenheim as far as I can tell the 56 charactor number is from long ago when 512-byte RSA keys were commonaly used and is not really valid. The real answer is if the data does not fit due to the required key size and then one moves to hybrid encryption. Please find current sources of information – zaph Nov 21 '16 at 21:10
  • The quote from "Snyder, Chris, Myer, Thomas, Southwell, Michael" is only applicable to 1024-bit keys, less fr smaller keys, more for longer keys. – zaph Nov 21 '16 at 21:13
  • @zaph unfortunately, I can't delete the accepted answer – Kevin Kopf Nov 21 '16 at 21:58
2

The actual key is 128-bytes (1024-bits), this is a common minimally accepted key size. 128 - 11 padding bytes = 117 allowable bytes of data to be encrypted.

The public key in the question is encoded and has additional header and footer lines and thus longer than 128-bytes.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • Thanks, but what is this magic "11" and where does it come from? – Axalix Nov 22 '16 at 01:09
  • Thew 11 bytes are padding, the most common padding scheme ([PKCS#1](https://en.wikipedia.org/wiki/PKCS_1)), the padding adds at least 11 bytes to the message. See [Why is padding used for RSA encryption](http://crypto.stackexchange.com/a/3609/4747). Excerpt: * With RSA the padding is essential for its core function. RSA has a lot of mathematical structure, which leads to weaknesses. Using correct padding prevents those weaknesses.* – zaph Nov 22 '16 at 01:29