Skip to content

Commit 489417a

Browse files
committed
Add AES-GCM-SIV AEAD support (RFC 8452)
Extends the AEAD switch in php_openssl_load_cipher_mode() to also recognize EVP_CIPH_GCM_SIV_MODE alongside the SIV/OCB cases added by GH-20853. GCM-SIV (OpenSSL >= 3.2, RFC 8452) uses the standard EVP_CTRL_AEAD_*_TAG controls and falls into the same arm. The existing aad_supports_vector = (cipher_mode == EVP_CIPH_SIV_MODE) check keeps that flag false for GCM-SIV, since RFC 8452 takes a single AAD input rather than vector AAD like RFC 5297 SIV. LibreSSL does not currently define EVP_CIPH_GCM_SIV_MODE, hence the #ifdef guard. Tests: - cipher_tests.inc gains aes-256-gcm-siv vectors from RFC 8452 Appendix C.2 (empty plaintext, 8-byte plaintext with and without AAD). - openssl_encrypt_gcm_siv.phpt and openssl_decrypt_gcm_siv.phpt consume those vectors, mirroring the SIV equivalents, and cover the missing-tag and tampering failure paths.
1 parent bd78496 commit 489417a

5 files changed

Lines changed: 138 additions & 0 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ PHP NEWS
9393

9494
- OpenSSL:
9595
. Added AES-SIV support. (jordikroon)
96+
. Added AES-GCM-SIV support. (Rakdos8)
9697
. Implemented GH-20310 (No critical extension indication in
9798
openssl_x509_parse() output). (StephenWall)
9899

ext/openssl/openssl_backend_common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,9 @@ void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EV
16581658
#ifdef EVP_CIPH_SIV_MODE
16591659
case EVP_CIPH_SIV_MODE:
16601660
#endif
1661+
#ifdef EVP_CIPH_GCM_SIV_MODE
1662+
case EVP_CIPH_GCM_SIV_MODE:
1663+
#endif
16611664
#ifdef EVP_CIPH_OCB_MODE
16621665
case EVP_CIPH_OCB_MODE:
16631666
/* For OCB mode, explicitly set the tag length even when decrypting,

ext/openssl/tests/cipher_tests.inc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,33 @@ $php_openssl_cipher_tests = array(
213213
'21ad626dc866cc539f2d0e34b6824fc3',
214214
),
215215
),
216+
/* RFC 8452 Appendix C.2 vectors for AES-256-GCM-SIV. */
217+
'aes-256-gcm-siv' => array(
218+
array(
219+
'key' => '0100000000000000000000000000000000000000000000000000000000000000',
220+
'iv' => '030000000000000000000000',
221+
'aad' => '',
222+
'tag' => '07f5f4169bbf55a8400cd47ea6fd400f',
223+
'pt' => '',
224+
'ct' => '',
225+
),
226+
array(
227+
'key' => '0100000000000000000000000000000000000000000000000000000000000000',
228+
'iv' => '030000000000000000000000',
229+
'aad' => '',
230+
'tag' => '843122130f7364b761e0b97427e3df28',
231+
'pt' => '0100000000000000',
232+
'ct' => 'c2ef328e5c71c83b',
233+
),
234+
array(
235+
'key' => '0100000000000000000000000000000000000000000000000000000000000000',
236+
'iv' => '030000000000000000000000',
237+
'aad' => '01',
238+
'tag' => '91213f267e3b452f02d01ae33e4ec854',
239+
'pt' => '0200000000000000',
240+
'ct' => '1de22967237a8132',
241+
),
242+
),
216243
'chacha20-poly1305' => array(
217244
array(
218245
'key' => '808182838485868788898a8b8c8d8e8f' .
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
openssl_decrypt() with GCM-SIV cipher algorithm tests
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (!in_array('aes-256-gcm-siv', openssl_get_cipher_methods())) {
8+
die("skip aes-256-gcm-siv not available (requires OpenSSL >= 3.2)");
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
require_once __DIR__ . "/cipher_tests.inc";
14+
$method = 'aes-256-gcm-siv';
15+
$tests = openssl_get_cipher_tests($method);
16+
17+
foreach ($tests as $idx => $test) {
18+
echo "TEST $idx\n";
19+
$pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA,
20+
$test['iv'], $test['tag'], $test['aad']);
21+
var_dump($test['pt'] === $pt);
22+
}
23+
24+
// Use the last vector (non-empty pt + AAD) for tampering checks.
25+
echo "TEST WRONGTAG\n";
26+
$bad_tag = $test['tag'];
27+
$bad_tag[0] = chr(ord($bad_tag[0]) ^ 0x01);
28+
var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA,
29+
$test['iv'], $bad_tag, $test['aad']));
30+
31+
echo "TEST WRONGCT\n";
32+
$bad_ct = $test['ct'];
33+
$bad_ct[0] = chr(ord($bad_ct[0]) ^ 0x01);
34+
var_dump(openssl_decrypt($bad_ct, $method, $test['key'], OPENSSL_RAW_DATA,
35+
$test['iv'], $test['tag'], $test['aad']));
36+
37+
echo "TEST WRONGNONCE\n";
38+
$bad_iv = $test['iv'];
39+
$bad_iv[0] = chr(ord($bad_iv[0]) ^ 0x01);
40+
var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA,
41+
$bad_iv, $test['tag'], $test['aad']));
42+
43+
echo "TEST WRONGAAD\n";
44+
var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA,
45+
$test['iv'], $test['tag'], 'unexpected aad'));
46+
?>
47+
--EXPECT--
48+
TEST 0
49+
bool(true)
50+
TEST 1
51+
bool(true)
52+
TEST 2
53+
bool(true)
54+
TEST WRONGTAG
55+
bool(false)
56+
TEST WRONGCT
57+
bool(false)
58+
TEST WRONGNONCE
59+
bool(false)
60+
TEST WRONGAAD
61+
bool(false)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
openssl_encrypt() with GCM-SIV cipher algorithm tests
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (!in_array('aes-256-gcm-siv', openssl_get_cipher_methods())) {
8+
die("skip aes-256-gcm-siv not available (requires OpenSSL >= 3.2)");
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
require_once __DIR__ . "/cipher_tests.inc";
14+
$method = 'aes-256-gcm-siv';
15+
$tests = openssl_get_cipher_tests($method);
16+
17+
foreach ($tests as $idx => $test) {
18+
echo "TEST $idx\n";
19+
$ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA,
20+
$test['iv'], $tag, $test['aad'], strlen($test['tag']));
21+
var_dump($test['ct'] === $ct);
22+
var_dump($test['tag'] === $tag);
23+
}
24+
25+
// Failing to retrieve tag (max is 16 bytes)
26+
var_dump(openssl_encrypt('data', $method, str_repeat('x', 32), 0, str_repeat('x', 12), $tag, '', 20));
27+
28+
// Failing when no tag supplied
29+
var_dump(openssl_encrypt('data', $method, str_repeat('x', 32), 0, str_repeat('x', 12)));
30+
?>
31+
--EXPECTF--
32+
TEST 0
33+
bool(true)
34+
bool(true)
35+
TEST 1
36+
bool(true)
37+
bool(true)
38+
TEST 2
39+
bool(true)
40+
bool(true)
41+
42+
Warning: openssl_encrypt(): Retrieving verification tag failed in %s on line %d
43+
bool(false)
44+
45+
Warning: openssl_encrypt(): A tag should be provided when using AEAD mode in %s on line %d
46+
bool(false)

0 commit comments

Comments
 (0)