Skip to content

Commit 1407968

Browse files
committed
Implement FR #76935: OpenSSL chacha20-poly1305 AEAD support
This adds support for ChaCha20-Poly1305 AEAD algorithm so it is possible to use it in the same way as AES GCM and other AEAD algorithms. This is available in OpenSSL 1.1.0+.
1 parent 505e8d2 commit 1407968

File tree

4 files changed

+138
-7
lines changed

4 files changed

+138
-7
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ PHP NEWS
1717
- OpenSSL:
1818
. Fixed bug GH-9310 (SSL local_cert and local_pk do not respect
1919
open_basedir). (Jakub Zelenka)
20+
. Implement FR #76935 ("chacha20-poly1305" is an AEAD but does not work like
21+
AEAD). (Jakub Zelenka)
2022

2123
- Random:
2224
. Fixed bug GH-9415 (Randomizer::getInt(0, 2**32 - 1) with Mt19937

ext/openssl/openssl.c

+22-7
Original file line numberDiff line numberDiff line change
@@ -7145,27 +7145,43 @@ struct php_openssl_cipher_mode {
71457145
int aead_ivlen_flag;
71467146
};
71477147

7148-
static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */
7148+
#if PHP_OPENSSL_API_VERSION >= 0x10100
7149+
static inline void php_openssl_set_aead_flags(struct php_openssl_cipher_mode *mode) {
7150+
mode->is_aead = true;
7151+
mode->aead_get_tag_flag = EVP_CTRL_AEAD_GET_TAG;
7152+
mode->aead_set_tag_flag = EVP_CTRL_AEAD_SET_TAG;
7153+
mode->aead_ivlen_flag = EVP_CTRL_AEAD_SET_IVLEN;
7154+
}
7155+
#endif
7156+
7157+
static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type)
71497158
{
71507159
int cipher_mode = EVP_CIPHER_mode(cipher_type);
71517160
memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
71527161
switch (cipher_mode) {
7153-
#ifdef EVP_CIPH_OCB_MODE
7162+
#if PHP_OPENSSL_API_VERSION >= 0x10100
71547163
/* Since OpenSSL 1.1, all AEAD ciphers use a common framework. We check for
71557164
* EVP_CIPH_OCB_MODE, because LibreSSL does not support it. */
71567165
case EVP_CIPH_GCM_MODE:
7166+
# ifdef EVP_CIPH_OCB_MODE
71577167
case EVP_CIPH_OCB_MODE:
7168+
# endif
71587169
case EVP_CIPH_CCM_MODE:
7159-
mode->is_aead = 1;
7170+
php_openssl_set_aead_flags(mode);
71607171
/* For OCB mode, explicitly set the tag length even when decrypting,
71617172
* see https://github.com/openssl/openssl/issues/8331. */
71627173
mode->set_tag_length_always = cipher_mode == EVP_CIPH_OCB_MODE;
71637174
mode->set_tag_length_when_encrypting = cipher_mode == EVP_CIPH_CCM_MODE;
71647175
mode->is_single_run_aead = cipher_mode == EVP_CIPH_CCM_MODE;
7165-
mode->aead_get_tag_flag = EVP_CTRL_AEAD_GET_TAG;
7166-
mode->aead_set_tag_flag = EVP_CTRL_AEAD_SET_TAG;
7167-
mode->aead_ivlen_flag = EVP_CTRL_AEAD_SET_IVLEN;
71687176
break;
7177+
# ifdef NID_chacha20_poly1305
7178+
default:
7179+
if (EVP_CIPHER_nid(cipher_type) == NID_chacha20_poly1305) {
7180+
php_openssl_set_aead_flags(mode);
7181+
}
7182+
break;
7183+
7184+
# endif
71697185
#else
71707186
# ifdef EVP_CIPH_GCM_MODE
71717187
case EVP_CIPH_GCM_MODE:
@@ -7188,7 +7204,6 @@ static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, c
71887204
#endif
71897205
}
71907206
}
7191-
/* }}} */
71927207

71937208
static int php_openssl_validate_iv(const char **piv, size_t *piv_len, size_t iv_required_len,
71947209
bool *free_iv, EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode) /* {{{ */

ext/openssl/tests/cipher_tests.inc

