@@ -37,6 +37,19 @@ static zend_class_entry *sodium_exception_ce;
37
37
# define HAVE_AESGCM 1
38
38
#endif
39
39
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
+
40
53
#include "libsodium_arginfo.h"
41
54
42
55
#ifndef crypto_aead_chacha20poly1305_IETF_KEYBYTES
@@ -335,6 +348,13 @@ PHP_MINIT_FUNCTION(sodium)
335
348
crypto_stream_NONCEBYTES , CONST_CS | CONST_PERSISTENT );
336
349
REGISTER_LONG_CONSTANT ("SODIUM_CRYPTO_STREAM_KEYBYTES" ,
337
350
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
338
358
#ifdef sodium_base64_VARIANT_ORIGINAL
339
359
REGISTER_LONG_CONSTANT ("SODIUM_BASE64_VARIANT_ORIGINAL" ,
340
360
sodium_base64_VARIANT_ORIGINAL , CONST_CS | CONST_PERSISTENT );
@@ -1465,6 +1485,87 @@ PHP_FUNCTION(sodium_crypto_stream_xor)
1465
1485
RETURN_NEW_STR (ciphertext );
1466
1486
}
1467
1487
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
+
1468
1569
#ifdef crypto_pwhash_SALTBYTES
1469
1570
PHP_FUNCTION (sodium_crypto_pwhash )
1470
1571
{
@@ -2894,6 +2995,18 @@ PHP_FUNCTION(sodium_crypto_stream_keygen)
2894
2995
randombytes_buf (key , sizeof key );
2895
2996
RETURN_STRINGL ((const char * ) key , sizeof key );
2896
2997
}
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
2897
3010
2898
3011
PHP_FUNCTION (sodium_crypto_kdf_derive_from_key )
2899
3012
{
0 commit comments