Re: [RFC] Libsodium - Discussion
| From: | Scott Arciszewski | Date: | Sun, 05 Jun 2016 07:46:02 +0000 |
| Subject: | Re: [RFC] Libsodium - Discussion | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-93797@lists.php.net to get a copy of this message | ||
On Sun, Jun 5, 2016 at 2:20 AM, Pierre Joye <pierre.php@gmail.com> wrote:
>
> On Jun 5, 2016 5:15 AM, "Stanislav Malyshev" <smalyshev@gmail.com> wrote:
> >
>
> > The stated goal is "You shouldn't need a Ph.D in Applied Cryptography to
> > build a secure web application." I fully agree with this goal. I however
> > feel that current implementation, while making admirable progress
> > towards this goal, still needs some work to actually achieve it.
>
> I fully agree with you. As much as I think we need something like that, I
> think these are stopping points.
>
> I would very interested to hear from Scott about these questions and the
> low level nature of the APIs make it not as friendly or future proof as it
> could.
>
> Cheers
> Pierre
>
Hi Pierre,
My position on the low level nature of libsodium's APIs is as follows:
That sounds like a call to action for https://wiki.php.net/rfc/php71-crypto
rather than a point of concern for adopting libsodium.
Compare the following two snippets which accomplish the same "goal"
(anonymous public-key encryption).
<?php
/**
* OpenSSL -- since the Diffie Hellman features in ext/openssl kind
* of suck, I'm going to use RSA to encrypt the AES key using the
* recipient's public key.
*/
## ENCRYPTION ##
$message = 'Prime Numbers Rock!';
$publicKey = openssl_pkey_get_public('file://path/to/public_key.pem');
$aesKey = random_bytes(32);
// Basically a poor-man's HKDF by just using HMAC
$keyE = hash_hmac('sha256', 'Encryption Key', $aesKey, true);
$keyA = hash_hmac('sha256', 'Authentication Key', $aesKey, true);
$iv = random_bytes(16);
$ciphertext = openssl_encrypt($message, 'aes-256-ctr', $keyE,
OPENSSL_RAW_DATA, $iv);
$mac = hash_hmac('sha256', $iv . $ciphertext, $keyA, true);
$combined = $mac . $iv . $ciphertext;
$rsaCipher = '';
openssl_public_encrypt($aesKey, $rsaCipher, $publicKey,
OPENSSL_PKCS1_OAEP_PADDING);
$sendMe = $rsaCipher . $combined;
## DECRYPTION ##
$privateKey = openssl_pkey_get_public('file://path/to/private_key.pem');
$rsaPart = mb_substr($sendMe, 0, 256, '8bit'); // Assuming 2048-bit RSA
$aesPart = mb_substr($sendMe, 256, null, '8bit');
$mac = mb_substr($aesPart, 0, 32, '8bit');
$iv = mb_substr($aesPart, 32, 16, '8bit');
$cipher = mb_substr($aesPart, 48, null, '8bit');
openssl_private_decrypt($rsaPart, $aesKey, $privateKey,
OPENSSL_PKCS1_OAEP_PADDING);
$keyE = hash_hmac('sha256', 'Encryption Key', $aesKey, true);
$keyA = hash_hmac('sha256', 'Authentication Key', $aesKey, true);
$calc = hash_hmac('sha256', $iv . $cipher, $keyA, true);
if (!hash_equals($calc, $mac)) {
throw new Exception('MAC validation failure');
}
$decrypted = openssl_decrypt($cipher, 'aes-256-ctr', $keyE,
OPENSSL_RAW_DATA, $iv);
var_dump($decrypted); // string(19) "Prime Numbers Rock!"
Can you count the foot-bullets in that snippet that you'd need to be a
cryptography engineer to successfully avoid?
Demo: https://3v4l.org/nYVPf
Here's a congruent implementation in libsodium:
<?php
/**
* Libsodium
*/
## ENCRYPTION ##
$message = 'Prime Numbers Rock!';
$bob_public_key = "... populate here ...";
$nonce = random_bytes(24);
$sendMe = \Sodium\crypto_box_seal($message, $bob_public_key);
## DECRYPTION ##
$bob_kp = "... populate here ...";
$decrypted = \Sodium\crypto_box_seal_open($sendMe, $bob_kp);
var_dump($decrypted); // string(19) "Prime Numbers Rock!"
(No demo available, as 3v4l doesn't have ext/sodium installed.)
Libsodium already knocks it out of the park compared to OpenSSL and
Mcrypt. If we want to talk about a higher-level abstraction-- such as
what's provided by paragonie/EasyRSA + defuse/php-encryption or
paragonie/halite-- I wholeheartedly endorse that discussion. But I don't
think we should try to solve that problem with this particular RFC.
In closing, I don't disagree that a simple crypto API is a good goal to
have. I just think the ideal you're discussing is:
A. Out of scope, and
B. Kind of belittling to how much of an improvement libsodium is to what we
already have.
Further reading: http://framework.zend.com/security/advisory/ZF2015-10
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com/>