+66
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,72 @@ $php_openssl_cipher_tests = array(
160160
'ct' => '1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6A',
161161
),
162162
),
163+
'chacha20-poly1305' => array(
164+
array(
165+
'key' => '808182838485868788898a8b8c8d8e8f' .
166+
'909192939495969798999a9b9c9d9e9f',
167+
'iv' => '070000004041424344454647',
168+
'aad' => '50515253c0c1c2c3c4c5c6c7',
169+
'tag' => '1ae10b594f09e26a7e902ecbd0600691',
170+
'pt' => '4c616469657320616e642047656e746c' .
171+
'656d656e206f662074686520636c6173' .
172+
'73206f66202739393a20496620492063' .
173+
'6f756c64206f6666657220796f75206f' .
174+
'6e6c79206f6e652074697020666f7220' .
175+
'746865206675747572652c2073756e73' .
176+
'637265656e20776f756c642062652069' .
177+
'742e',
178+
'ct' => 'd31a8d34648e60db7b86afbc53ef7ec2' .
179+
'a4aded51296e08fea9e2b5a736ee62d6' .
180+
'3dbea45e8ca9671282fafb69da92728b' .
181+
'1a71de0a9e060b2905d6a5b67ecd3b36' .
182+
'92ddbd7f2d778b8c9803aee328091b58' .
183+
'fab324e4fad675945585808b4831d7bc' .
184+
'3ff4def08e4b7a9de576d26586cec64b' .
185+
'6116',
186+
),
187+
array(
188+
'key' => '1c9240a5eb55d38af333888604f6b5f0' .
189+
'473917c1402b80099dca5cbc207075c0',
190+
'iv' => '000000000102030405060708',
191+
'aad' => 'f33388860000000000004e91',
192+
'tag' => 'eead9d67890cbb22392336fea1851f38',
193+
'pt' => '496e7465726e65742d44726166747320' .
194+
'61726520647261667420646f63756d65' .
195+
'6e74732076616c696420666f72206120' .
196+
'6d6178696d756d206f6620736978206d' .
197+
'6f6e74687320616e64206d6179206265' .
198+
'20757064617465642c207265706c6163' .
199+
'65642c206f72206f62736f6c65746564' .
200+
'206279206f7468657220646f63756d65' .
201+
'6e747320617420616e792074696d652e' .
202+
'20497420697320696e617070726f7072' .
203+
'6961746520746f2075736520496e7465' .
204+
'726e65742d4472616674732061732072' .
205+
'65666572656e6365206d617465726961' .
206+
'6c206f7220746f206369746520746865' .
207+
'6d206f74686572207468616e20617320' .
208+
'2fe2809c776f726b20696e2070726f67' .
209+
'726573732e2fe2809d',
210+
'ct' => '64a0861575861af460f062c79be643bd' .
211+
'5e805cfd345cf389f108670ac76c8cb2' .
212+
'4c6cfc18755d43eea09ee94e382d26b0' .
213+
'bdb7b73c321b0100d4f03b7f355894cf' .
214+
'332f830e710b97ce98c8a84abd0b9481' .
215+
'14ad176e008d33bd60f982b1ff37c855' .
216+
'9797a06ef4f0ef61c186324e2b350638' .
217+
'3606907b6a7c02b0f9f6157b53c867e4' .
218+
'b9166c767b804d46a59b5216cde7a4e9' .
219+
'9040c5a40433225ee282a1b0a06c523e' .
220+
'af4534d7f83fa1155b0047718cbc546a' .
221+
'0d072b04b3564eea1b422273f548271a' .
222+
'0bb2316053fa76991955ebd63159434e' .
223+
'cebb4e466dae5a1073a6727627097a10' .
224+
'49e617d91d361094fa68f0ff77987130' .
225+
'305beaba2eda04df997b714d6c6f2c29' .
226+
'a6ad5cb4022b02709b',
227+
),
228+
),
163229
);
164230

165231
function openssl_get_cipher_tests($method)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
openssl_encrypt() with ChaCha20 and Poly1305 cipher algorithm tests
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (!in_array('chacha20-poly1305', openssl_get_cipher_methods()))
8+
die("skip: chacha20-poly1305 not available");
9+
?>
10+
--FILE--
11+
<?php
12+
require_once __DIR__ . "/cipher_tests.inc";
13+
$method = 'chacha20-poly1305';
14+
$tests = openssl_get_cipher_tests($method);
15+
16+
foreach ($tests as $idx => $test) {
17+
echo "TEST $idx\n";
18+
$ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA,
19+
$test['iv'], $tag, $test['aad'], strlen($test['tag']));
20+
var_dump($test['ct'] === $ct);
21+
var_dump($test['tag'] === $tag);
22+
}
23+
24+
// Empty IV error
25+
var_dump(openssl_encrypt('data', $method, 'password', 0, '', $tag, ''));
26+
27+
// Failing to retrieve tag (max is 16 bytes)
28+
var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 12), $tag, '', 20));
29+
30+
// Failing when no tag supplied
31+
var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 12)));
32+
?>
33+
--EXPECTF--
34+
TEST 0
35+
bool(true)
36+
bool(true)
37+
TEST 1
38+
bool(true)
39+
bool(true)
40+
41+
Warning: openssl_encrypt(): Setting of IV length for AEAD mode failed in %s on line %d
42+
bool(false)
43+
44+
Warning: openssl_encrypt(): Retrieving verification tag failed in %s on line %d
45+
bool(false)
46+
47+
Warning: openssl_encrypt(): A tag should be provided when using AEAD mode in %s on line %d
48+
bool(false)

0 commit comments

Comments
 (0)