@@ -37,6 +37,19 @@ static zend_class_entry *sodium_exception_ce;
3737# define HAVE_AESGCM 1
3838#endif
3939
40+ static zend_always_inline zend_string * zend_string_checked_alloc (size_t len , int persistent )
41+ {
42+ zend_string * zs ;
43+
44+ if (ZEND_MM_ALIGNED_SIZE (_ZSTR_STRUCT_SIZE (len )) < len ) {
45+ zend_error_noreturn (E_ERROR , "Memory allocation too large (%zu bytes)" , len );
46+ }
47+ zs = zend_string_alloc (len , persistent );
48+ ZSTR_VAL (zs )[len ] = 0 ;
49+
50+ return zs ;
51+ }
52+
4053#include "libsodium_arginfo.h"
4154
4255#ifndef crypto_aead_chacha20poly1305_IETF_KEYBYTES
@@ -335,6 +348,13 @@ PHP_MINIT_FUNCTION(sodium)
335348 crypto_stream_NONCEBYTES , CONST_CS | CONST_PERSISTENT );
336349 REGISTER_LONG_CONSTANT ("SODIUM_CRYPTO_STREAM_KEYBYTES" ,
337350 crypto_stream_KEYBYTES , CONST_CS | CONST_PERSISTENT );
351+
352+ #ifdef crypto_stream_xchacha20_KEYBYTES
353+ REGISTER_LONG_CONSTANT ("SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES" ,
354+ crypto_stream_xchacha20_NONCEBYTES , CONST_CS | CONST_PERSISTENT );
355+ REGISTER_LONG_CONSTANT ("SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES" ,
356+ crypto_stream_xchacha20_KEYBYTES , CONST_CS | CONST_PERSISTENT );
357+ #endif
338358#ifdef sodium_base64_VARIANT_ORIGINAL
339359 REGISTER_LONG_CONSTANT ("SODIUM_BASE64_VARIANT_ORIGINAL" ,
340360 sodium_base64_VARIANT_ORIGINAL , CONST_CS | CONST_PERSISTENT );
@@ -1465,6 +1485,87 @@ PHP_FUNCTION(sodium_crypto_stream_xor)
14651485 RETURN_NEW_STR (ciphertext );
14661486}
14671487
1488+ #ifdef crypto_stream_xchacha20_KEYBYTES
1489+ PHP_FUNCTION (sodium_crypto_stream_xchacha20 )
1490+ {
1491+ zend_string * ciphertext ;
1492+ unsigned char * key ;
1493+ unsigned char * nonce ;
1494+ zend_long ciphertext_len ;
1495+ size_t key_len ;
1496+ size_t nonce_len ;
1497+
1498+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "lss" ,
1499+ & ciphertext_len ,
1500+ & nonce , & nonce_len ,
1501+ & key , & key_len ) == FAILURE ) {
1502+ sodium_remove_param_values_from_backtrace (EG (exception ));
1503+ RETURN_THROWS ();
1504+ }
1505+ if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX ) {
1506+ zend_argument_error (sodium_exception_ce , 1 , "length must be greater than 0" );
1507+ RETURN_THROWS ();
1508+ }
1509+ if (nonce_len != crypto_stream_xchacha20_NONCEBYTES ) {
1510+ zend_argument_error (sodium_exception_ce , 2 , "nonce must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long" );
1511+ RETURN_THROWS ();
1512+ }
1513+ if (key_len != crypto_stream_xchacha20_KEYBYTES ) {
1514+ zend_argument_error (sodium_exception_ce , 3 , "key must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long" );
1515+ RETURN_THROWS ();
1516+ }
1517+ ciphertext = zend_string_checked_alloc ((size_t ) ciphertext_len , 0 );
1518+ if (crypto_stream_xchacha20 ((unsigned char * ) ZSTR_VAL (ciphertext ),
1519+ (unsigned long long ) ciphertext_len , nonce , key ) != 0 ) {
1520+ zend_string_free (ciphertext );
1521+ zend_throw_exception (sodium_exception_ce , "internal error" , 0 );
1522+ RETURN_THROWS ();
1523+ }
1524+ ZSTR_VAL (ciphertext )[ciphertext_len ] = 0 ;
1525+
1526+ RETURN_NEW_STR (ciphertext );
1527+ }
1528+
1529+ PHP_FUNCTION (sodium_crypto_stream_xchacha20_xor )
1530+ {
1531+ zend_string * ciphertext ;
1532+ unsigned char * key ;
1533+ unsigned char * msg ;
1534+ unsigned char * nonce ;
1535+ size_t ciphertext_len ;
1536+ size_t key_len ;
1537+ size_t msg_len ;
1538+ size_t nonce_len ;
1539+
1540+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "sss" ,
1541+ & msg , & msg_len ,
1542+ & nonce , & nonce_len ,
1543+ & key , & key_len ) == FAILURE ) {
1544+ sodium_remove_param_values_from_backtrace (EG (exception ));
1545+ RETURN_THROWS ();
1546+ }
1547+ if (nonce_len != crypto_stream_xchacha20_NONCEBYTES ) {
1548+ zend_argument_error (sodium_exception_ce , 2 , "nonce must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long" );
1549+ RETURN_THROWS ();
1550+ }
1551+ if (key_len != crypto_stream_xchacha20_KEYBYTES ) {
1552+ zend_argument_error (sodium_exception_ce , 3 , "key must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long" );
1553+ RETURN_THROWS ();
1554+ }
1555+ ciphertext_len = msg_len ;
1556+ ciphertext = zend_string_checked_alloc ((size_t ) ciphertext_len , 0 );
1557+ if (crypto_stream_xchacha20_xor ((unsigned char * ) ZSTR_VAL (ciphertext ), msg ,
1558+ (unsigned long long ) msg_len , nonce , key ) != 0 ) {
1559+ zend_string_free (ciphertext );
1560+ zend_throw_exception (sodium_exception_ce , "internal error" , 0 );
1561+ RETURN_THROWS ();
1562+ }
1563+ ZSTR_VAL (ciphertext )[ciphertext_len ] = 0 ;
1564+
1565+ RETURN_NEW_STR (ciphertext );
1566+ }
1567+ #endif
1568+
14681569#ifdef crypto_pwhash_SALTBYTES
14691570PHP_FUNCTION (sodium_crypto_pwhash )
14701571{
@@ -2894,6 +2995,18 @@ PHP_FUNCTION(sodium_crypto_stream_keygen)
28942995 randombytes_buf (key , sizeof key );
28952996 RETURN_STRINGL ((const char * ) key , sizeof key );
28962997}
2998+ #ifdef crypto_stream_xchacha20_KEYBYTES
2999+ PHP_FUNCTION (sodium_crypto_stream_xchacha20_keygen )
3000+ {
3001+ unsigned char key [crypto_stream_xchacha20_KEYBYTES ];
3002+
3003+ if (zend_parse_parameters_none () == FAILURE ) {
3004+ return ;
3005+ }
3006+ randombytes_buf (key , sizeof key );
3007+ RETURN_STRINGL ((const char * ) key , sizeof key );
3008+ }
3009+ #endif
28973010
28983011PHP_FUNCTION (sodium_crypto_kdf_derive_from_key )
28993012{
0 commit comments