diff --git a/NEWS b/NEWS index 5be5ffd18ac4..48e3b1df07fb 100644 --- a/NEWS +++ b/NEWS @@ -93,6 +93,7 @@ PHP NEWS - OpenSSL: . Added AES-SIV support. (jordikroon) + . Added AES-GCM-SIV support. (Rakdos8) . Implemented GH-20310 (No critical extension indication in openssl_x509_parse() output). (StephenWall) diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 99193615bec2..d75a085cbe8f 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -1658,6 +1658,9 @@ void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EV #ifdef EVP_CIPH_SIV_MODE case EVP_CIPH_SIV_MODE: #endif +#ifdef EVP_CIPH_GCM_SIV_MODE + case EVP_CIPH_GCM_SIV_MODE: +#endif #ifdef EVP_CIPH_OCB_MODE case EVP_CIPH_OCB_MODE: /* For OCB mode, explicitly set the tag length even when decrypting, diff --git a/ext/openssl/tests/cipher_tests.inc b/ext/openssl/tests/cipher_tests.inc index 9d17e847bfa2..ffc57ad21556 100644 --- a/ext/openssl/tests/cipher_tests.inc +++ b/ext/openssl/tests/cipher_tests.inc @@ -213,6 +213,33 @@ $php_openssl_cipher_tests = array( '21ad626dc866cc539f2d0e34b6824fc3', ), ), + /* RFC 8452 Appendix C.2 vectors for AES-256-GCM-SIV. */ + 'aes-256-gcm-siv' => array( + array( + 'key' => '0100000000000000000000000000000000000000000000000000000000000000', + 'iv' => '030000000000000000000000', + 'aad' => '', + 'tag' => '07f5f4169bbf55a8400cd47ea6fd400f', + 'pt' => '', + 'ct' => '', + ), + array( + 'key' => '0100000000000000000000000000000000000000000000000000000000000000', + 'iv' => '030000000000000000000000', + 'aad' => '', + 'tag' => '843122130f7364b761e0b97427e3df28', + 'pt' => '0100000000000000', + 'ct' => 'c2ef328e5c71c83b', + ), + array( + 'key' => '0100000000000000000000000000000000000000000000000000000000000000', + 'iv' => '030000000000000000000000', + 'aad' => '01', + 'tag' => '91213f267e3b452f02d01ae33e4ec854', + 'pt' => '0200000000000000', + 'ct' => '1de22967237a8132', + ), + ), 'chacha20-poly1305' => array( array( 'key' => '808182838485868788898a8b8c8d8e8f' . diff --git a/ext/openssl/tests/openssl_decrypt_gcm_siv.phpt b/ext/openssl/tests/openssl_decrypt_gcm_siv.phpt new file mode 100644 index 000000000000..cb1e9b7fcf66 --- /dev/null +++ b/ext/openssl/tests/openssl_decrypt_gcm_siv.phpt @@ -0,0 +1,61 @@ +--TEST-- +openssl_decrypt() with GCM-SIV cipher algorithm tests +--EXTENSIONS-- +openssl +--SKIPIF-- += 3.2)"); +} +?> +--FILE-- + $test) { + echo "TEST $idx\n"; + $pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'], $test['aad']); + var_dump($test['pt'] === $pt); +} + +// Use the last vector (non-empty pt + AAD) for tampering checks. +echo "TEST WRONGTAG\n"; +$bad_tag = $test['tag']; +$bad_tag[0] = chr(ord($bad_tag[0]) ^ 0x01); +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $bad_tag, $test['aad'])); + +echo "TEST WRONGCT\n"; +$bad_ct = $test['ct']; +$bad_ct[0] = chr(ord($bad_ct[0]) ^ 0x01); +var_dump(openssl_decrypt($bad_ct, $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'], $test['aad'])); + +echo "TEST WRONGNONCE\n"; +$bad_iv = $test['iv']; +$bad_iv[0] = chr(ord($bad_iv[0]) ^ 0x01); +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $bad_iv, $test['tag'], $test['aad'])); + +echo "TEST WRONGAAD\n"; +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'], 'unexpected aad')); +?> +--EXPECT-- +TEST 0 +bool(true) +TEST 1 +bool(true) +TEST 2 +bool(true) +TEST WRONGTAG +bool(false) +TEST WRONGCT +bool(false) +TEST WRONGNONCE +bool(false) +TEST WRONGAAD +bool(false) diff --git a/ext/openssl/tests/openssl_encrypt_gcm_siv.phpt b/ext/openssl/tests/openssl_encrypt_gcm_siv.phpt new file mode 100644 index 000000000000..bf34103907ee --- /dev/null +++ b/ext/openssl/tests/openssl_encrypt_gcm_siv.phpt @@ -0,0 +1,46 @@ +--TEST-- +openssl_encrypt() with GCM-SIV cipher algorithm tests +--EXTENSIONS-- +openssl +--SKIPIF-- += 3.2)"); +} +?> +--FILE-- + $test) { + echo "TEST $idx\n"; + $ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $tag, $test['aad'], strlen($test['tag'])); + var_dump($test['ct'] === $ct); + var_dump($test['tag'] === $tag); +} + +// Failing to retrieve tag (max is 16 bytes) +var_dump(openssl_encrypt('data', $method, str_repeat('x', 32), 0, str_repeat('x', 12), $tag, '', 20)); + +// Failing when no tag supplied +var_dump(openssl_encrypt('data', $method, str_repeat('x', 32), 0, str_repeat('x', 12))); +?> +--EXPECTF-- +TEST 0 +bool(true) +bool(true) +TEST 1 +bool(true) +bool(true) +TEST 2 +bool(true) +bool(true) + +Warning: openssl_encrypt(): Retrieving verification tag failed in %s on line %d +bool(false) + +Warning: openssl_encrypt(): A tag should be provided when using AEAD mode in %s on line %d +bool(false)