/* +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Frank Denis | +----------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_libsodium.h" #include "zend_exceptions.h" #include #include #include #define PHP_SODIUM_ZSTR_TRUNCATE(zs, len) do { ZSTR_LEN(zs) = (len); } while(0) static zend_class_entry *sodium_exception_ce; ZEND_BEGIN_ARG_INFO_EX(AI_None, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_FirstArgByReference, 0, 0, 1) ZEND_ARG_INFO(1, reference) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_String, 0, 0, 1) ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringRef, 0, 0, 1) ZEND_ARG_INFO(1, string) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_TwoStrings, 0, 0, 2) ZEND_ARG_INFO(0, string_1) ZEND_ARG_INFO(0, string_2) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndMaybeString, 0, 0, 1) ZEND_ARG_INFO(0, string_1) /* optional */ ZEND_ARG_INFO(0, string_2) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndIdAndMaybeString, 0, 0, 2) ZEND_ARG_INFO(0, string_1) ZEND_ARG_INFO(0, id) /* optional */ ZEND_ARG_INFO(0, string_2) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringRefAndString, 0, 0, 2) ZEND_ARG_INFO(1, string_1) ZEND_ARG_INFO(0, string_2) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndKey, 0, 0, 2) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndLength, 0, 0, 2) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndId, 0, 0, 2) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, id) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndKeyPair, 0, 0, 2) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, keypair) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_SignatureAndStringAndKey, 0, 0, 3) ZEND_ARG_INFO(0, signature) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_Key, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_SecretKeyAndPublicKey, 0, 0, 2) ZEND_ARG_INFO(0, secret_key) ZEND_ARG_INFO(0, public_key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_LengthAndNonceAndKey, 0, 0, 3) ZEND_ARG_INFO(0, length) ZEND_ARG_INFO(0, nonce) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndNonceAndKey, 0, 0, 3) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, nonce) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndNonceAndKeyPair, 0, 0, 3) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, nonce) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndMaybeKeyAndLength, 0, 0, 1) ZEND_ARG_INFO(0, string) /* optional */ ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_LengthAndPasswordAndSaltAndOpsLimitAndMemLimit, 0, 0, 5) ZEND_ARG_INFO(0, length) ZEND_ARG_INFO(0, password) ZEND_ARG_INFO(0, salt) ZEND_ARG_INFO(0, opslimit) ZEND_ARG_INFO(0, memlimit) /* optional */ ZEND_ARG_INFO(0, alg) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_PasswordAndOpsLimitAndMemLimit, 0, 0, 3) ZEND_ARG_INFO(0, password) ZEND_ARG_INFO(0, opslimit) ZEND_ARG_INFO(0, memlimit) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_HashAndPassword, 0, 0, 2) ZEND_ARG_INFO(0, hash) ZEND_ARG_INFO(0, password) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StringAndADAndNonceAndKey, 0, 0, 4) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, ad) ZEND_ARG_INFO(0, nonce) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StateByReference, 0, 0, 1) ZEND_ARG_INFO(1, state) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StateByReferenceAndStringAndMaybeStringAndLong, 0, 0, 2) ZEND_ARG_INFO(1, state) ZEND_ARG_INFO(0, string) /* optional */ ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, long) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StateByReferenceAndStringAndMaybeString, 0, 0, 2) ZEND_ARG_INFO(1, state) ZEND_ARG_INFO(0, string) /* optional */ ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StateByReferenceAndMaybeLength, 0, 0, 1) ZEND_ARG_INFO(1, state) /* optional */ ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_StateByReferenceAndString, 0, 0, 2) ZEND_ARG_INFO(1, state) ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_MaybeKeyAndLength, 0, 0, 0) /* optional */ ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_KXClientSession, 0, 0, 2) ZEND_ARG_INFO(0, client_keypair) ZEND_ARG_INFO(0, server_key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_KXServerSession, 0, 0, 2) ZEND_ARG_INFO(0, server_keypair) ZEND_ARG_INFO(0, client_key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(AI_KDF, 0, 0, 4) ZEND_ARG_INFO(0, subkey_len) ZEND_ARG_INFO(0, subkey_id) ZEND_ARG_INFO(0, context) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(__i386__) || \ defined(_M_AMD64) || defined(_M_IX86)) # define HAVE_AESGCM 1 #endif #ifndef crypto_aead_chacha20poly1305_IETF_KEYBYTES # define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_KEYBYTES #endif #ifndef crypto_aead_chacha20poly1305_IETF_NSECBYTES # define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_NSECBYTES #endif #ifndef crypto_aead_chacha20poly1305_IETF_ABYTES # define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ABYTES #endif #if defined(crypto_secretstream_xchacha20poly1305_ABYTES) && SODIUM_LIBRARY_VERSION_MAJOR < 10 # undef crypto_secretstream_xchacha20poly1305_ABYTES #endif #ifndef crypto_pwhash_OPSLIMIT_MIN # define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_OPSLIMIT_INTERACTIVE #endif #ifndef crypto_pwhash_MEMLIMIT_MIN # define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_MEMLIMIT_INTERACTIVE #endif #ifndef crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN # define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE #endif #ifndef crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN # define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE #endif static const zend_function_entry sodium_functions[] = { PHP_FE(sodium_crypto_aead_aes256gcm_is_available, AI_None) #ifdef HAVE_AESGCM PHP_FE(sodium_crypto_aead_aes256gcm_decrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_aes256gcm_encrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_aes256gcm_keygen, AI_None) #endif PHP_FE(sodium_crypto_aead_chacha20poly1305_decrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_chacha20poly1305_encrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_chacha20poly1305_keygen, AI_None) PHP_FE(sodium_crypto_aead_chacha20poly1305_ietf_decrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_chacha20poly1305_ietf_encrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_chacha20poly1305_ietf_keygen, AI_None) #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES PHP_FE(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt, AI_StringAndADAndNonceAndKey) PHP_FE(sodium_crypto_aead_xchacha20poly1305_ietf_keygen, AI_None) PHP_FE(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt, AI_StringAndADAndNonceAndKey) #endif PHP_FE(sodium_crypto_auth, AI_StringAndKey) PHP_FE(sodium_crypto_auth_keygen, AI_None) PHP_FE(sodium_crypto_auth_verify, AI_SignatureAndStringAndKey) PHP_FE(sodium_crypto_box, AI_StringAndNonceAndKeyPair) PHP_FE(sodium_crypto_box_keypair, AI_None) PHP_FE(sodium_crypto_box_seed_keypair, AI_Key) PHP_FE(sodium_crypto_box_keypair_from_secretkey_and_publickey, AI_SecretKeyAndPublicKey) PHP_FE(sodium_crypto_box_open, AI_StringAndNonceAndKey) PHP_FE(sodium_crypto_box_publickey, AI_Key) PHP_FE(sodium_crypto_box_publickey_from_secretkey, AI_Key) PHP_FE(sodium_crypto_box_seal, AI_StringAndKey) PHP_FE(sodium_crypto_box_seal_open, AI_StringAndKey) PHP_FE(sodium_crypto_box_secretkey, AI_Key) PHP_FE(sodium_crypto_kx_keypair, AI_None) PHP_FE(sodium_crypto_kx_publickey, AI_Key) PHP_FE(sodium_crypto_kx_secretkey, AI_Key) PHP_FE(sodium_crypto_kx_seed_keypair, AI_String) PHP_FE(sodium_crypto_kx_client_session_keys, AI_KXClientSession) PHP_FE(sodium_crypto_kx_server_session_keys, AI_KXServerSession) PHP_FE(sodium_crypto_generichash, AI_StringAndMaybeKeyAndLength) PHP_FE(sodium_crypto_generichash_keygen, AI_None) PHP_FE(sodium_crypto_generichash_init, AI_MaybeKeyAndLength) PHP_FE(sodium_crypto_generichash_update, AI_StateByReferenceAndString) PHP_FE(sodium_crypto_generichash_final, AI_StateByReferenceAndMaybeLength) PHP_FE(sodium_crypto_kdf_derive_from_key, AI_KDF) PHP_FE(sodium_crypto_kdf_keygen, AI_None) #ifdef crypto_pwhash_SALTBYTES PHP_FE(sodium_crypto_pwhash, AI_LengthAndPasswordAndSaltAndOpsLimitAndMemLimit) PHP_FE(sodium_crypto_pwhash_str, AI_PasswordAndOpsLimitAndMemLimit) PHP_FE(sodium_crypto_pwhash_str_verify, AI_HashAndPassword) #endif #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) PHP_FE(sodium_crypto_pwhash_str_needs_rehash, AI_PasswordAndOpsLimitAndMemLimit) #endif #ifdef crypto_pwhash_scryptsalsa208sha256_SALTBYTES PHP_FE(sodium_crypto_pwhash_scryptsalsa208sha256, AI_LengthAndPasswordAndSaltAndOpsLimitAndMemLimit) PHP_FE(sodium_crypto_pwhash_scryptsalsa208sha256_str, AI_PasswordAndOpsLimitAndMemLimit) PHP_FE(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify, AI_HashAndPassword) #endif PHP_FE(sodium_crypto_scalarmult, AI_TwoStrings) PHP_FE(sodium_crypto_secretbox, AI_StringAndNonceAndKey) PHP_FE(sodium_crypto_secretbox_keygen, AI_None) PHP_FE(sodium_crypto_secretbox_open, AI_StringAndNonceAndKey) #ifdef crypto_secretstream_xchacha20poly1305_ABYTES PHP_FE(sodium_crypto_secretstream_xchacha20poly1305_keygen, AI_None) PHP_FE(sodium_crypto_secretstream_xchacha20poly1305_init_push, AI_Key) PHP_FE(sodium_crypto_secretstream_xchacha20poly1305_push, AI_StateByReferenceAndStringAndMaybeStringAndLong) PHP_FE(sodium_crypto_secretstream_xchacha20poly1305_init_pull, AI_StringAndKey) PHP_FE(sodium_crypto_secretstream_xchacha20poly1305_pull, AI_StateByReferenceAndStringAndMaybeString) PHP_FE(sodium_crypto_secretstream_xchacha20poly1305_rekey, AI_StateByReference) #endif PHP_FE(sodium_crypto_shorthash, AI_StringAndKey) PHP_FE(sodium_crypto_shorthash_keygen, AI_None) PHP_FE(sodium_crypto_sign, AI_StringAndKeyPair) PHP_FE(sodium_crypto_sign_detached, AI_StringAndKeyPair) PHP_FE(sodium_crypto_sign_ed25519_pk_to_curve25519, AI_Key) PHP_FE(sodium_crypto_sign_ed25519_sk_to_curve25519, AI_Key) PHP_FE(sodium_crypto_sign_keypair, AI_None) PHP_FE(sodium_crypto_sign_keypair_from_secretkey_and_publickey, AI_SecretKeyAndPublicKey) PHP_FE(sodium_crypto_sign_open, AI_StringAndKeyPair) PHP_FE(sodium_crypto_sign_publickey, AI_Key) PHP_FE(sodium_crypto_sign_secretkey, AI_Key) PHP_FE(sodium_crypto_sign_publickey_from_secretkey, AI_Key) PHP_FE(sodium_crypto_sign_seed_keypair, AI_Key) PHP_FE(sodium_crypto_sign_verify_detached, AI_SignatureAndStringAndKey) PHP_FE(sodium_crypto_stream, AI_LengthAndNonceAndKey) PHP_FE(sodium_crypto_stream_keygen, AI_None) PHP_FE(sodium_crypto_stream_xor, AI_StringAndNonceAndKey) /* helpers */ PHP_FE(sodium_add, AI_StringRefAndString) PHP_FE(sodium_compare, AI_TwoStrings) PHP_FE(sodium_increment, AI_StringRef) PHP_FE(sodium_memcmp, AI_TwoStrings) PHP_FE(sodium_memzero, AI_FirstArgByReference) PHP_FE(sodium_pad, AI_StringAndLength) PHP_FE(sodium_unpad, AI_StringAndLength) /* codecs */ PHP_FE(sodium_bin2hex, AI_String) PHP_FE(sodium_hex2bin, AI_StringAndMaybeString) #ifdef sodium_base64_VARIANT_ORIGINAL PHP_FE(sodium_bin2base64, AI_StringAndId) PHP_FE(sodium_base642bin, AI_StringAndIdAndMaybeString) #endif /* aliases */ PHP_FALIAS(sodium_crypto_scalarmult_base, sodium_crypto_box_publickey_from_secretkey, AI_TwoStrings) PHP_FE_END }; /* Load after the "standard" module in order to give it * priority in registering argon2i/argon2id password hashers. */ static const zend_module_dep sodium_deps[] = { ZEND_MOD_REQUIRED("standard") ZEND_MOD_END }; zend_module_entry sodium_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, sodium_deps, "sodium", sodium_functions, PHP_MINIT(sodium), PHP_MSHUTDOWN(sodium), NULL, NULL, PHP_MINFO(sodium), PHP_SODIUM_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_SODIUM ZEND_GET_MODULE(sodium) #endif /* Remove argument information from backtrace to prevent information leaks */ static void sodium_remove_param_values_from_backtrace(zend_object *obj) { zval obj_zv, rv, *trace; ZVAL_OBJ(&obj_zv, obj); trace = zend_read_property(zend_get_exception_base(&obj_zv), &obj_zv, "trace", sizeof("trace")-1, 0, &rv); if (trace && Z_TYPE_P(trace) == IS_ARRAY) { zval *frame; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(trace), frame) { if (Z_TYPE_P(frame) == IS_ARRAY) { zval *args = zend_hash_str_find(Z_ARRVAL_P(frame), "args", sizeof("args")-1); if (args) { zval_ptr_dtor(args); ZVAL_EMPTY_ARRAY(args); } } } ZEND_HASH_FOREACH_END(); } } static zend_object *sodium_exception_create_object(zend_class_entry *ce) { zend_object *obj = zend_ce_exception->create_object(ce); sodium_remove_param_values_from_backtrace(obj); return obj; } static void sodium_separate_string(zval *zv) { ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING); if (!Z_REFCOUNTED_P(zv) || Z_REFCOUNT_P(zv) > 1) { zend_string *copy = zend_string_init(Z_STRVAL_P(zv), Z_STRLEN_P(zv), 0); Z_TRY_DELREF_P(zv); ZVAL_STR(zv, copy); } } PHP_MINIT_FUNCTION(sodium) { zend_class_entry ce; if (sodium_init() < 0) { zend_error(E_ERROR, "sodium_init()"); } INIT_CLASS_ENTRY(ce, "SodiumException", NULL); sodium_exception_ce = zend_register_internal_class_ex(&ce, zend_ce_exception); sodium_exception_ce->create_object = sodium_exception_create_object; REGISTER_STRING_CONSTANT("SODIUM_LIBRARY_VERSION", (char *) (void *) sodium_version_string(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_LIBRARY_MAJOR_VERSION", sodium_library_version_major(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_LIBRARY_MINOR_VERSION", sodium_library_version_minor(), CONST_CS | CONST_PERSISTENT); #ifdef HAVE_AESGCM REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES", crypto_aead_aes256gcm_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_NSECBYTES", crypto_aead_aes256gcm_NSECBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES", crypto_aead_aes256gcm_NPUBBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_ABYTES", crypto_aead_aes256gcm_ABYTES, CONST_CS | CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES", crypto_aead_chacha20poly1305_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES", crypto_aead_chacha20poly1305_NSECBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES", crypto_aead_chacha20poly1305_NPUBBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_ABYTES", crypto_aead_chacha20poly1305_ABYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES", crypto_aead_chacha20poly1305_IETF_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES", crypto_aead_chacha20poly1305_IETF_NSECBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES", crypto_aead_chacha20poly1305_IETF_NPUBBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES", crypto_aead_chacha20poly1305_IETF_ABYTES, CONST_CS | CONST_PERSISTENT); #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES", crypto_aead_xchacha20poly1305_IETF_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES", crypto_aead_xchacha20poly1305_IETF_NSECBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES", crypto_aead_xchacha20poly1305_IETF_NPUBBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES", crypto_aead_xchacha20poly1305_IETF_ABYTES, CONST_CS | CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AUTH_BYTES", crypto_auth_BYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AUTH_KEYBYTES", crypto_auth_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_SEALBYTES", crypto_box_SEALBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_SECRETKEYBYTES", crypto_box_SECRETKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_PUBLICKEYBYTES", crypto_box_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_KEYPAIRBYTES", crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_MACBYTES", crypto_box_MACBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_NONCEBYTES", crypto_box_NONCEBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_SEEDBYTES", crypto_box_SEEDBYTES, CONST_CS | CONST_PERSISTENT); #ifndef crypto_kdf_BYTES_MIN # define crypto_kdf_BYTES_MIN 16 # define crypto_kdf_BYTES_MAX 64 # define crypto_kdf_CONTEXTBYTES 8 # define crypto_kdf_KEYBYTES 32 #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KDF_BYTES_MIN", crypto_kdf_BYTES_MIN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KDF_BYTES_MAX", crypto_kdf_BYTES_MAX, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KDF_CONTEXTBYTES", crypto_kdf_CONTEXTBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KDF_KEYBYTES", crypto_kdf_KEYBYTES, CONST_CS | CONST_PERSISTENT); #ifndef crypto_kx_SEEDBYTES # define crypto_kx_SEEDBYTES 32 # define crypto_kx_SESSIONKEYBYTES 32 # define crypto_kx_PUBLICKEYBYTES 32 # define crypto_kx_SECRETKEYBYTES 32 #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_SEEDBYTES", crypto_kx_SEEDBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_SESSIONKEYBYTES", crypto_kx_SESSIONKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_PUBLICKEYBYTES", crypto_kx_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_SECRETKEYBYTES", crypto_kx_SECRETKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_KEYPAIRBYTES", crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); #ifdef crypto_secretstream_xchacha20poly1305_ABYTES REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES", crypto_secretstream_xchacha20poly1305_ABYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES", crypto_secretstream_xchacha20poly1305_HEADERBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES", crypto_secretstream_xchacha20poly1305_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX", crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE", crypto_secretstream_xchacha20poly1305_TAG_MESSAGE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH", crypto_secretstream_xchacha20poly1305_TAG_PUSH, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY", crypto_secretstream_xchacha20poly1305_TAG_REKEY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL", crypto_secretstream_xchacha20poly1305_TAG_FINAL, CONST_CS | CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_BYTES", crypto_generichash_BYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_BYTES_MIN", crypto_generichash_BYTES_MIN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_BYTES_MAX", crypto_generichash_BYTES_MAX, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_KEYBYTES", crypto_generichash_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MIN", crypto_generichash_KEYBYTES_MIN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MAX", crypto_generichash_KEYBYTES_MAX, CONST_CS | CONST_PERSISTENT); #ifdef crypto_pwhash_SALTBYTES REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13", crypto_pwhash_ALG_ARGON2I13, CONST_CS | CONST_PERSISTENT); # ifdef crypto_pwhash_ALG_ARGON2ID13 REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13", crypto_pwhash_ALG_ARGON2ID13, CONST_CS | CONST_PERSISTENT); # endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_ALG_DEFAULT", crypto_pwhash_ALG_DEFAULT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SALTBYTES", crypto_pwhash_SALTBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("SODIUM_CRYPTO_PWHASH_STRPREFIX", crypto_pwhash_STRPREFIX, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE", crypto_pwhash_opslimit_interactive(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE", crypto_pwhash_memlimit_interactive(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE", crypto_pwhash_opslimit_moderate(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE", crypto_pwhash_memlimit_moderate(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE", crypto_pwhash_opslimit_sensitive(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE", crypto_pwhash_memlimit_sensitive(), CONST_CS | CONST_PERSISTENT); #endif #ifdef crypto_pwhash_scryptsalsa208sha256_SALTBYTES REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES", crypto_pwhash_scryptsalsa208sha256_SALTBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX", crypto_pwhash_scryptsalsa208sha256_STRPREFIX, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE", crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE", crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE", crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(), CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE", crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(), CONST_CS | CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SCALARMULT_BYTES", crypto_scalarmult_BYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SCALARMULT_SCALARBYTES", crypto_scalarmult_SCALARBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SHORTHASH_BYTES", crypto_shorthash_BYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SHORTHASH_KEYBYTES", crypto_shorthash_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETBOX_KEYBYTES", crypto_secretbox_KEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETBOX_MACBYTES", crypto_secretbox_MACBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETBOX_NONCEBYTES", crypto_secretbox_NONCEBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SIGN_BYTES", crypto_sign_BYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SIGN_SEEDBYTES", crypto_sign_SEEDBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES", crypto_sign_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SIGN_SECRETKEYBYTES", crypto_sign_SECRETKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SIGN_KEYPAIRBYTES", crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_STREAM_NONCEBYTES", crypto_stream_NONCEBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_STREAM_KEYBYTES", crypto_stream_KEYBYTES, CONST_CS | CONST_PERSISTENT); #ifdef sodium_base64_VARIANT_ORIGINAL REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_ORIGINAL", sodium_base64_VARIANT_ORIGINAL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING", sodium_base64_VARIANT_ORIGINAL_NO_PADDING, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_URLSAFE", sodium_base64_VARIANT_URLSAFE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING", sodium_base64_VARIANT_URLSAFE_NO_PADDING, CONST_CS | CONST_PERSISTENT); #endif #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) if (FAILURE == PHP_MINIT(sodium_password_hash)(INIT_FUNC_ARGS_PASSTHRU)) { return FAILURE; } #endif return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(sodium) { randombytes_close(); return SUCCESS; } PHP_MINFO_FUNCTION(sodium) { php_info_print_table_start(); php_info_print_table_header(2, "sodium support", "enabled"); php_info_print_table_row(2, "libsodium headers version", SODIUM_VERSION_STRING); php_info_print_table_row(2, "libsodium library version", sodium_version_string()); php_info_print_table_end(); } PHP_FUNCTION(sodium_memzero) { zval *buf_zv; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "z", &buf_zv) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(buf_zv); if (Z_TYPE_P(buf_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0); return; } if (Z_REFCOUNTED_P(buf_zv) && Z_REFCOUNT_P(buf_zv) == 1) { char *buf = Z_STRVAL(*buf_zv); size_t buf_len = Z_STRLEN(*buf_zv); if (buf_len > 0) { sodium_memzero(buf, (size_t) buf_len); } } convert_to_null(buf_zv); } PHP_FUNCTION(sodium_increment) { zval *val_zv; unsigned char *val; size_t val_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "z", &val_zv) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(val_zv); if (Z_TYPE_P(val_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0); return; } sodium_separate_string(val_zv); val = (unsigned char *) Z_STRVAL(*val_zv); val_len = Z_STRLEN(*val_zv); sodium_increment(val, val_len); } PHP_FUNCTION(sodium_add) { zval *val_zv; unsigned char *val; unsigned char *addv; size_t val_len; size_t addv_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs", &val_zv, &addv, &addv_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(val_zv); if (Z_TYPE_P(val_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "PHP strings are required", 0); return; } sodium_separate_string(val_zv); val = (unsigned char *) Z_STRVAL(*val_zv); val_len = Z_STRLEN(*val_zv); if (val_len != addv_len) { zend_throw_exception(sodium_exception_ce, "values must have the same length", 0); return; } sodium_add(val, addv, val_len); } PHP_FUNCTION(sodium_memcmp) { char *buf1; char *buf2; size_t len1; size_t len2; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &buf1, &len1, &buf2, &len2) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (len1 != len2) { zend_throw_exception(sodium_exception_ce, "arguments have different sizes", 0); return; } RETURN_LONG(sodium_memcmp(buf1, buf2, len1)); } PHP_FUNCTION(sodium_crypto_shorthash) { zend_string *hash; unsigned char *key; unsigned char *msg; size_t key_len; size_t msg_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &msg, &msg_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (key_len != crypto_shorthash_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key size should be SODIUM_CRYPTO_SHORTHASH_KEYBYTES bytes", 0); return; } hash = zend_string_alloc(crypto_shorthash_BYTES, 0); if (crypto_shorthash((unsigned char *) ZSTR_VAL(hash), msg, (unsigned long long) msg_len, key) != 0) { zend_string_efree(hash); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(hash)[crypto_shorthash_BYTES] = 0; RETURN_NEW_STR(hash); } PHP_FUNCTION(sodium_crypto_secretbox) { zend_string *ciphertext; unsigned char *key; unsigned char *msg; unsigned char *nonce; size_t key_len; size_t msg_len; size_t nonce_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &msg, &msg_len, &nonce, &nonce_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (nonce_len != crypto_secretbox_NONCEBYTES) { zend_throw_exception(sodium_exception_ce, "nonce size should be SODIUM_CRYPTO_SECRETBOX_NONCEBYTES bytes", 0); return; } if (key_len != crypto_secretbox_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key size should be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_secretbox_MACBYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } ciphertext = zend_string_alloc((size_t) msg_len + crypto_secretbox_MACBYTES, 0); if (crypto_secretbox_easy((unsigned char *) ZSTR_VAL(ciphertext), msg, (unsigned long long) msg_len, nonce, key) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(ciphertext)[msg_len + crypto_secretbox_MACBYTES] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_secretbox_open) { zend_string *msg; unsigned char *key; unsigned char *ciphertext; unsigned char *nonce; size_t key_len; size_t ciphertext_len; size_t nonce_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &ciphertext, &ciphertext_len, &nonce, &nonce_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (nonce_len != crypto_secretbox_NONCEBYTES) { zend_throw_exception(sodium_exception_ce, "nonce size should be SODIUM_CRYPTO_SECRETBOX_NONCEBYTES bytes", 0); return; } if (key_len != crypto_secretbox_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key size should be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes", 0); return; } if (ciphertext_len < crypto_secretbox_MACBYTES) { RETURN_FALSE; } msg = zend_string_alloc ((size_t) ciphertext_len - crypto_secretbox_MACBYTES, 0); if (crypto_secretbox_open_easy((unsigned char *) ZSTR_VAL(msg), ciphertext, (unsigned long long) ciphertext_len, nonce, key) != 0) { zend_string_efree(msg); RETURN_FALSE; } else { ZSTR_VAL(msg)[ciphertext_len - crypto_secretbox_MACBYTES] = 0; RETURN_NEW_STR(msg); } } PHP_FUNCTION(sodium_crypto_generichash) { zend_string *hash; unsigned char *key = NULL; unsigned char *msg; zend_long hash_len = crypto_generichash_BYTES; size_t key_len = 0; size_t msg_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s|sl", &msg, &msg_len, &key, &key_len, &hash_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (hash_len < crypto_generichash_BYTES_MIN || hash_len > crypto_generichash_BYTES_MAX) { zend_throw_exception(sodium_exception_ce, "unsupported output length", 0); return; } if (key_len != 0 && (key_len < crypto_generichash_KEYBYTES_MIN || key_len > crypto_generichash_KEYBYTES_MAX)) { zend_throw_exception(sodium_exception_ce, "unsupported key length", 0); return; } hash = zend_string_alloc(hash_len, 0); if (crypto_generichash((unsigned char *) ZSTR_VAL(hash), (size_t) hash_len, msg, (unsigned long long) msg_len, key, (size_t) key_len) != 0) { zend_string_efree(hash); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(hash)[hash_len] = 0; RETURN_NEW_STR(hash); } PHP_FUNCTION(sodium_crypto_generichash_init) { crypto_generichash_state state_tmp; zend_string *state; unsigned char *key = NULL; size_t state_len = sizeof (crypto_generichash_state); zend_long hash_len = crypto_generichash_BYTES; size_t key_len = 0; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|sl", &key, &key_len, &hash_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (hash_len < crypto_generichash_BYTES_MIN || hash_len > crypto_generichash_BYTES_MAX) { zend_throw_exception(sodium_exception_ce, "unsupported output length", 0); return; } if (key_len != 0 && (key_len < crypto_generichash_KEYBYTES_MIN || key_len > crypto_generichash_KEYBYTES_MAX)) { zend_throw_exception(sodium_exception_ce, "unsupported key length", 0); return; } memset(&state_tmp, 0, sizeof state_tmp); if (crypto_generichash_init((void *) &state_tmp, key, (size_t) key_len, (size_t) hash_len) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } state = zend_string_alloc(state_len, 0); memcpy(ZSTR_VAL(state), &state_tmp, state_len); sodium_memzero(&state_tmp, sizeof state_tmp); ZSTR_VAL(state)[state_len] = 0; RETURN_STR(state); } PHP_FUNCTION(sodium_crypto_generichash_update) { crypto_generichash_state state_tmp; zval *state_zv; unsigned char *msg; unsigned char *state; size_t msg_len; size_t state_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs", &state_zv, &msg, &msg_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(state_zv); if (Z_TYPE_P(state_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a reference to a state is required", 0); return; } sodium_separate_string(state_zv); state = (unsigned char *) Z_STRVAL(*state_zv); state_len = Z_STRLEN(*state_zv); if (state_len != sizeof (crypto_generichash_state)) { zend_throw_exception(sodium_exception_ce, "incorrect state length", 0); return; } memcpy(&state_tmp, state, sizeof state_tmp); if (crypto_generichash_update((void *) &state_tmp, msg, (unsigned long long) msg_len) != 0) { sodium_memzero(&state_tmp, sizeof state_tmp); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } memcpy(state, &state_tmp, state_len); sodium_memzero(&state_tmp, sizeof state_tmp); RETURN_TRUE; } PHP_FUNCTION(sodium_crypto_generichash_final) { crypto_generichash_state state_tmp; zend_string *hash; zval *state_zv; unsigned char *state; size_t state_len; zend_long hash_len = crypto_generichash_BYTES; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "z|l", &state_zv, &hash_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(state_zv); if (Z_TYPE_P(state_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a reference to a state is required", 0); return; } sodium_separate_string(state_zv); state = (unsigned char *) Z_STRVAL(*state_zv); state_len = Z_STRLEN(*state_zv); if (state_len != sizeof (crypto_generichash_state)) { zend_throw_exception(sodium_exception_ce, "incorrect state length", 0); return; } if (hash_len < crypto_generichash_BYTES_MIN || hash_len > crypto_generichash_BYTES_MAX) { zend_throw_exception(sodium_exception_ce, "unsupported output length", 0); return; } hash = zend_string_alloc(hash_len, 0); memcpy(&state_tmp, state, sizeof state_tmp); if (crypto_generichash_final((void *) &state_tmp, (unsigned char *) ZSTR_VAL(hash), (size_t) hash_len) != 0) { sodium_memzero(&state_tmp, sizeof state_tmp); zend_string_efree(hash); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } sodium_memzero(&state_tmp, sizeof state_tmp); sodium_memzero(state, state_len); convert_to_null(state_zv); ZSTR_VAL(hash)[hash_len] = 0; RETURN_NEW_STR(hash); } PHP_FUNCTION(sodium_crypto_box_keypair) { zend_string *keypair; size_t keypair_len; if (zend_parse_parameters_none() == FAILURE) { return; } keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES; keypair = zend_string_alloc(keypair_len, 0); if (crypto_box_keypair((unsigned char *) ZSTR_VAL(keypair) + crypto_box_SECRETKEYBYTES, (unsigned char *) ZSTR_VAL(keypair)) != 0) { zend_string_efree(keypair); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(keypair)[keypair_len] = 0; RETURN_NEW_STR(keypair); } PHP_FUNCTION(sodium_crypto_box_seed_keypair) { zend_string *keypair; unsigned char *seed; size_t keypair_len; size_t seed_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &seed, &seed_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (seed_len != crypto_box_SEEDBYTES) { zend_throw_exception(sodium_exception_ce, "seed should be SODIUM_CRYPTO_BOX_SEEDBYTES bytes", 0); return; } keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES; keypair = zend_string_alloc(keypair_len, 0); if (crypto_box_seed_keypair((unsigned char *) ZSTR_VAL(keypair) + crypto_box_SECRETKEYBYTES, (unsigned char *) ZSTR_VAL(keypair), seed) != 0) { zend_string_efree(keypair); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(keypair)[keypair_len] = 0; RETURN_NEW_STR(keypair); } PHP_FUNCTION(sodium_crypto_box_keypair_from_secretkey_and_publickey) { zend_string *keypair; char *publickey; char *secretkey; size_t keypair_len; size_t publickey_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &secretkey, &secretkey_len, &publickey, &publickey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (secretkey_len != crypto_box_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "secretkey should be SODIUM_CRYPTO_BOX_SECRETKEYBYTES bytes", 0); return; } if (publickey_len != crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "publickey should be SODIUM_CRYPTO_BOX_PUBLICKEYBYTES bytes", 0); return; } keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES; keypair = zend_string_alloc(keypair_len, 0); memcpy(ZSTR_VAL(keypair), secretkey, crypto_box_SECRETKEYBYTES); memcpy(ZSTR_VAL(keypair) + crypto_box_SECRETKEYBYTES, publickey, crypto_box_PUBLICKEYBYTES); ZSTR_VAL(keypair)[keypair_len] = 0; RETURN_STR(keypair); } PHP_FUNCTION(sodium_crypto_box_secretkey) { zend_string *secretkey; unsigned char *keypair; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair should be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes", 0); return; } secretkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0); memcpy(ZSTR_VAL(secretkey), keypair, crypto_box_SECRETKEYBYTES); ZSTR_VAL(secretkey)[crypto_box_SECRETKEYBYTES] = 0; RETURN_STR(secretkey); } PHP_FUNCTION(sodium_crypto_box_publickey) { zend_string *publickey; unsigned char *keypair; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair should be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes", 0); return; } publickey = zend_string_alloc(crypto_box_PUBLICKEYBYTES, 0); memcpy(ZSTR_VAL(publickey), keypair + crypto_box_SECRETKEYBYTES, crypto_box_PUBLICKEYBYTES); ZSTR_VAL(publickey)[crypto_box_PUBLICKEYBYTES] = 0; RETURN_STR(publickey); } PHP_FUNCTION(sodium_crypto_box_publickey_from_secretkey) { zend_string *publickey; unsigned char *secretkey; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (secretkey_len != crypto_box_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "key should be SODIUM_CRYPTO_BOX_SECRETKEYBYTES bytes", 0); return; } publickey = zend_string_alloc(crypto_box_PUBLICKEYBYTES, 0); (void) sizeof(int[crypto_scalarmult_BYTES == crypto_box_PUBLICKEYBYTES ? 1 : -1]); (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_box_SECRETKEYBYTES ? 1 : -1]); crypto_scalarmult_base((unsigned char *) ZSTR_VAL(publickey), secretkey); ZSTR_VAL(publickey)[crypto_box_PUBLICKEYBYTES] = 0; RETURN_STR(publickey); } PHP_FUNCTION(sodium_crypto_box) { zend_string *ciphertext; unsigned char *keypair; unsigned char *msg; unsigned char *nonce; unsigned char *publickey; unsigned char *secretkey; size_t keypair_len; size_t msg_len; size_t nonce_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &msg, &msg_len, &nonce, &nonce_len, &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (nonce_len != crypto_box_NONCEBYTES) { zend_throw_exception(sodium_exception_ce, "nonce size should be SODIUM_CRYPTO_BOX_NONCEBYTES bytes", 0); return; } if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair size should be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes", 0); return; } secretkey = keypair; publickey = keypair + crypto_box_SECRETKEYBYTES; if (SIZE_MAX - msg_len <= crypto_box_MACBYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } ciphertext = zend_string_alloc((size_t) msg_len + crypto_box_MACBYTES, 0); if (crypto_box_easy((unsigned char *) ZSTR_VAL(ciphertext), msg, (unsigned long long) msg_len, nonce, publickey, secretkey) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(ciphertext)[msg_len + crypto_box_MACBYTES] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_box_open) { zend_string *msg; unsigned char *ciphertext; unsigned char *keypair; unsigned char *nonce; unsigned char *publickey; unsigned char *secretkey; size_t ciphertext_len; size_t keypair_len; size_t nonce_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &ciphertext, &ciphertext_len, &nonce, &nonce_len, &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (nonce_len != crypto_box_NONCEBYTES) { zend_throw_exception(sodium_exception_ce, "nonce size should be SODIUM_CRYPTO_BOX_NONCEBYTES bytes", 0); return; } if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair size should be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes", 0); return; } secretkey = keypair; publickey = keypair + crypto_box_SECRETKEYBYTES; if (ciphertext_len < crypto_box_MACBYTES) { RETURN_FALSE; } msg = zend_string_alloc((size_t) ciphertext_len - crypto_box_MACBYTES, 0); if (crypto_box_open_easy((unsigned char *) ZSTR_VAL(msg), ciphertext, (unsigned long long) ciphertext_len, nonce, publickey, secretkey) != 0) { zend_string_efree(msg); RETURN_FALSE; } else { ZSTR_VAL(msg)[ciphertext_len - crypto_box_MACBYTES] = 0; RETURN_NEW_STR(msg); } } PHP_FUNCTION(sodium_crypto_box_seal) { zend_string *ciphertext; unsigned char *msg; unsigned char *publickey; size_t msg_len; size_t publickey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &msg, &msg_len, &publickey, &publickey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (publickey_len != crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "public key size should be SODIUM_CRYPTO_BOX_PUBLICKEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_box_SEALBYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } ciphertext = zend_string_alloc((size_t) msg_len + crypto_box_SEALBYTES, 0); if (crypto_box_seal((unsigned char *) ZSTR_VAL(ciphertext), msg, (unsigned long long) msg_len, publickey) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(ciphertext)[msg_len + crypto_box_SEALBYTES] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_box_seal_open) { zend_string *msg; unsigned char *ciphertext; unsigned char *keypair; unsigned char *publickey; unsigned char *secretkey; size_t ciphertext_len; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &ciphertext, &ciphertext_len, &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair size should be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes", 0); return; } secretkey = keypair; publickey = keypair + crypto_box_SECRETKEYBYTES; if (ciphertext_len < crypto_box_SEALBYTES) { RETURN_FALSE; } msg = zend_string_alloc((size_t) ciphertext_len - crypto_box_SEALBYTES, 0); if (crypto_box_seal_open((unsigned char *) ZSTR_VAL(msg), ciphertext, (unsigned long long) ciphertext_len, publickey, secretkey) != 0) { zend_string_efree(msg); RETURN_FALSE; } else { ZSTR_VAL(msg)[ciphertext_len - crypto_box_SEALBYTES] = 0; RETURN_NEW_STR(msg); } } PHP_FUNCTION(sodium_crypto_sign_keypair) { zend_string *keypair; size_t keypair_len; if (zend_parse_parameters_none() == FAILURE) { return; } keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES; keypair = zend_string_alloc(keypair_len, 0); if (crypto_sign_keypair((unsigned char *) ZSTR_VAL(keypair) + crypto_sign_SECRETKEYBYTES, (unsigned char *) ZSTR_VAL(keypair)) != 0) { zend_string_efree(keypair); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(keypair)[keypair_len] = 0; RETURN_NEW_STR(keypair); } PHP_FUNCTION(sodium_crypto_sign_seed_keypair) { zend_string *keypair; unsigned char *seed; size_t keypair_len; size_t seed_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &seed, &seed_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (seed_len != crypto_sign_SEEDBYTES) { zend_throw_exception(sodium_exception_ce, "seed should be SODIUM_CRYPTO_SIGN_SEEDBYTES bytes", 0); return; } keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES; keypair = zend_string_alloc(keypair_len, 0); if (crypto_sign_seed_keypair((unsigned char *) ZSTR_VAL(keypair) + crypto_sign_SECRETKEYBYTES, (unsigned char *) ZSTR_VAL(keypair), seed) != 0) { zend_string_efree(keypair); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(keypair)[keypair_len] = 0; RETURN_NEW_STR(keypair); } PHP_FUNCTION(sodium_crypto_sign_keypair_from_secretkey_and_publickey) { zend_string *keypair; char *publickey; char *secretkey; size_t keypair_len; size_t publickey_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &secretkey, &secretkey_len, &publickey, &publickey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (secretkey_len != crypto_sign_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes", 0); return; } if (publickey_len != crypto_sign_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes", 0); return; } keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES; keypair = zend_string_alloc(keypair_len, 0); memcpy(ZSTR_VAL(keypair), secretkey, crypto_sign_SECRETKEYBYTES); memcpy(ZSTR_VAL(keypair) + crypto_sign_SECRETKEYBYTES, publickey, crypto_sign_PUBLICKEYBYTES); ZSTR_VAL(keypair)[keypair_len] = 0; RETURN_STR(keypair); } PHP_FUNCTION(sodium_crypto_sign_publickey_from_secretkey) { zend_string *publickey; char *secretkey; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (secretkey_len != crypto_sign_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes", 0); return; } publickey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0); if (crypto_sign_ed25519_sk_to_pk((unsigned char *) ZSTR_VAL(publickey), (const unsigned char *) secretkey) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(publickey)[crypto_sign_PUBLICKEYBYTES] = 0; RETURN_STR(publickey); } PHP_FUNCTION(sodium_crypto_sign_secretkey) { zend_string *secretkey; unsigned char *keypair; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair should be SODIUM_CRYPTO_SIGN_KEYPAIRBYTES bytes", 0); return; } secretkey = zend_string_alloc(crypto_sign_SECRETKEYBYTES, 0); memcpy(ZSTR_VAL(secretkey), keypair, crypto_sign_SECRETKEYBYTES); ZSTR_VAL(secretkey)[crypto_sign_SECRETKEYBYTES] = 0; RETURN_STR(secretkey); } PHP_FUNCTION(sodium_crypto_sign_publickey) { zend_string *publickey; unsigned char *keypair; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair should be SODIUM_CRYPTO_SIGN_KEYPAIRBYTES bytes", 0); return; } publickey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0); memcpy(ZSTR_VAL(publickey), keypair + crypto_sign_SECRETKEYBYTES, crypto_sign_PUBLICKEYBYTES); ZSTR_VAL(publickey)[crypto_sign_PUBLICKEYBYTES] = 0; RETURN_STR(publickey); } PHP_FUNCTION(sodium_crypto_sign) { zend_string *msg_signed; unsigned char *msg; unsigned char *secretkey; unsigned long long msg_signed_real_len; size_t msg_len; size_t msg_signed_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &msg, &msg_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (secretkey_len != crypto_sign_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_sign_BYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } msg_signed_len = msg_len + crypto_sign_BYTES; msg_signed = zend_string_alloc((size_t) msg_signed_len, 0); if (crypto_sign((unsigned char *) ZSTR_VAL(msg_signed), &msg_signed_real_len, msg, (unsigned long long) msg_len, secretkey) != 0) { zend_string_efree(msg_signed); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } if (msg_signed_real_len >= SIZE_MAX || msg_signed_real_len > msg_signed_len) { zend_string_efree(msg_signed); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg_signed, (size_t) msg_signed_real_len); ZSTR_VAL(msg_signed)[msg_signed_real_len] = 0; RETURN_NEW_STR(msg_signed); } PHP_FUNCTION(sodium_crypto_sign_open) { zend_string *msg; unsigned char *msg_signed; unsigned char *publickey; unsigned long long msg_real_len; size_t msg_len; size_t msg_signed_len; size_t publickey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &msg_signed, &msg_signed_len, &publickey, &publickey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (publickey_len != crypto_sign_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "public key size should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes", 0); return; } msg_len = msg_signed_len; if (msg_len >= SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } msg = zend_string_alloc((size_t) msg_len, 0); if (crypto_sign_open((unsigned char *) ZSTR_VAL(msg), &msg_real_len, msg_signed, (unsigned long long) msg_signed_len, publickey) != 0) { zend_string_efree(msg); RETURN_FALSE; } if (msg_real_len >= SIZE_MAX || msg_real_len > msg_signed_len) { zend_string_efree(msg); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len); ZSTR_VAL(msg)[msg_real_len] = 0; RETURN_NEW_STR(msg); } PHP_FUNCTION(sodium_crypto_sign_detached) { zend_string *signature; unsigned char *msg; unsigned char *secretkey; unsigned long long signature_real_len; size_t msg_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &msg, &msg_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (secretkey_len != crypto_sign_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes", 0); return; } signature = zend_string_alloc((size_t) crypto_sign_BYTES, 0); memset(ZSTR_VAL(signature), 0, (size_t) crypto_sign_BYTES); if (crypto_sign_detached((unsigned char *) ZSTR_VAL(signature), &signature_real_len, msg, (unsigned long long) msg_len, secretkey) != 0) { zend_string_efree(signature); zend_throw_exception(sodium_exception_ce, "signature creation failed", 0); return; } if (signature_real_len <= 0U || signature_real_len > crypto_sign_BYTES) { zend_string_efree(signature); zend_throw_exception(sodium_exception_ce, "signature has a bogus size", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(signature, (size_t) signature_real_len); ZSTR_VAL(signature)[signature_real_len] = 0; RETURN_NEW_STR(signature); } PHP_FUNCTION(sodium_crypto_sign_verify_detached) { unsigned char *msg; unsigned char *publickey; unsigned char *signature; size_t msg_len; size_t publickey_len; size_t signature_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &signature, &signature_len, &msg, &msg_len, &publickey, &publickey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (signature_len != crypto_sign_BYTES) { zend_throw_exception(sodium_exception_ce, "signature size should be SODIUM_CRYPTO_SIGN_BYTES bytes", 0); return; } if (publickey_len != crypto_sign_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "public key size should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes", 0); return; } if (crypto_sign_verify_detached(signature, msg, (unsigned long long) msg_len, publickey) != 0) { RETURN_FALSE; } RETURN_TRUE; } PHP_FUNCTION(sodium_crypto_stream) { zend_string *ciphertext; unsigned char *key; unsigned char *nonce; zend_long ciphertext_len; size_t key_len; size_t nonce_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "lss", &ciphertext_len, &nonce, &nonce_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "ciphertext length must be greater than 0", 0); return; } if (nonce_len != crypto_stream_NONCEBYTES) { zend_throw_exception(sodium_exception_ce, "nonce should be SODIUM_CRYPTO_STREAM_NONCEBYTES bytes", 0); return; } if (key_len != crypto_stream_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key should be SODIUM_CRYPTO_STREAM_KEYBYTES bytes", 0); return; } ciphertext = zend_string_alloc((size_t) ciphertext_len, 0); if (crypto_stream((unsigned char *) ZSTR_VAL(ciphertext), (unsigned long long) ciphertext_len, nonce, key) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(ciphertext)[ciphertext_len] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_stream_xor) { zend_string *ciphertext; unsigned char *key; unsigned char *msg; unsigned char *nonce; size_t ciphertext_len; size_t key_len; size_t msg_len; size_t nonce_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &msg, &msg_len, &nonce, &nonce_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (nonce_len != crypto_stream_NONCEBYTES) { zend_throw_exception(sodium_exception_ce, "nonce should be SODIUM_CRYPTO_STREAM_NONCEBYTES bytes", 0); return; } if (key_len != crypto_stream_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key should be SODIUM_CRYPTO_STREAM_KEYBYTES bytes", 0); return; } ciphertext_len = msg_len; ciphertext = zend_string_alloc((size_t) ciphertext_len, 0); if (crypto_stream_xor((unsigned char *) ZSTR_VAL(ciphertext), msg, (unsigned long long) msg_len, nonce, key) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(ciphertext)[ciphertext_len] = 0; RETURN_NEW_STR(ciphertext); } #ifdef crypto_pwhash_SALTBYTES PHP_FUNCTION(sodium_crypto_pwhash) { zend_string *hash; unsigned char *salt; char *passwd; zend_long hash_len; zend_long memlimit; zend_long opslimit; zend_long alg; size_t passwd_len; size_t salt_len; int ret; alg = (zend_long) crypto_pwhash_ALG_DEFAULT; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "lssll|l", &hash_len, &passwd, &passwd_len, &salt, &salt_len, &opslimit, &memlimit, &alg) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (hash_len <= 0 || hash_len >= 0xffffffff) { zend_throw_exception(sodium_exception_ce, "hash length must be greater than 0", 0); return; } if (passwd_len >= 0xffffffff) { zend_throw_exception(sodium_exception_ce, "unsupported password length", 0); return; } if (opslimit <= 0) { zend_throw_exception(sodium_exception_ce, "ops limit must be greater than 0", 0); return; } if (memlimit <= 0 || memlimit > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "memory limit must be greater than 0", 0); return; } if (alg != crypto_pwhash_ALG_ARGON2I13 # ifdef crypto_pwhash_ALG_ARGON2ID13 && alg != crypto_pwhash_ALG_ARGON2ID13 # endif && alg != crypto_pwhash_ALG_DEFAULT) { zend_throw_exception(sodium_exception_ce, "unsupported password hashing algorithm", 0); return; } if (passwd_len <= 0) { zend_error(E_WARNING, "empty password"); } if (salt_len != crypto_pwhash_SALTBYTES) { zend_throw_exception(sodium_exception_ce, "salt should be SODIUM_CRYPTO_PWHASH_SALTBYTES bytes", 0); return; } if (opslimit < crypto_pwhash_OPSLIMIT_MIN) { zend_throw_exception(sodium_exception_ce, "number of operations for the password hashing function is too low", 0); return; } if (memlimit < crypto_pwhash_MEMLIMIT_MIN) { zend_throw_exception(sodium_exception_ce, "maximum memory for the password hashing function is too low", 0); } hash = zend_string_alloc((size_t) hash_len, 0); ret = -1; # ifdef crypto_pwhash_ALG_ARGON2ID13 if (alg == crypto_pwhash_ALG_ARGON2ID13) { ret = crypto_pwhash_argon2id ((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len, passwd, (unsigned long long) passwd_len, salt, (unsigned long long) opslimit, (size_t) memlimit, (int) alg); } # endif if (ret == -1) { ret = crypto_pwhash ((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len, passwd, (unsigned long long) passwd_len, salt, (unsigned long long) opslimit, (size_t) memlimit, (int) alg); } if (ret != 0) { zend_string_efree(hash); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(hash)[hash_len] = 0; RETURN_NEW_STR(hash); } PHP_FUNCTION(sodium_crypto_pwhash_str) { zend_string *hash_str; char *passwd; zend_long memlimit; zend_long opslimit; size_t passwd_len; size_t len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sll", &passwd, &passwd_len, &opslimit, &memlimit) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (opslimit <= 0) { zend_throw_exception(sodium_exception_ce, "ops limit must be greater than 0", 0); return; } if (memlimit <= 0 || memlimit > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "memory limit must be greater than 0", 0); return; } if (passwd_len >= 0xffffffff) { zend_throw_exception(sodium_exception_ce, "unsupported password length", 0); return; } if (passwd_len <= 0) { zend_error(E_WARNING, "empty password"); } if (opslimit < crypto_pwhash_OPSLIMIT_MIN) { zend_throw_exception(sodium_exception_ce, "number of operations for the password hashing function is too low", 0); } if (memlimit < crypto_pwhash_MEMLIMIT_MIN) { zend_throw_exception(sodium_exception_ce, "maximum memory for the password hashing function is too low", 0); } hash_str = zend_string_alloc(crypto_pwhash_STRBYTES - 1, 0); if (crypto_pwhash_str (ZSTR_VAL(hash_str), passwd, (unsigned long long) passwd_len, (unsigned long long) opslimit, (size_t) memlimit) != 0) { zend_string_efree(hash_str); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(hash_str)[crypto_pwhash_STRBYTES - 1] = 0; len = strlen(ZSTR_VAL(hash_str)); PHP_SODIUM_ZSTR_TRUNCATE(hash_str, len); RETURN_NEW_STR(hash_str); } #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) PHP_FUNCTION(sodium_crypto_pwhash_str_needs_rehash) { char *hash_str; zend_long memlimit; zend_long opslimit; size_t hash_str_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sll", &hash_str, &hash_str_len, &opslimit, &memlimit) == FAILURE) { zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0); return; } if (crypto_pwhash_str_needs_rehash(hash_str, opslimit, memlimit) == 0) { RETURN_FALSE; } RETURN_TRUE; } #endif PHP_FUNCTION(sodium_crypto_pwhash_str_verify) { char *hash_str; char *passwd; size_t hash_str_len; size_t passwd_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &hash_str, &hash_str_len, &passwd, &passwd_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (passwd_len >= 0xffffffff) { zend_throw_exception(sodium_exception_ce, "unsupported password length", 0); return; } if (passwd_len <= 0) { zend_error(E_WARNING, "empty password"); } if (crypto_pwhash_str_verify (hash_str, passwd, (unsigned long long) passwd_len) == 0) { RETURN_TRUE; } RETURN_FALSE; } #endif #ifdef crypto_pwhash_scryptsalsa208sha256_SALTBYTES PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256) { zend_string *hash; unsigned char *salt; char *passwd; zend_long hash_len; zend_long memlimit; zend_long opslimit; size_t passwd_len; size_t salt_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "lssll", &hash_len, &passwd, &passwd_len, &salt, &salt_len, &opslimit, &memlimit) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (hash_len <= 0 || hash_len >= SIZE_MAX || hash_len > 0x1fffffffe0ULL) { zend_throw_exception(sodium_exception_ce, "hash length must be greater than 0", 0); return; } if (opslimit <= 0) { zend_throw_exception(sodium_exception_ce, "ops limit must be greater than 0", 0); return; } if (memlimit <= 0 || memlimit > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "memory limit must be greater than 0", 0); return; } if (passwd_len <= 0) { zend_error(E_WARNING, "empty password"); } if (salt_len != crypto_pwhash_scryptsalsa208sha256_SALTBYTES) { zend_throw_exception(sodium_exception_ce, "salt should be SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES bytes", 0); return; } if (opslimit < crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE) { zend_throw_exception(sodium_exception_ce, "number of operations for the scrypt function is too low", 0); } if (memlimit < crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) { zend_throw_exception(sodium_exception_ce, "maximum memory for the scrypt function is too low", 0); } hash = zend_string_alloc((size_t) hash_len, 0); if (crypto_pwhash_scryptsalsa208sha256 ((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len, passwd, (unsigned long long) passwd_len, salt, (unsigned long long) opslimit, (size_t) memlimit) != 0) { zend_string_efree(hash); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(hash)[hash_len] = 0; RETURN_NEW_STR(hash); } PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str) { zend_string *hash_str; char *passwd; zend_long memlimit; zend_long opslimit; size_t passwd_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sll", &passwd, &passwd_len, &opslimit, &memlimit) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (opslimit <= 0) { zend_throw_exception(sodium_exception_ce, "ops limit must be greater than 0", 0); return; } if (memlimit <= 0 || memlimit > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "memory limit must be greater than 0", 0); return; } if (passwd_len <= 0) { zend_error(E_WARNING, "empty password"); } if (opslimit < crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE) { zend_throw_exception(sodium_exception_ce, "number of operations for the scrypt function is too low", 0); } if (memlimit < crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) { zend_throw_exception(sodium_exception_ce, "maximum memory for the scrypt function is too low", 0); } hash_str = zend_string_alloc (crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1, 0); if (crypto_pwhash_scryptsalsa208sha256_str (ZSTR_VAL(hash_str), passwd, (unsigned long long) passwd_len, (unsigned long long) opslimit, (size_t) memlimit) != 0) { zend_string_efree(hash_str); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(hash_str)[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1] = 0; RETURN_NEW_STR(hash_str); } PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify) { char *hash_str; char *passwd; size_t hash_str_len; size_t passwd_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &hash_str, &hash_str_len, &passwd, &passwd_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (passwd_len <= 0) { zend_error(E_WARNING, "empty password"); } if (hash_str_len != crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1) { zend_error(E_WARNING, "wrong size for the hashed password"); RETURN_FALSE; } if (crypto_pwhash_scryptsalsa208sha256_str_verify (hash_str, passwd, (unsigned long long) passwd_len) == 0) { RETURN_TRUE; } RETURN_FALSE; } #endif PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available) { if (zend_parse_parameters_none() == FAILURE) { return; } #ifdef HAVE_AESGCM RETURN_BOOL(crypto_aead_aes256gcm_is_available()); #else RETURN_FALSE; #endif } #ifdef HAVE_AESGCM PHP_FUNCTION(sodium_crypto_aead_aes256gcm_encrypt) { zend_string *ciphertext; unsigned char *ad; unsigned char *msg; unsigned char *npub; unsigned char *secretkey; unsigned long long ciphertext_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &msg, &msg_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_aead_aes256gcm_ABYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } if ((unsigned long long) msg_len > (16ULL * ((1ULL << 32) - 2ULL)) - crypto_aead_aes256gcm_ABYTES) { zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0); return; } ciphertext_len = msg_len + crypto_aead_aes256gcm_ABYTES; ciphertext = zend_string_alloc((size_t) ciphertext_len, 0); if (crypto_aead_aes256gcm_encrypt ((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || ciphertext_real_len > ciphertext_len) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len); ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt) { zend_string *msg; unsigned char *ad; unsigned char *ciphertext; unsigned char *npub; unsigned char *secretkey; unsigned long long msg_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &ciphertext, &ciphertext_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES bytes", 0); return; } if (ciphertext_len < crypto_aead_aes256gcm_ABYTES) { RETURN_FALSE; } if (ciphertext_len - crypto_aead_aes256gcm_ABYTES > 16ULL * ((1ULL << 32) - 2ULL)) { zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0); return; } msg_len = ciphertext_len; if (msg_len >= SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } msg = zend_string_alloc((size_t) msg_len, 0); if (crypto_aead_aes256gcm_decrypt ((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL, ciphertext, (unsigned long long) ciphertext_len, ad, (unsigned long long) ad_len, npub, secretkey) != 0) { zend_string_efree(msg); RETURN_FALSE; } if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { zend_string_efree(msg); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len); ZSTR_VAL(msg)[msg_real_len] = 0; RETURN_NEW_STR(msg); } #endif PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_encrypt) { zend_string *ciphertext; unsigned char *ad; unsigned char *msg; unsigned char *npub; unsigned char *secretkey; unsigned long long ciphertext_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &msg, &msg_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_chacha20poly1305_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_ABYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } ciphertext_len = msg_len + crypto_aead_chacha20poly1305_ABYTES; ciphertext = zend_string_alloc((size_t) ciphertext_len, 0); if (crypto_aead_chacha20poly1305_encrypt ((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || ciphertext_real_len > ciphertext_len) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len); ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_decrypt) { zend_string *msg; unsigned char *ad; unsigned char *ciphertext; unsigned char *npub; unsigned char *secretkey; unsigned long long msg_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &ciphertext, &ciphertext_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_chacha20poly1305_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes", 0); return; } if (ciphertext_len < crypto_aead_chacha20poly1305_ABYTES) { RETURN_FALSE; } msg_len = ciphertext_len; if (msg_len >= SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } msg = zend_string_alloc((size_t) msg_len, 0); if (crypto_aead_chacha20poly1305_decrypt ((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL, ciphertext, (unsigned long long) ciphertext_len, ad, (unsigned long long) ad_len, npub, secretkey) != 0) { zend_string_efree(msg); RETURN_FALSE; } if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { zend_string_efree(msg); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len); ZSTR_VAL(msg)[msg_real_len] = 0; RETURN_NEW_STR(msg); } PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_encrypt) { zend_string *ciphertext; unsigned char *ad; unsigned char *msg; unsigned char *npub; unsigned char *secretkey; unsigned long long ciphertext_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &msg, &msg_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_chacha20poly1305_IETF_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_IETF_ABYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } if ((unsigned long long) msg_len > 64ULL * (1ULL << 32) - 64ULL) { zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0); return; } ciphertext_len = msg_len + crypto_aead_chacha20poly1305_IETF_ABYTES; ciphertext = zend_string_alloc((size_t) ciphertext_len, 0); if (crypto_aead_chacha20poly1305_ietf_encrypt ((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || ciphertext_real_len > ciphertext_len) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len); ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_decrypt) { zend_string *msg; unsigned char *ad; unsigned char *ciphertext; unsigned char *npub; unsigned char *secretkey; unsigned long long msg_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &ciphertext, &ciphertext_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_chacha20poly1305_IETF_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes", 0); return; } msg_len = ciphertext_len; if (msg_len >= SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } if (ciphertext_len < crypto_aead_chacha20poly1305_IETF_ABYTES) { RETURN_FALSE; } if ((unsigned long long) ciphertext_len - crypto_aead_chacha20poly1305_IETF_ABYTES > 64ULL * (1ULL << 32) - 64ULL) { zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0); return; } msg = zend_string_alloc((size_t) msg_len, 0); if (crypto_aead_chacha20poly1305_ietf_decrypt ((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL, ciphertext, (unsigned long long) ciphertext_len, ad, (unsigned long long) ad_len, npub, secretkey) != 0) { zend_string_efree(msg); RETURN_FALSE; } if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { zend_string_efree(msg); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len); ZSTR_VAL(msg)[msg_real_len] = 0; RETURN_NEW_STR(msg); } #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt) { zend_string *ciphertext; unsigned char *ad; unsigned char *msg; unsigned char *npub; unsigned char *secretkey; unsigned long long ciphertext_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &msg, &msg_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES bytes", 0); return; } if (SIZE_MAX - msg_len <= crypto_aead_xchacha20poly1305_IETF_ABYTES) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } ciphertext_len = msg_len + crypto_aead_xchacha20poly1305_IETF_ABYTES; ciphertext = zend_string_alloc((size_t) ciphertext_len, 0); if (crypto_aead_xchacha20poly1305_ietf_encrypt ((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || ciphertext_real_len > ciphertext_len) { zend_string_efree(ciphertext); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len); ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0; RETURN_NEW_STR(ciphertext); } PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt) { zend_string *msg; unsigned char *ad; unsigned char *ciphertext; unsigned char *npub; unsigned char *secretkey; unsigned long long msg_real_len; size_t ad_len; size_t ciphertext_len; size_t msg_len; size_t npub_len; size_t secretkey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ssss", &ciphertext, &ciphertext_len, &ad, &ad_len, &npub, &npub_len, &secretkey, &secretkey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) { zend_throw_exception(sodium_exception_ce, "public nonce size should be " "SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes", 0); return; } if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "secret key size should be " "SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES bytes", 0); return; } if (ciphertext_len < crypto_aead_xchacha20poly1305_IETF_ABYTES) { RETURN_FALSE; } msg_len = ciphertext_len; if (msg_len - crypto_aead_xchacha20poly1305_IETF_ABYTES >= SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } if ((unsigned long long) ciphertext_len - crypto_aead_xchacha20poly1305_IETF_ABYTES > 64ULL * (1ULL << 32) - 64ULL) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } msg = zend_string_alloc((size_t) msg_len, 0); if (crypto_aead_xchacha20poly1305_ietf_decrypt ((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL, ciphertext, (unsigned long long) ciphertext_len, ad, (unsigned long long) ad_len, npub, secretkey) != 0) { zend_string_efree(msg); RETURN_FALSE; } if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { zend_string_efree(msg); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len); ZSTR_VAL(msg)[msg_real_len] = 0; RETURN_NEW_STR(msg); } #endif PHP_FUNCTION(sodium_bin2hex) { zend_string *hex; unsigned char *bin; size_t bin_len; size_t hex_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &bin, &bin_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (bin_len >= SIZE_MAX / 2U) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } hex_len = bin_len * 2U; hex = zend_string_alloc((size_t) hex_len, 0); sodium_bin2hex(ZSTR_VAL(hex), hex_len + 1U, bin, bin_len); ZSTR_VAL(hex)[hex_len] = 0; RETURN_STR(hex); } PHP_FUNCTION(sodium_hex2bin) { zend_string *bin; const char *end; char *hex; char *ignore = NULL; size_t bin_real_len; size_t bin_len; size_t hex_len; size_t ignore_len = 0; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s|s", &hex, &hex_len, &ignore, &ignore_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } bin_len = hex_len / 2; bin = zend_string_alloc(bin_len, 0); if (sodium_hex2bin((unsigned char *) ZSTR_VAL(bin), bin_len, hex, hex_len, ignore, &bin_real_len, &end) != 0 || end != hex + hex_len) { zend_string_efree(bin); zend_throw_exception(sodium_exception_ce, "invalid hex string", 0); return; } if (bin_real_len >= SIZE_MAX || bin_real_len > bin_len) { zend_string_efree(bin); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len); ZSTR_VAL(bin)[bin_real_len] = 0; RETURN_NEW_STR(bin); } #ifdef sodium_base64_VARIANT_ORIGINAL PHP_FUNCTION(sodium_bin2base64) { zend_string *b64; unsigned char *bin; zend_long variant; size_t bin_len; size_t b64_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sl", &bin, &bin_len, &variant) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { zend_throw_exception(sodium_exception_ce, "invalid base64 variant identifier", 0); return; } if (bin_len >= SIZE_MAX / 4U * 3U - 3U - 1U) { zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } b64_len = sodium_base64_ENCODED_LEN(bin_len, variant); b64 = zend_string_alloc((size_t) b64_len - 1U, 0); sodium_bin2base64(ZSTR_VAL(b64), b64_len, bin, bin_len, (int) variant); RETURN_STR(b64); } PHP_FUNCTION(sodium_base642bin) { zend_string *bin; char *b64; const char *end; char *ignore = NULL; zend_long variant; size_t bin_real_len; size_t bin_len; size_t b64_len; size_t ignore_len = 0; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sl|s", &b64, &b64_len, &variant, &ignore, &ignore_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { zend_throw_exception(sodium_exception_ce, "invalid base64 variant identifier", 0); return; } bin_len = b64_len / 4U * 3U + 2U; bin = zend_string_alloc(bin_len, 0); if (sodium_base642bin((unsigned char *) ZSTR_VAL(bin), bin_len, b64, b64_len, ignore, &bin_real_len, &end, (int) variant) != 0 || end != b64 + b64_len) { zend_string_efree(bin); zend_throw_exception(sodium_exception_ce, "invalid base64 string", 0); return; } if (bin_real_len >= SIZE_MAX || bin_real_len > bin_len) { zend_string_efree(bin); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len); ZSTR_VAL(bin)[bin_real_len] = 0; RETURN_NEW_STR(bin); } #endif PHP_FUNCTION(sodium_crypto_scalarmult) { zend_string *q; unsigned char *n; unsigned char *p; size_t n_len; size_t p_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &n, &n_len, &p, &p_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (n_len != crypto_scalarmult_SCALARBYTES || p_len != crypto_scalarmult_BYTES) { zend_throw_exception(sodium_exception_ce, "scalar and point must be " "SODIUM_CRYPTO_SCALARMULT_SCALARBYTES bytes", 0); return; } q = zend_string_alloc(crypto_scalarmult_BYTES, 0); if (crypto_scalarmult((unsigned char *) ZSTR_VAL(q), n, p) != 0) { zend_string_efree(q); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0; RETURN_NEW_STR(q); } PHP_FUNCTION(sodium_crypto_kx_seed_keypair) { unsigned char *sk; unsigned char *pk; unsigned char *seed; size_t seed_len; zend_string *keypair; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &seed, &seed_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (seed_len != crypto_kx_SEEDBYTES) { zend_throw_exception(sodium_exception_ce, "seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes", 0); return; } (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]); (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]); keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0); sk = (unsigned char *) ZSTR_VAL(keypair); pk = sk + crypto_kx_SECRETKEYBYTES; crypto_generichash(sk, crypto_kx_SECRETKEYBYTES, seed, crypto_kx_SEEDBYTES, NULL, 0); if (crypto_scalarmult_base(pk, sk) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0; RETURN_STR(keypair); } PHP_FUNCTION(sodium_crypto_kx_keypair) { unsigned char *sk; unsigned char *pk; zend_string *keypair; if (zend_parse_parameters_none() == FAILURE) { return; } keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0); sk = (unsigned char *) ZSTR_VAL(keypair); pk = sk + crypto_kx_SECRETKEYBYTES; randombytes_buf(sk, crypto_kx_SECRETKEYBYTES); if (crypto_scalarmult_base(pk, sk) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0; RETURN_STR(keypair); } PHP_FUNCTION(sodium_crypto_kx_secretkey) { zend_string *secretkey; unsigned char *keypair; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes", 0); return; } secretkey = zend_string_alloc(crypto_kx_SECRETKEYBYTES, 0); memcpy(ZSTR_VAL(secretkey), keypair, crypto_kx_SECRETKEYBYTES); ZSTR_VAL(secretkey)[crypto_kx_SECRETKEYBYTES] = 0; RETURN_STR(secretkey); } PHP_FUNCTION(sodium_crypto_kx_publickey) { zend_string *publickey; unsigned char *keypair; size_t keypair_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &keypair, &keypair_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes", 0); return; } publickey = zend_string_alloc(crypto_kx_PUBLICKEYBYTES, 0); memcpy(ZSTR_VAL(publickey), keypair + crypto_kx_SECRETKEYBYTES, crypto_kx_PUBLICKEYBYTES); ZSTR_VAL(publickey)[crypto_kx_PUBLICKEYBYTES] = 0; RETURN_STR(publickey); } PHP_FUNCTION(sodium_crypto_kx_client_session_keys) { crypto_generichash_state h; unsigned char q[crypto_scalarmult_BYTES]; unsigned char *keypair; unsigned char *client_sk; unsigned char *client_pk; unsigned char *server_pk; unsigned char session_keys[2 * crypto_kx_SESSIONKEYBYTES]; size_t keypair_len; size_t server_pk_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &keypair, &keypair_len, &server_pk, &server_pk_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes", 0); return; } if (server_pk_len != crypto_kx_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes", 0); return; } client_sk = &keypair[0]; client_pk = &keypair[crypto_kx_SECRETKEYBYTES]; (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]); (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]); if (crypto_scalarmult(q, client_sk, server_pk) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES); crypto_generichash_update(&h, q, sizeof q); sodium_memzero(q, sizeof q); crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES); crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES); crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES); sodium_memzero(&h, sizeof h); array_init(return_value); add_next_index_stringl(return_value, (const char *) session_keys, crypto_kx_SESSIONKEYBYTES); add_next_index_stringl(return_value, (const char *) session_keys + crypto_kx_SESSIONKEYBYTES, crypto_kx_SESSIONKEYBYTES); } PHP_FUNCTION(sodium_crypto_kx_server_session_keys) { crypto_generichash_state h; unsigned char q[crypto_scalarmult_BYTES]; unsigned char *keypair; unsigned char *server_sk; unsigned char *server_pk; unsigned char *client_pk; unsigned char session_keys[2 * crypto_kx_SESSIONKEYBYTES]; size_t keypair_len; size_t client_pk_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &keypair, &keypair_len, &client_pk, &client_pk_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "keypair must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes", 0); return; } if (client_pk_len != crypto_kx_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes", 0); return; } server_sk = &keypair[0]; server_pk = &keypair[crypto_kx_SECRETKEYBYTES]; (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]); (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]); if (crypto_scalarmult(q, server_sk, client_pk) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES); crypto_generichash_update(&h, q, sizeof q); sodium_memzero(q, sizeof q); crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES); crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES); crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES); sodium_memzero(&h, sizeof h); array_init(return_value); add_next_index_stringl(return_value, (const char *) session_keys + crypto_kx_SESSIONKEYBYTES, crypto_kx_SESSIONKEYBYTES); add_next_index_stringl(return_value, (const char *) session_keys, crypto_kx_SESSIONKEYBYTES); } PHP_FUNCTION(sodium_crypto_auth) { zend_string *mac; char *key; char *msg; size_t msg_len; size_t key_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &msg, &msg_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (key_len != crypto_auth_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes", 0); return; } mac = zend_string_alloc(crypto_auth_BYTES, 0); if (crypto_auth((unsigned char *) ZSTR_VAL(mac), (const unsigned char *) msg, msg_len, (const unsigned char *) key) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } ZSTR_VAL(mac)[crypto_auth_BYTES] = 0; RETURN_STR(mac); } PHP_FUNCTION(sodium_crypto_auth_verify) { char *mac; char *key; char *msg; size_t mac_len; size_t msg_len; size_t key_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sss", &mac, &mac_len, &msg, &msg_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (key_len != crypto_auth_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes", 0); return; } if (mac_len != crypto_auth_BYTES) { zend_throw_exception(sodium_exception_ce, "authentication tag must be SODIUM_CRYPTO_AUTH_BYTES bytes", 0); return; } if (crypto_auth_verify((const unsigned char *) mac, (const unsigned char *) msg, msg_len, (const unsigned char *) key) != 0) { RETURN_FALSE; } RETURN_TRUE; } PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519) { zend_string *ecdhkey; char *eddsakey; size_t eddsakey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &eddsakey, &eddsakey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (eddsakey_len != crypto_sign_SECRETKEYBYTES) { zend_throw_exception(sodium_exception_ce, "Ed25519 key should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes", 0); return; } ecdhkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0); if (crypto_sign_ed25519_sk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey), (const unsigned char *) eddsakey) != 0) { zend_throw_exception(sodium_exception_ce, "conversion failed", 0); return; } ZSTR_VAL(ecdhkey)[crypto_box_SECRETKEYBYTES] = 0; RETURN_STR(ecdhkey); } PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519) { zend_string *ecdhkey; char *eddsakey; size_t eddsakey_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &eddsakey, &eddsakey_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (eddsakey_len != crypto_sign_PUBLICKEYBYTES) { zend_throw_exception(sodium_exception_ce, "Ed25519 key should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes", 0); return; } ecdhkey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0); if (crypto_sign_ed25519_pk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey), (const unsigned char *) eddsakey) != 0) { zend_throw_exception(sodium_exception_ce, "conversion failed", 0); return; } ZSTR_VAL(ecdhkey)[crypto_box_PUBLICKEYBYTES] = 0; RETURN_STR(ecdhkey); } PHP_FUNCTION(sodium_compare) { char *buf1; char *buf2; size_t len1; size_t len2; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &buf1, &len1, &buf2, &len2) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (len1 != len2) { zend_throw_exception(sodium_exception_ce, "arguments have different sizes", 0); return; } else { RETURN_LONG(sodium_compare((const unsigned char *) buf1, (const unsigned char *) buf2, (size_t) len1)); } } #ifdef HAVE_AESGCM PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen) { unsigned char key[crypto_aead_aes256gcm_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } #endif PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen) { unsigned char key[crypto_aead_chacha20poly1305_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen) { unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen) { unsigned char key[crypto_aead_xchacha20poly1305_IETF_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } #endif PHP_FUNCTION(sodium_crypto_auth_keygen) { unsigned char key[crypto_auth_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_generichash_keygen) { unsigned char key[crypto_generichash_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_kdf_keygen) { unsigned char key[crypto_kdf_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_secretbox_keygen) { unsigned char key[crypto_secretbox_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_shorthash_keygen) { unsigned char key[crypto_shorthash_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_stream_keygen) { unsigned char key[crypto_stream_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_kdf_derive_from_key) { unsigned char ctx_padded[crypto_generichash_blake2b_PERSONALBYTES]; #ifndef crypto_kdf_PRIMITIVE unsigned char salt[crypto_generichash_blake2b_SALTBYTES]; #endif char *ctx; char *key; zend_string *subkey; zend_long subkey_id; zend_long subkey_len; size_t ctx_len; size_t key_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "llss", &subkey_len, &subkey_id, &ctx, &ctx_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (subkey_len < crypto_kdf_BYTES_MIN) { zend_throw_exception(sodium_exception_ce, "subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN", 0); return; } if (subkey_len > crypto_kdf_BYTES_MAX || subkey_len > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX", 0); return; } if (subkey_id < 0) { zend_throw_exception(sodium_exception_ce, "subkey_id cannot be negative", 0); return; } if (ctx_len != crypto_kdf_CONTEXTBYTES) { zend_throw_exception(sodium_exception_ce, "context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes", 0); return; } if (key_len != crypto_kdf_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes", 0); return; } memcpy(ctx_padded, ctx, crypto_kdf_CONTEXTBYTES); memset(ctx_padded + crypto_kdf_CONTEXTBYTES, 0, sizeof ctx_padded - crypto_kdf_CONTEXTBYTES); subkey = zend_string_alloc((size_t) subkey_len, 0); #ifdef crypto_kdf_PRIMITIVE crypto_kdf_derive_from_key((unsigned char *) ZSTR_VAL(subkey), (size_t) subkey_len, (uint64_t) subkey_id, ctx, (const unsigned char *) key); #else salt[0] = (unsigned char) (((uint64_t) subkey_id) ); salt[1] = (unsigned char) (((uint64_t) subkey_id) >> 8); salt[2] = (unsigned char) (((uint64_t) subkey_id) >> 16); salt[3] = (unsigned char) (((uint64_t) subkey_id) >> 24); salt[4] = (unsigned char) (((uint64_t) subkey_id) >> 32); salt[5] = (unsigned char) (((uint64_t) subkey_id) >> 40); salt[6] = (unsigned char) (((uint64_t) subkey_id) >> 48); salt[7] = (unsigned char) (((uint64_t) subkey_id) >> 56); memset(salt + 8, 0, (sizeof salt) - 8); crypto_generichash_blake2b_salt_personal((unsigned char *) ZSTR_VAL(subkey), (size_t) subkey_len, NULL, 0, (const unsigned char *) key, crypto_kdf_KEYBYTES, salt, ctx_padded); #endif ZSTR_VAL(subkey)[subkey_len] = 0; RETURN_STR(subkey); } PHP_FUNCTION(sodium_pad) { zend_string *padded; char *unpadded; zend_long blocksize; volatile size_t st; size_t i, j, k; size_t unpadded_len; size_t xpadlen; size_t xpadded_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sl", &unpadded, &unpadded_len, &blocksize) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (blocksize <= 0) { zend_throw_exception(sodium_exception_ce, "block size cannot be less than 1", 0); return; } if (blocksize > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "block size is too large", 0); return; } xpadlen = blocksize - 1U; if ((blocksize & (blocksize - 1U)) == 0U) { xpadlen -= unpadded_len & ((size_t) blocksize - 1U); } else { xpadlen -= unpadded_len % (size_t) blocksize; } if ((size_t) SIZE_MAX - unpadded_len <= xpadlen) { zend_throw_exception(sodium_exception_ce, "input is too large", 0); return; } xpadded_len = unpadded_len + xpadlen; padded = zend_string_alloc(xpadded_len + 1U, 0); if (unpadded_len > 0) { st = 1U; i = 0U; k = unpadded_len; for (j = 0U; j <= xpadded_len; j++) { ZSTR_VAL(padded)[j] = unpadded[i]; k -= st; st = (size_t) (~(((( (((uint64_t) k) >> 48) | (((uint64_t) k) >> 32) | (k >> 16) | k) & 0xffff) - 1U) >> 16)) & 1U; i += st; } } #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) if (sodium_pad(NULL, (unsigned char *) ZSTR_VAL(padded), unpadded_len, (size_t) blocksize, xpadded_len + 1U) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } #else { char *tail; volatile unsigned char mask; unsigned char barrier_mask; tail = &ZSTR_VAL(padded)[xpadded_len]; mask = 0U; for (i = 0; i < blocksize; i++) { barrier_mask = (unsigned char) (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT)); tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask); mask |= barrier_mask; } } #endif ZSTR_VAL(padded)[xpadded_len + 1U] = 0; RETURN_STR(padded); } PHP_FUNCTION(sodium_unpad) { zend_string *unpadded; char *padded; size_t padded_len; size_t unpadded_len; zend_long blocksize; int ret; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "sl", &padded, &padded_len, &blocksize) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (blocksize <= 0) { zend_throw_exception(sodium_exception_ce, "block size cannot be less than 1", 0); return; } if (blocksize > SIZE_MAX) { zend_throw_exception(sodium_exception_ce, "block size is too large", 0); return; } if (padded_len < blocksize) { zend_throw_exception(sodium_exception_ce, "invalid padding", 0); return; } #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) ret = sodium_unpad(&unpadded_len, (const unsigned char *) padded, padded_len, (size_t) blocksize); #else { const char *tail; unsigned char acc = 0U; unsigned char c; unsigned char valid = 0U; volatile size_t pad_len = 0U; size_t i; size_t is_barrier; tail = &padded[padded_len - 1U]; for (i = 0U; i < (size_t) blocksize; i++) { c = tail[-i]; is_barrier = (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U; acc |= c; pad_len |= i & (1U + ~is_barrier); valid |= (unsigned char) is_barrier; } unpadded_len = padded_len - 1U - pad_len; ret = (int) (valid - 1U); } #endif if (ret != 0 || unpadded_len > LONG_MAX) { zend_throw_exception(sodium_exception_ce, "invalid padding", 0); return; } unpadded = zend_string_init(padded, padded_len, 0); PHP_SODIUM_ZSTR_TRUNCATE(unpadded, unpadded_len); ZSTR_VAL(unpadded)[unpadded_len] = 0; RETURN_STR(unpadded); } #ifdef crypto_secretstream_xchacha20poly1305_ABYTES PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen) { unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]; if (zend_parse_parameters_none() == FAILURE) { return; } randombytes_buf(key, sizeof key); RETURN_STRINGL((const char *) key, sizeof key); } PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push) { crypto_secretstream_xchacha20poly1305_state state; unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; unsigned char *key; size_t key_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes", 0); return; } if (crypto_secretstream_xchacha20poly1305_init_push(&state, header, key) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } array_init(return_value); add_next_index_stringl(return_value, (const char *) &state, sizeof state); add_next_index_stringl(return_value, (const char *) header, sizeof header); } PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push) { zval *state_zv; zend_string *c; unsigned char *ad = NULL; unsigned char *msg; unsigned char *state; unsigned long long c_real_len; zend_long tag = crypto_secretstream_xchacha20poly1305_TAG_MESSAGE; size_t ad_len = (size_t) 0U; size_t c_len; size_t msg_len; size_t state_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs|sl", &state_zv, &msg, &msg_len, &ad, &ad_len, &tag) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(state_zv); if (Z_TYPE_P(state_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a reference to a state is required", 0); return; } sodium_separate_string(state_zv); state = (unsigned char *) Z_STRVAL(*state_zv); state_len = Z_STRLEN(*state_zv); if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) { zend_throw_exception(sodium_exception_ce, "incorrect state length", 0); return; } if (msg_len > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX || msg_len > SIZE_MAX - crypto_secretstream_xchacha20poly1305_ABYTES) { zend_throw_exception(sodium_exception_ce, "message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes", 0); return; } if (tag < 0 || tag > 255) { zend_throw_exception(sodium_exception_ce, "unsupported value for the tag", 0); return; } c_len = msg_len + crypto_secretstream_xchacha20poly1305_ABYTES; c = zend_string_alloc((size_t) c_len, 0); if (crypto_secretstream_xchacha20poly1305_push ((void *) state, (unsigned char *) ZSTR_VAL(c), &c_real_len, msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len, (unsigned char) tag) != 0) { zend_string_efree(c); zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } if (c_real_len <= 0U || c_real_len >= SIZE_MAX || c_real_len > c_len) { zend_string_efree(c); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(c, (size_t) c_real_len); ZSTR_VAL(c)[c_real_len] = 0; RETURN_NEW_STR(c); } PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull) { crypto_secretstream_xchacha20poly1305_state state; unsigned char *header; unsigned char *key; size_t header_len; size_t key_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss", &header, &header_len, &key, &key_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } if (header_len != crypto_secretstream_xchacha20poly1305_HEADERBYTES) { zend_throw_exception(sodium_exception_ce, "header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes", 0); return; } if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) { zend_throw_exception(sodium_exception_ce, "key size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes", 0); return; } if (crypto_secretstream_xchacha20poly1305_init_pull(&state, header, key) != 0) { zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } RETURN_STRINGL((const char *) &state, sizeof state); } PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull) { zval *state_zv; zend_string *msg; unsigned char *ad = NULL; unsigned char *c; unsigned char *state; unsigned long long msg_real_len; size_t ad_len = (size_t) 0U; size_t msg_len; size_t c_len; size_t state_len; unsigned char tag; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs|s", &state_zv, &c, &c_len, &ad, &ad_len) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(state_zv); if (Z_TYPE_P(state_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a reference to a state is required", 0); return; } sodium_separate_string(state_zv); state = (unsigned char *) Z_STRVAL(*state_zv); state_len = Z_STRLEN(*state_zv); if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) { zend_throw_exception(sodium_exception_ce, "incorrect state length", 0); return; } if (c_len < crypto_secretstream_xchacha20poly1305_ABYTES) { RETURN_FALSE; } msg_len = c_len - crypto_secretstream_xchacha20poly1305_ABYTES; msg = zend_string_alloc((size_t) msg_len, 0); if (crypto_secretstream_xchacha20poly1305_pull ((void *) state, (unsigned char *) ZSTR_VAL(msg), &msg_real_len, &tag, c, (unsigned long long) c_len, ad, (unsigned long long) ad_len) != 0) { zend_string_efree(msg); RETURN_FALSE; } if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { zend_string_efree(msg); zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); return; } PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len); ZSTR_VAL(msg)[msg_real_len] = 0; array_init(return_value); add_next_index_str(return_value, msg); add_next_index_long(return_value, (long) tag); } PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey) { zval *state_zv; unsigned char *state; size_t state_len; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "z", &state_zv) == FAILURE) { sodium_remove_param_values_from_backtrace(EG(exception)); return; } ZVAL_DEREF(state_zv); if (Z_TYPE_P(state_zv) != IS_STRING) { zend_throw_exception(sodium_exception_ce, "a reference to a state is required", 0); return; } sodium_separate_string(state_zv); state = (unsigned char *) Z_STRVAL(*state_zv); state_len = Z_STRLEN(*state_zv); if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) { zend_throw_exception(sodium_exception_ce, "incorrect state length", 0); return; } crypto_secretstream_xchacha20poly1305_rekey((void *) state); } #endif