diff options
Diffstat (limited to 'ext/sodium')
25 files changed, 3838 insertions, 0 deletions
diff --git a/ext/sodium/CREDITS b/ext/sodium/CREDITS new file mode 100644 index 0000000000..02cd6984a1 --- /dev/null +++ b/ext/sodium/CREDITS @@ -0,0 +1,2 @@ +;; libsodium +Frank Denis [jedisct1@php.net] (lead) diff --git a/ext/sodium/README.md b/ext/sodium/README.md new file mode 100644 index 0000000000..104570a241 --- /dev/null +++ b/ext/sodium/README.md @@ -0,0 +1,13 @@ +[![Build Status](https://travis-ci.org/jedisct1/libsodium-php.svg?branch=master)](https://travis-ci.org/jedisct1/libsodium-php?branch=master) + +libsodium-php +============= + +A simple, low-level PHP extension for +[libsodium](https://github.com/jedisct1/libsodium). + +Full documentation here: +[Using Libsodium in PHP Projects](https://paragonie.com/book/pecl-libsodium), +a guide to using the libsodium PHP extension for modern, secure, and +fast cryptography. + diff --git a/ext/sodium/config.m4 b/ext/sodium/config.m4 new file mode 100644 index 0000000000..edb5cd67bc --- /dev/null +++ b/ext/sodium/config.m4 @@ -0,0 +1,68 @@ +dnl $Id$ +dnl config.m4 for extension sodium + +PHP_ARG_WITH(sodium, for sodium support, +[ --with-sodium Include sodium support]) + +PHP_ARG_WITH(libsodium, for libsodium library location, +[ --with-libsodium[[=DIR]] libsodium library location, else rely on pkg-config]) + +if test "$PHP_SODIUM" != "no"; then + SEARCH_PATH="/usr/local /usr" # you might want to change this + SEARCH_FOR="/include/sodium.h" # you most likely want to change this + + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + AC_MSG_CHECKING([for libsodium]) + + dnl user provided location + if test -r $PHP_LIBSODIUM/$SEARCH_FOR; then # path given as parameter + LIBSODIUM_DIR=$PHP_LIBSODIUM + AC_MSG_RESULT([found in $PHP_LIBSODIUM]) + + dnl pkg-config output + elif test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libsodium; then + LIBSODIUM_CFLAGS=`$PKG_CONFIG libsodium --cflags` + LIBSODIUM_LIBS=`$PKG_CONFIG libsodium --libs` + LIBSODIUM_VERSION=`$PKG_CONFIG libsodium --modversion` + AC_MSG_RESULT(version $LIBSODIUM_VERSION found using pkg-config) + PHP_EVAL_LIBLINE($LIBSODIUM_LIBS, SODIUM_SHARED_LIBADD) + PHP_EVAL_INCLINE($LIBSODIUM_CFLAGS) + + dnl search default path list + else + for i in $SEARCH_PATH ; do + if test -r $i/$SEARCH_FOR; then + LIBSODIUM_DIR=$i + AC_MSG_RESULT(found in $i) + fi + done + if test -z "$LIBSODIUM_DIR"; then + AC_MSG_ERROR([Please install libsodium - See https://github.com/jedisct1/libsodium]) + fi + fi + + LIBNAME=sodium + LIBSYMBOL=crypto_pwhash_scryptsalsa208sha256 + + if test -n "$LIBSODIUM_DIR"; then + PHP_ADD_INCLUDE($LIBSODIUM_DIR/include) + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $LIBSODIUM_DIR/$PHP_LIBDIR, SODIUM_SHARED_LIBADD) + fi + + PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, + [ + AC_DEFINE(HAVE_LIBSODIUMLIB,1,[ ]) + ],[ + AC_MSG_ERROR([wrong libsodium lib version or lib not found]) + ],[ + ]) + PHP_CHECK_LIBRARY($LIBNAME,crypto_aead_aes256gcm_encrypt, + [ + AC_DEFINE(HAVE_CRYPTO_AEAD_AES256GCM,1,[ ]) + ],[],[ + ]) + + PHP_SUBST(SODIUM_SHARED_LIBADD) + + PHP_NEW_EXTENSION(sodium, libsodium.c, $ext_shared) +fi diff --git a/ext/sodium/config.w32 b/ext/sodium/config.w32 new file mode 100644 index 0000000000..c1af4e65fb --- /dev/null +++ b/ext/sodium/config.w32 @@ -0,0 +1,14 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("sodium", "for libsodium support", "no"); + +if (PHP_SODIUM != "no") { + if (CHECK_LIB("libsodium.lib", "sodium", PHP_SODIUM) && CHECK_HEADER_ADD_INCLUDE("sodium.h", "CFLAGS_SODIUM")) { + EXTENSION("sodium", "libsodium.c"); + AC_DEFINE('HAVE_LIBSODIUMLIB', 1 , 'Have the Sodium library'); + PHP_INSTALL_HEADERS("ext/sodium/", "php_libsodium.h"); + } else { + WARNING("libsodium not enabled; libraries and headers not found"); + } +} diff --git a/ext/sodium/libsodium.c b/ext/sodium/libsodium.c new file mode 100644 index 0000000000..ae93e6dc58 --- /dev/null +++ b/ext/sodium/libsodium.c @@ -0,0 +1,2688 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2017 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: Andi Gutmans <andi@zend.com> | + | Zeev Suraski <zeev@zend.com> | + | Rasmus Lerdorf <rasmus@php.net> | + | Andrei Zmievski <andrei@php.net> | + | Stig Venaas <venaas@php.net> | + | Jason Greene <jason@php.net> | + +----------------------------------------------------------------------+ +*/ + +#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 <sodium.h> +#include <stdint.h> + +#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_FirstArgByReferenceSecondLength, 0, 0, 2) + ZEND_ARG_INFO(1, reference) + ZEND_ARG_INFO(0, length) +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_StringRef_And_String, 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_FourStrings, 0, 0, 3) + ZEND_ARG_INFO(0, string_1) + ZEND_ARG_INFO(0, string_2) + ZEND_ARG_INFO(0, string_3) + ZEND_ARG_INFO(0, string_4) +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_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) +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_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() + +#if defined(HAVE_CRYPTO_AEAD_AES256GCM) && defined(crypto_aead_aes256gcm_KEYBYTES) && \ + (defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(__i386__) || \ + defined(_M_AMD64) || defined(_M_IX86)) +# define HAVE_AESGCM 1 +#endif + +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) +#endif + PHP_FE(sodium_crypto_aead_chacha20poly1305_decrypt, AI_StringAndADAndNonceAndKey) + PHP_FE(sodium_crypto_aead_chacha20poly1305_encrypt, AI_StringAndADAndNonceAndKey) +#ifdef crypto_aead_chacha20poly1305_IETF_NPUBBYTES + PHP_FE(sodium_crypto_aead_chacha20poly1305_ietf_decrypt, AI_StringAndADAndNonceAndKey) + PHP_FE(sodium_crypto_aead_chacha20poly1305_ietf_encrypt, AI_StringAndADAndNonceAndKey) +#endif +#ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES + PHP_FE(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt, AI_StringAndADAndNonceAndKey) + PHP_FE(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt, AI_StringAndADAndNonceAndKey) +#endif + PHP_FE(sodium_crypto_auth, AI_StringAndKey) + 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) +#ifdef crypto_box_SEALBYTES + PHP_FE(sodium_crypto_box_seal, AI_StringAndKey) + PHP_FE(sodium_crypto_box_seal_open, AI_StringAndKey) +#endif + PHP_FE(sodium_crypto_box_secretkey, AI_Key) + PHP_FE(sodium_crypto_kx, AI_FourStrings) + PHP_FE(sodium_crypto_generichash, AI_StringAndMaybeKeyAndLength) + PHP_FE(sodium_crypto_generichash_init, AI_MaybeKeyAndLength) + PHP_FE(sodium_crypto_generichash_update, AI_StateByReferenceAndString) + PHP_FE(sodium_crypto_generichash_final, AI_StateByReferenceAndMaybeLength) +#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 + 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) + PHP_FE(sodium_crypto_scalarmult, AI_TwoStrings) + PHP_FE(sodium_crypto_secretbox, AI_StringAndNonceAndKey) + PHP_FE(sodium_crypto_secretbox_open, AI_StringAndNonceAndKey) + PHP_FE(sodium_crypto_shorthash, AI_StringAndKey) + 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_xor, AI_StringAndNonceAndKey) + PHP_FE(sodium_bin2hex, AI_String) +#if SODIUM_LIBRARY_VERSION_MAJOR > 7 || \ + (SODIUM_LIBRARY_VERSION_MAJOR == 7 && SODIUM_LIBRARY_VERSION_MINOR >= 6) + PHP_FE(sodium_compare, AI_TwoStrings) +#endif + PHP_FE(sodium_hex2bin, AI_TwoStrings) + PHP_FE(sodium_increment, AI_StringRef) + PHP_FE(sodium_add, AI_StringRef_And_String) + PHP_FE(sodium_memcmp, AI_TwoStrings) + PHP_FE(sodium_memzero, AI_FirstArgByReferenceSecondLength) + + PHP_FALIAS(sodium_crypto_scalarmult_base, sodium_crypto_box_publickey_from_secretkey, AI_TwoStrings) + + PHP_FE_END +}; + +zend_module_entry sodium_module_entry = { + STANDARD_MODULE_HEADER, + "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 + +static zend_object *sodium_exception_create_object(zend_class_entry *ce) { + zend_object *obj = zend_ce_exception->create_object(ce); + zval obj_zv, rv, *trace; + + /* Remove argument information from backtrace to prevent information leaks */ + ZVAL_OBJ(&obj_zv, obj); + trace = zend_read_property(zend_ce_exception, &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 && Z_TYPE_P(frame) == IS_ARRAY) { + zend_hash_clean(Z_ARRVAL_P(args)); + } + } + } ZEND_HASH_FOREACH_END(); + } + + 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); +#ifdef crypto_aead_chacha20poly1305_IETF_NPUBBYTES + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES", + crypto_aead_chacha20poly1305_KEYBYTES, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES", + crypto_aead_chacha20poly1305_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_ABYTES, CONST_CS | CONST_PERSISTENT); +#endif +#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); +#ifdef crypto_box_SEALBYTES + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_SEALBYTES", + crypto_box_SEALBYTES, CONST_CS | CONST_PERSISTENT); +#endif + 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); + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_BYTES", + crypto_kx_BYTES, 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_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_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 + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES", + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, CONST_CS | CONST_PERSISTENT); +#ifndef crypto_pwhash_scryptsalsa208sha256_STRPREFIX +# define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" +#endif + 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); + 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); + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(sodium) +{ + return SUCCESS; +} + +PHP_MINFO_FUNCTION(sodium) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "sodium support", "enabled"); + php_info_print_table_header(2, "libsodium headers version", SODIUM_VERSION_STRING); + php_info_print_table_header(2, "libsodium library version", sodium_version_string()); + php_info_print_table_end(); +} + +PHP_FUNCTION(sodium_memzero) +{ + zval *buf_zv; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), + "z", &buf_zv) == FAILURE) { + return; + } + ZVAL_DEREF(buf_zv); + if (Z_TYPE_P(buf_zv) != IS_STRING) { + zend_throw_exception(sodium_exception_ce, "memzero: 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 i; + size_t val_len; + unsigned int c; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), + "z", &val_zv) == FAILURE) { + return; + } + ZVAL_DEREF(val_zv); + if (Z_TYPE_P(val_zv) != IS_STRING) { + zend_throw_exception(sodium_exception_ce, "increment(): 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); + c = 1U << 8; + for (i = (size_t) 0U; i < val_len; i++) { + c >>= 8; + c += val[i]; + val[i] = (unsigned char) c; + } +} + +PHP_FUNCTION(sodium_add) +{ + zval *val_zv; + unsigned char *val; + unsigned char *addv; + size_t i; + size_t val_len; + size_t addv_len; + unsigned int c; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), + "zs", &val_zv, &addv, &addv_len) == FAILURE) { + return; + } + ZVAL_DEREF(val_zv); + if (Z_TYPE_P(val_zv) != IS_STRING) { + zend_throw_exception(sodium_exception_ce, "add(): 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, "add(): values must have the same length", 0); + return; + } + c = 0U; + for (i = (size_t) 0U; i < val_len; i++) { + c += val[i] + addv[i]; + val[i] = (unsigned char) c; + c >>= 8; + } +} + +PHP_FUNCTION(sodium_memcmp) +{ + char *buf1; + char *buf2; + size_t len1; + size_t len2; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", + &buf1, &len1, + &buf2, &len2) == FAILURE) { + return; + } + if (len1 != len2) { + zend_throw_exception(sodium_exception_ce, "memcmp(): arguments have different sizes", 0); + } else { + 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(ZEND_NUM_ARGS(), "ss", + &msg, &msg_len, + &key, &key_len) == FAILURE) { + return; + } + if (key_len != crypto_shorthash_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_shorthash(): key size should be " + "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_free(hash); + zend_throw_exception(sodium_exception_ce, "crypto_shorthash(): internal error", 0); + return; + } + ZSTR_VAL(hash)[crypto_shorthash_BYTES] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "sss", + &msg, &msg_len, + &nonce, &nonce_len, + &key, &key_len) == FAILURE) { + return; + } + if (nonce_len != crypto_secretbox_NONCEBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_secretbox(): nonce size should be " + "CRYPTO_SECRETBOX_NONCEBYTES bytes", + 0); + return; + } + if (key_len != crypto_secretbox_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_secretbox(): key size should be " + "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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_secretbox(): internal error", 0); + return; + } + ZSTR_VAL(ciphertext)[msg_len + crypto_secretbox_MACBYTES] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "sss", + &ciphertext, &ciphertext_len, + &nonce, &nonce_len, + &key, &key_len) == FAILURE) { + return; + } + if (nonce_len != crypto_secretbox_NONCEBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_secretbox_open(): nonce size should be " + "CRYPTO_SECRETBOX_NONCEBYTES bytes", + 0); + return; + } + if (key_len != crypto_secretbox_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_secretbox_open(): key size should be " + "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_free(msg); + RETURN_FALSE; + } else { + ZSTR_VAL(msg)[ciphertext_len - crypto_secretbox_MACBYTES] = 0; + RETURN_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(ZEND_NUM_ARGS(), "s|sl", + &msg, &msg_len, + &key, &key_len, + &hash_len) == FAILURE) { + return; + } + if (hash_len < crypto_generichash_BYTES_MIN || + hash_len > crypto_generichash_BYTES_MAX) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash(): 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, "crypto_generichash(): 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_free(hash); + zend_throw_exception(sodium_exception_ce, "crypto_generichash(): internal error", 0); + return; + } + ZSTR_VAL(hash)[hash_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "|sl", + &key, &key_len, + &hash_len) == FAILURE) { + return; + } + if (hash_len < crypto_generichash_BYTES_MIN || + hash_len > crypto_generichash_BYTES_MAX) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash_init(): 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, "crypto_generichash_init(): unsupported key length", 0); + return; + } + if (crypto_generichash_init((void *) &state_tmp, key, (size_t) key_len, + (size_t) hash_len) != 0) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash_init(): 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(ZEND_NUM_ARGS(), "zs", + &state_zv, &msg, &msg_len) == FAILURE) { + return; + } + ZVAL_DEREF(state_zv); + if (Z_TYPE_P(state_zv) != IS_STRING) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash_update: 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, "crypto_generichash_update(): 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) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash_update(): 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(ZEND_NUM_ARGS(), "z|l", + &state_zv, &hash_len) == FAILURE) { + return; + } + ZVAL_DEREF(state_zv); + if (Z_TYPE_P(state_zv) != IS_STRING) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash_final: 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, "crypto_generichash_final(): incorrect state length", 0); + return; + } + if (hash_len < crypto_generichash_BYTES_MIN || + hash_len > crypto_generichash_BYTES_MAX) { + zend_throw_exception(sodium_exception_ce, "crypto_generichash_final(): 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) { + zend_string_free(hash); + zend_throw_exception(sodium_exception_ce, "crypto_generichash_final(): internal error", 0); + return; + } + sodium_memzero(state, state_len); + convert_to_null(state_zv); + ZSTR_VAL(hash)[hash_len] = 0; + + RETURN_STR(hash); +} + +PHP_FUNCTION(sodium_crypto_box_keypair) +{ + zend_string *keypair; + size_t keypair_len; + + 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_free(keypair); + zend_throw_exception(sodium_exception_ce, "crypto_box_keypair(): internal error", 0); + return; + } + ZSTR_VAL(keypair)[keypair_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "s", + &seed, &seed_len) == FAILURE) { + return; + } + if (seed_len != crypto_box_SEEDBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_seed_keypair(): " + "seed should be 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_free(keypair); + zend_throw_exception(sodium_exception_ce, "crypto_box_seed_keypair(): internal error", 0); + return; + } + ZSTR_VAL(keypair)[keypair_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "ss", + &secretkey, &secretkey_len, + &publickey, &publickey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_box_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_keypair_from_secretkey_and_publickey(): " + "secretkey should be CRYPTO_BOX_SECRETKEYBYTES bytes", + 0); + return; + } + if (publickey_len != crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_keypair_from_secretkey_and_publickey(): " + "publickey should be 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(ZEND_NUM_ARGS(), "s", + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != + crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_secretkey(): keypair should be " + "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(ZEND_NUM_ARGS(), "s", + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != + crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_publickey(): keypair should be " + "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(ZEND_NUM_ARGS(), "s", + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_box_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_publickey_from_secretkey(): key should be " + "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(ZEND_NUM_ARGS(), "sss", + &msg, &msg_len, + &nonce, &nonce_len, + &keypair, &keypair_len) == FAILURE) { + return; + } + if (nonce_len != crypto_box_NONCEBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box(): nonce size should be " + "CRYPTO_BOX_NONCEBYTES bytes", + 0); + return; + } + if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box(): keypair size should be " + "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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_box(): internal error", 0); + return; + } + ZSTR_VAL(ciphertext)[msg_len + crypto_box_MACBYTES] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "sss", + &ciphertext, &ciphertext_len, + &nonce, &nonce_len, + &keypair, &keypair_len) == FAILURE) { + return; + } + if (nonce_len != crypto_box_NONCEBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_open(): nonce size should be " + "CRYPTO_BOX_NONCEBYTES bytes", + 0); + return; + } + if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_open(): keypair size should be " + "CRYPTO_BOX_KEYBYTES 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_free(msg); + RETURN_FALSE; + } else { + ZSTR_VAL(msg)[ciphertext_len - crypto_box_MACBYTES] = 0; + RETURN_STR(msg); + } +} + +#ifdef crypto_box_SEALBYTES +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(ZEND_NUM_ARGS(), "ss", + &msg, &msg_len, + &publickey, &publickey_len) == FAILURE) { + return; + } + if (publickey_len != crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_seal(): public key size should be " + "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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_box_seal(): internal error", 0); + return; + } + ZSTR_VAL(ciphertext)[msg_len + crypto_box_SEALBYTES] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "ss", + &ciphertext, &ciphertext_len, + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_box_seal_open(): keypair size should be " + "CRYPTO_BOX_KEYBYTES 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_free(msg); + RETURN_FALSE; + } else { + ZSTR_VAL(msg)[ciphertext_len - crypto_box_SEALBYTES] = 0; + RETURN_STR(msg); + } +} +#endif + +PHP_FUNCTION(sodium_crypto_sign_keypair) +{ + zend_string *keypair; + size_t keypair_len; + + 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_free(keypair); + zend_throw_exception(sodium_exception_ce, "crypto_sign_keypair(): internal error", 0); + return; + } + ZSTR_VAL(keypair)[keypair_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "s", + &seed, &seed_len) == FAILURE) { + return; + } + if (seed_len != crypto_sign_SEEDBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_seed_keypair(): " + "seed should be 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_free(keypair); + zend_throw_exception(sodium_exception_ce, "crypto_sign_seed_keypair(): internal error", 0); + return; + } + ZSTR_VAL(keypair)[keypair_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "ss", + &secretkey, &secretkey_len, + &publickey, &publickey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_sign_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_keypair_from_secretkey_and_publickey(): " + "secretkey should be CRYPTO_SIGN_SECRETKEYBYTES bytes", + 0); + return; + } + if (publickey_len != crypto_sign_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_keypair_from_secretkey_and_publickey(): " + "publickey should be 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(ZEND_NUM_ARGS(), "s", + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_sign_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_publickey_from_secretkey(): " + "secretkey should be 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, + "crypto_sign_publickey_from_secretkey(): 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(ZEND_NUM_ARGS(), "s", + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != + crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_secretkey(): keypair should be " + "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(ZEND_NUM_ARGS(), "s", + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != + crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_publickey(): keypair should be " + "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(ZEND_NUM_ARGS(), "ss", + &msg, &msg_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_sign_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign(): secret key size should be " + "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_free(msg_signed); + zend_throw_exception(sodium_exception_ce, "crypto_sign(): internal error", 0); + return; + } + if (msg_signed_real_len <= 0U || msg_signed_real_len >= SIZE_MAX || + msg_signed_real_len > msg_signed_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ss", + &msg_signed, &msg_signed_len, + &publickey, &publickey_len) == FAILURE) { + return; + } + if (publickey_len != crypto_sign_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_open(): public key size should be " + "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_free(msg); + RETURN_FALSE; + } + if (msg_real_len >= SIZE_MAX || msg_real_len > msg_signed_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ss", + &msg, &msg_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_sign_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_detached(): secret key size should be " + "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_free(signature); + zend_throw_exception(sodium_exception_ce, "crypto_sign_detached()", 0); + return; + } + if (signature_real_len <= 0U || signature_real_len > crypto_sign_BYTES) { + zend_string_free(signature); + zend_throw_exception(sodium_exception_ce, "signature has a bogus size", 0); + return; + } + ZEND_ASSERT(ZSTR_VAL(signature)[signature_real_len] == 0); + + RETURN_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(ZEND_NUM_ARGS(), "sss", + &signature, &signature_len, + &msg, &msg_len, + &publickey, &publickey_len) == FAILURE) { + return; + } + if (signature_len != crypto_sign_BYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_verify_detached(): signature size should be " + "CRYPTO_SIGN_BYTES bytes", + 0); + return; + } + if (publickey_len != crypto_sign_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_verify_detached(): public key size should be " + "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(ZEND_NUM_ARGS(), "lss", + &ciphertext_len, + &nonce, &nonce_len, + &key, &key_len) == FAILURE) { + return; + } + if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, "crypto_stream(): invalid length", 0); + return; + } + if (nonce_len != crypto_stream_NONCEBYTES) { + zend_throw_exception(sodium_exception_ce, "nonce should be CRYPTO_STREAM_NONCEBYTES bytes", 0); + return; + } + if (key_len != crypto_stream_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, "key should be 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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_stream(): internal error", 0); + return; + } + ZSTR_VAL(ciphertext)[ciphertext_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "sss", + &msg, &msg_len, + &nonce, &nonce_len, + &key, &key_len) == FAILURE) { + return; + } + if (nonce_len != crypto_stream_NONCEBYTES) { + zend_throw_exception(sodium_exception_ce, "nonce should be CRYPTO_STREAM_NONCEBYTES bytes", 0); + return; + } + if (key_len != crypto_stream_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, "key should be 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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_stream_xor(): internal error", 0); + return; + } + ZSTR_VAL(ciphertext)[ciphertext_len] = 0; + + RETURN_STR(ciphertext); +} + +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(ZEND_NUM_ARGS(), "lssll", + &hash_len, + &passwd, &passwd_len, + &salt, &salt_len, + &opslimit, &memlimit) == FAILURE || + hash_len <= 0 || hash_len >= SIZE_MAX || + opslimit <= 0 || memlimit <= 0 || memlimit > SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, "crypto_pwhash_scryptsalsa208sha256(): invalid parameters", 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 CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES bytes", + 0); + return; + } + if (opslimit < crypto_pwhash_scryptsalsa208sha256_opslimit_interactive()) { + zend_error(E_WARNING, + "number of operations for the scrypt function is low"); + } + if (memlimit < crypto_pwhash_scryptsalsa208sha256_memlimit_interactive()) { + zend_error(E_WARNING, + "maximum memory for the scrypt function is low"); + } + 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_free(hash); + zend_throw_exception(sodium_exception_ce, "crypto_pwhash_scryptsalsa208sha256(): internal error", 0); + return; + } + ZSTR_VAL(hash)[hash_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "sll", + &passwd, &passwd_len, + &opslimit, &memlimit) == FAILURE || + opslimit <= 0 || memlimit <= 0 || memlimit > SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, + "crypto_pwhash_scryptsalsa208sha256_str(): invalid parameters", + 0); + return; + } + if (passwd_len <= 0) { + zend_error(E_WARNING, "empty password"); + } + if (opslimit < crypto_pwhash_scryptsalsa208sha256_opslimit_interactive()) { + zend_error(E_WARNING, + "number of operations for the scrypt function is low"); + } + if (memlimit < crypto_pwhash_scryptsalsa208sha256_memlimit_interactive()) { + zend_error(E_WARNING, + "maximum memory for the scrypt function is low"); + } + 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_free(hash_str); + zend_throw_exception(sodium_exception_ce, "crypto_pwhash_scryptsalsa208sha256_str(): internal error", 0); + return; + } + ZSTR_VAL(hash_str)[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "ss", + &hash_str, &hash_str_len, + &passwd, &passwd_len) == FAILURE) { + zend_throw_exception(sodium_exception_ce, + "crypto_pwhash_scryptsalsa208sha256_str_verify(): invalid parameters", + 0); + 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; +} + +#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; + size_t passwd_len; + size_t salt_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lssll", + &hash_len, + &passwd, &passwd_len, + &salt, &salt_len, + &opslimit, &memlimit) == FAILURE || + hash_len <= 0 || hash_len >= SIZE_MAX || + opslimit <= 0 || memlimit <= 0 || memlimit > SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, "crypto_pwhash(): invalid parameters", 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 CRYPTO_PWHASH_SALTBYTES bytes", 0); + return; + } + if (opslimit < crypto_pwhash_OPSLIMIT_INTERACTIVE) { + zend_error(E_WARNING, + "number of operations for the argon2i function is low"); + } + if (memlimit < crypto_pwhash_MEMLIMIT_INTERACTIVE) { + zend_error(E_WARNING, "maximum memory for the argon2i function is low"); + } + hash = zend_string_alloc((size_t) hash_len, 0); + if (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, + crypto_pwhash_alg_default()) != 0) { + zend_string_free(hash); + zend_throw_exception(sodium_exception_ce, "crypto_pwhash(): internal error", 0); + return; + } + ZSTR_VAL(hash)[hash_len] = 0; + + RETURN_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(ZEND_NUM_ARGS(), "sll", + &passwd, &passwd_len, + &opslimit, &memlimit) == FAILURE || + opslimit <= 0 || memlimit <= 0 || memlimit > SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, + "crypto_pwhash_str(): invalid parameters", + 0); + return; + } + if (passwd_len <= 0) { + zend_error(E_WARNING, "empty password"); + } + if (opslimit < crypto_pwhash_OPSLIMIT_INTERACTIVE) { + zend_error(E_WARNING, + "number of operations for the argon2i function is low"); + } + if (memlimit < crypto_pwhash_MEMLIMIT_INTERACTIVE) { + zend_error(E_WARNING, + "maximum memory for the argon2i function is low"); + } + 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_free(hash_str); + zend_throw_exception(sodium_exception_ce, "crypto_pwhash_str(): 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_STR(hash_str); +} + +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(ZEND_NUM_ARGS(), "ss", + &hash_str, &hash_str_len, + &passwd, &passwd_len) == FAILURE) { + zend_throw_exception(sodium_exception_ce, + "crypto_pwhash_str_verify(): invalid parameters", + 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 + +PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available) +{ +#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(ZEND_NUM_ARGS(), "ssss", + &msg, &msg_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_aes256gcm_encrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_aes256gcm_encrypt(): " + "secret key size should be " + "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; + } + 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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_aead_aes256gcm_encrypt(): internal error", 0); + return; + } + if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || + ciphertext_real_len > ciphertext_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ssss", + &ciphertext, &ciphertext_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_aes256gcm_decrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_aes256gcm_decrypt(): " + "secret key size should be " + "CRYPTO_AEAD_AES256GCM_KEYBYTES bytes", + 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 (ciphertext_len < crypto_aead_aes256gcm_ABYTES || + 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_free(msg); + RETURN_FALSE; + } + if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ssss", + &msg, &msg_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_chacha20poly1305_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_encrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_encrypt(): " + "secret key size should be " + "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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_aead_chacha20poly1305_encrypt(): internal error", 0); + return; + } + if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || + ciphertext_real_len > ciphertext_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ssss", + &ciphertext, &ciphertext_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_chacha20poly1305_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_decrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_decrypt(): " + "secret key size should be " + "CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes", + 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 (ciphertext_len < crypto_aead_chacha20poly1305_ABYTES || + 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_free(msg); + RETURN_FALSE; + } + if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { + zend_string_free(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_STR(msg); +} + +#ifdef crypto_aead_chacha20poly1305_IETF_NPUBBYTES +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(ZEND_NUM_ARGS(), "ssss", + &msg, &msg_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_ietf_encrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_ietf_encrypt(): " + "secret key size should be " + "CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes", + 0); + return; + } + if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_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, "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_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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_aead_chacha20poly1305_ietf_encrypt(): internal error", 0); + return; + } + if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || + ciphertext_real_len > ciphertext_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ssss", + &ciphertext, &ciphertext_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_ietf_decrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_chacha20poly1305_ietf_decrypt(): " + "secret key size should be " + "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 ((unsigned long long) ciphertext_len - + crypto_aead_chacha20poly1305_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 (ciphertext_len < crypto_aead_chacha20poly1305_ABYTES || + 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_free(msg); + RETURN_FALSE; + } + if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { + zend_string_free(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_STR(msg); +} +#endif + +#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(ZEND_NUM_ARGS(), "ssss", + &msg, &msg_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_xchacha20poly1305_ietf_encrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_xchacha20poly1305_ietf_encrypt(): " + "secret key size should be " + "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; + } + if ((unsigned long long) msg_len > 64ULL * (1ULL << 32) - 64ULL) { + 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_free(ciphertext); + zend_throw_exception(sodium_exception_ce, "crypto_aead_xchacha20poly1305_ietf_encrypt(): internal error", 0); + return; + } + if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX || + ciphertext_real_len > ciphertext_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "ssss", + &ciphertext, &ciphertext_len, + &ad, &ad_len, + &npub, &npub_len, + &secretkey, &secretkey_len) == FAILURE) { + return; + } + if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_xchacha20poly1305_ietf_decrypt(): " + "public nonce size should be " + "CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes", + 0); + return; + } + if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_aead_xchacha20poly1305_ietf_decrypt(): " + "secret key size should be " + "CRYPTO_AEAD_XCHACHA20POLY1305_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 ((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 (ciphertext_len < crypto_aead_xchacha20poly1305_IETF_ABYTES || + 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_free(msg); + RETURN_FALSE; + } + if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) { + zend_string_free(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_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(ZEND_NUM_ARGS(), "s", + &bin, &bin_len) == FAILURE) { + 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; + 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(ZEND_NUM_ARGS(), "s|s", + &hex, &hex_len, + &ignore, &ignore_len) == FAILURE) { + 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, NULL) != 0 || + bin_real_len >= SIZE_MAX || bin_real_len > bin_len) { + zend_string_free(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_STR(bin); +} + +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(ZEND_NUM_ARGS(), "ss", + &n, &n_len, &p, &p_len) == FAILURE) { + return; + } + if (n_len != crypto_scalarmult_SCALARBYTES || + p_len != crypto_scalarmult_SCALARBYTES) { + zend_throw_exception(sodium_exception_ce, "crypto_scalarmult(): scalar and point must be " + "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_free(q); + zend_throw_exception(sodium_exception_ce, "crypto_scalarmult(): internal error", 0); + return; + } + ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0; + + RETURN_STR(q); +} + +PHP_FUNCTION(sodium_crypto_kx) +{ + crypto_generichash_state h; + unsigned char q[crypto_scalarmult_BYTES]; + zend_string *sharedkey; + unsigned char *client_publickey; + unsigned char *publickey; + unsigned char *secretkey; + unsigned char *server_publickey; + size_t client_publickey_len; + size_t publickey_len; + size_t secretkey_len; + size_t server_publickey_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss", + &secretkey, &secretkey_len, + &publickey, &publickey_len, + &client_publickey, &client_publickey_len, + &server_publickey, &server_publickey_len) == FAILURE) { + return; + } + if (secretkey_len != crypto_kx_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, "crypto_kx(): secret key must be CRYPTO_KX_SECRETKEY bytes", 0); + return; + } + if (publickey_len != crypto_kx_PUBLICKEYBYTES || + client_publickey_len != crypto_kx_PUBLICKEYBYTES || + server_publickey_len != crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, "crypto_kx(): public keys must be CRYPTO_KX_PUBLICKEY 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]); + if (crypto_scalarmult(q, secretkey, publickey) != 0) { + zend_throw_exception(sodium_exception_ce, "crypto_kx(): internal error", 0); + return; + } + sharedkey = zend_string_alloc(crypto_kx_BYTES, 0); + crypto_generichash_init(&h, NULL, 0U, crypto_generichash_BYTES); + crypto_generichash_update(&h, q, sizeof q); + sodium_memzero(q, sizeof q); + crypto_generichash_update(&h, client_publickey, client_publickey_len); + crypto_generichash_update(&h, server_publickey, server_publickey_len); + crypto_generichash_final(&h, (unsigned char *) ZSTR_VAL(sharedkey), + crypto_kx_BYTES); + ZSTR_VAL(sharedkey)[crypto_kx_BYTES] = 0; + + RETURN_STR(sharedkey); +} + +PHP_FUNCTION(sodium_crypto_auth) +{ + zend_string *mac; + char *key; + char *msg; + size_t msg_len; + size_t key_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", + &msg, &msg_len, + &key, &key_len) == FAILURE) { + return; + } + if (key_len != crypto_auth_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, "crypto_auth(): key must be 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, "crypto_auth(): 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(ZEND_NUM_ARGS(), "sss", + &mac, &mac_len, + &msg, &msg_len, + &key, &key_len) == FAILURE) { + return; + } + if (key_len != crypto_auth_KEYBYTES) { + zend_throw_exception(sodium_exception_ce, "crypto_auth_verify(): key must be CRYPTO_AUTH_KEYBYTES bytes", 0); + return; + } + if (mac_len != crypto_auth_BYTES) { + zend_throw_exception(sodium_exception_ce, "crypto_auth_verify(): authentication tag must be 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(ZEND_NUM_ARGS(), "s", + &eddsakey, &eddsakey_len) == FAILURE) { + return; + } + if (eddsakey_len != crypto_sign_SECRETKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_ed25519_sk_to_curve25519(): " + "Ed25519 key should be 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, "crypto_sign_ed25519_sk_to_curve25519()", 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(ZEND_NUM_ARGS(), "s", + &eddsakey, &eddsakey_len) == FAILURE) { + return; + } + if (eddsakey_len != crypto_sign_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "crypto_sign_ed25519_pk_to_curve25519(): " + "Ed25519 key should be 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, "crypto_sign_ed25519_pk_to_curve25519()", 0); + return; + } + ZSTR_VAL(ecdhkey)[crypto_box_PUBLICKEYBYTES] = 0; + + RETURN_STR(ecdhkey); +} + +#if SODIUM_LIBRARY_VERSION_MAJOR > 7 || \ + (SODIUM_LIBRARY_VERSION_MAJOR == 7 && SODIUM_LIBRARY_VERSION_MINOR >= 6) +PHP_FUNCTION(sodium_compare) +{ + char *buf1; + char *buf2; + size_t len1; + size_t len2; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", + &buf1, &len1, + &buf2, &len2) == FAILURE) { + return; + } + if (len1 != len2) { + zend_throw_exception(sodium_exception_ce, "compare(): arguments have different sizes", 0); + } else { + RETURN_LONG(sodium_compare((const unsigned char *) buf1, + (const unsigned char *) buf2, (size_t) len1)); + } +} +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 tw=78 fdm=marker + * vim<600: sw=4 ts=4 tw=78 + */ diff --git a/ext/sodium/libsodium.php b/ext/sodium/libsodium.php new file mode 100644 index 0000000000..bb18faff19 --- /dev/null +++ b/ext/sodium/libsodium.php @@ -0,0 +1,24 @@ +<?php +$br = (php_sapi_name() == "cli")? "":"<br>"; + +if(!extension_loaded('libsodium')) { + dl('libsodium.' . PHP_SHLIB_SUFFIX); +} +$module = 'libsodium'; +$functions = get_extension_funcs($module); +echo "Functions available in the test extension:$br\n"; +foreach($functions as $func) { + echo $func."$br\n"; +} +echo "$br\n"; +$function = 'sodium_memzero'; +$exit = 0; +if (extension_loaded($module)) { + $str = $function($module); +} else { + $str = "Module $module is not compiled into PHP"; + $exit = 255; +} +echo "$str\n"; +exit($exit); +?> diff --git a/ext/sodium/php_libsodium.h b/ext/sodium/php_libsodium.h new file mode 100644 index 0000000000..3348c41a6e --- /dev/null +++ b/ext/sodium/php_libsodium.h @@ -0,0 +1,117 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2017 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: Andi Gutmans <andi@zend.com> | + | Zeev Suraski <zeev@zend.com> | + | Rasmus Lerdorf <rasmus@php.net> | + | Andrei Zmievski <andrei@php.net> | + | Stig Venaas <venaas@php.net> | + | Jason Greene <jason@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_LIBSODIUM_H +#define PHP_LIBSODIUM_H + +extern zend_module_entry sodium_module_entry; +#define phpext_sodium_ptr &sodium_module_entry + +#define PHP_SODIUM_VERSION PHP_VERSION + +#ifdef ZTS +# include "TSRM.h" +#endif + +PHP_MINIT_FUNCTION(sodium); +PHP_MSHUTDOWN_FUNCTION(sodium); +PHP_RINIT_FUNCTION(sodium); +PHP_RSHUTDOWN_FUNCTION(sodium); +PHP_MINFO_FUNCTION(sodium); + +PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available); +PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt); +PHP_FUNCTION(sodium_crypto_aead_aes256gcm_encrypt); +PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_decrypt); +PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_encrypt); +PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_decrypt); +PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_encrypt); +PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt); +PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt); +PHP_FUNCTION(sodium_crypto_auth); +PHP_FUNCTION(sodium_crypto_auth_verify); +PHP_FUNCTION(sodium_crypto_box); +PHP_FUNCTION(sodium_crypto_box_keypair); +PHP_FUNCTION(sodium_crypto_box_seed_keypair); +PHP_FUNCTION(sodium_crypto_box_keypair_from_secretkey_and_publickey); +PHP_FUNCTION(sodium_crypto_box_open); +PHP_FUNCTION(sodium_crypto_box_publickey); +PHP_FUNCTION(sodium_crypto_box_publickey_from_secretkey); +PHP_FUNCTION(sodium_crypto_box_seal); +PHP_FUNCTION(sodium_crypto_box_seal_open); +PHP_FUNCTION(sodium_crypto_box_secretkey); +PHP_FUNCTION(sodium_crypto_generichash); +PHP_FUNCTION(sodium_crypto_generichash_final); +PHP_FUNCTION(sodium_crypto_generichash_init); +PHP_FUNCTION(sodium_crypto_generichash_update); +PHP_FUNCTION(sodium_crypto_kx); +PHP_FUNCTION(sodium_crypto_pwhash); +PHP_FUNCTION(sodium_crypto_pwhash_str); +PHP_FUNCTION(sodium_crypto_pwhash_str_verify); +PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256); +PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str); +PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify); +PHP_FUNCTION(sodium_crypto_scalarmult); +PHP_FUNCTION(sodium_crypto_scalarmult_base); +PHP_FUNCTION(sodium_crypto_secretbox); +PHP_FUNCTION(sodium_crypto_secretbox_open); +PHP_FUNCTION(sodium_crypto_shorthash); +PHP_FUNCTION(sodium_crypto_sign); +PHP_FUNCTION(sodium_crypto_sign_detached); +PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519); +PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519); +PHP_FUNCTION(sodium_crypto_sign_keypair); +PHP_FUNCTION(sodium_crypto_sign_keypair_from_secretkey_and_publickey); +PHP_FUNCTION(sodium_crypto_sign_open); +PHP_FUNCTION(sodium_crypto_sign_publickey); +PHP_FUNCTION(sodium_crypto_sign_publickey_from_secretkey); +PHP_FUNCTION(sodium_crypto_sign_secretkey); +PHP_FUNCTION(sodium_crypto_sign_seed_keypair); +PHP_FUNCTION(sodium_crypto_sign_verify_detached); +PHP_FUNCTION(sodium_crypto_stream); +PHP_FUNCTION(sodium_crypto_stream_xor); +PHP_FUNCTION(sodium_randombytes_buf); +PHP_FUNCTION(sodium_randombytes_random16); +PHP_FUNCTION(sodium_randombytes_uniform); +PHP_FUNCTION(sodium_bin2hex); +PHP_FUNCTION(sodium_compare); +PHP_FUNCTION(sodium_hex2bin); +PHP_FUNCTION(sodium_increment); +PHP_FUNCTION(sodium_add); +PHP_FUNCTION(sodium_memcmp); +PHP_FUNCTION(sodium_memzero); + +#define crypto_kx_BYTES crypto_scalarmult_BYTES +#define crypto_kx_PUBLICKEYBYTES crypto_scalarmult_SCALARBYTES +#define crypto_kx_SECRETKEYBYTES crypto_scalarmult_SCALARBYTES + +#endif /* PHP_LIBSODIUM_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/sodium/tests/crypto_aead.phpt b/ext/sodium/tests/crypto_aead.phpt new file mode 100644 index 0000000000..5c4a51d32c --- /dev/null +++ b/ext/sodium/tests/crypto_aead.phpt @@ -0,0 +1,135 @@ +--TEST-- +Check for libsodium AEAD +--SKIPIF-- +<?php +if (!extension_loaded("sodium")) print "skip extension not loaded"; +if (!defined('SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES')) print "skip libsodium without AESGCM"; +?> +--FILE-- +<?php +echo "aead_chacha20poly1305:\n"; + +$msg = random_bytes(random_int(1, 1000)); +$nonce = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES); +$key = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES); +$ad = random_bytes(random_int(1, 1000)); + +$ciphertext = sodium_crypto_aead_chacha20poly1305_encrypt($msg, $ad, $nonce, $key); +$msg2 = sodium_crypto_aead_chacha20poly1305_decrypt($ciphertext, $ad, $nonce, $key); +var_dump($ciphertext !== $msg); +var_dump($msg === $msg2); +var_dump(sodium_crypto_aead_chacha20poly1305_decrypt($ciphertext, 'x' . $ad, $nonce, $key)); +try { + // Switched order + $msg2 = sodium_crypto_aead_chacha20poly1305_decrypt($ciphertext, $ad, $key, $nonce); + var_dump(false); +} catch (SodiumException $ex) { + var_dump(true); +} + +echo "aead_chacha20poly1305_ietf:\n"; + +if (SODIUM_LIBRARY_MAJOR_VERSION > 7 || + (SODIUM_LIBRARY_MAJOR_VERSION == 7 && + SODIUM_LIBRARY_MINOR_VERSION >= 6)) { + $msg = random_bytes(random_int(1, 1000)); + $nonce = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES); + $key = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES); + $ad = random_bytes(random_int(1, 1000)); + + $ciphertext = sodium_crypto_aead_chacha20poly1305_ietf_encrypt($msg, $ad, $nonce, $key); + $msg2 = sodium_crypto_aead_chacha20poly1305_ietf_decrypt($ciphertext, $ad, $nonce, $key); + var_dump($ciphertext !== $msg); + var_dump($msg === $msg2); + var_dump(sodium_crypto_aead_chacha20poly1305_ietf_decrypt($ciphertext, 'x' . $ad, $nonce, $key)); + try { + // Switched order + $msg2 = sodium_crypto_aead_chacha20poly1305_ietf_decrypt($ciphertext, $ad, $key, $nonce); + var_dump(false); + } catch (SodiumException $ex) { + var_dump(true); + } +} else { + var_dump(true); + var_dump(true); + var_dump(false); + var_dump(true); +} + +echo "aead_xchacha20poly1305_ietf:\n"; + +if (SODIUM_LIBRARY_MAJOR_VERSION > 9 || + (SODIUM_LIBRARY_MAJOR_VERSION == 9 && + SODIUM_LIBRARY_MINOR_VERSION >= 4)) { + $msg = random_bytes(random_int(1, 1000)); + $nonce = random_bytes(SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES); + $key = random_bytes(SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES); + $ad = random_bytes(random_int(1, 1000)); + + $ciphertext = sodium_crypto_aead_xchacha20poly1305_ietf_encrypt($msg, $ad, $nonce, $key); + $msg2 = sodium_crypto_aead_xchacha20poly1305_ietf_decrypt($ciphertext, $ad, $nonce, $key); + var_dump($ciphertext !== $msg); + var_dump($msg === $msg2); + var_dump(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt($ciphertext, 'x' . $ad, $nonce, $key)); + try { + // Switched order + $msg2 = sodium_crypto_aead_xchacha20poly1305_ietf_decrypt($ciphertext, $ad, $key, $nonce); + var_dump(false); + } catch (SodiumException $ex) { + var_dump(true); + } +} else { + var_dump(true); + var_dump(true); + var_dump(false); + var_dump(true); +} + +echo "aead_aes256gcm:\n"; + +$msg = random_bytes(random_int(1, 1000)); +$nonce = random_bytes(SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES); +$key = random_bytes(SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES); +$ad = random_bytes(random_int(1, 1000)); + +if (sodium_crypto_aead_aes256gcm_is_available()) { + $ciphertext = sodium_crypto_aead_aes256gcm_encrypt($msg, $ad, $nonce, $key); + $msg2 = sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $ad, $nonce, $key); + var_dump($ciphertext !== $msg); + var_dump($msg === $msg2); + var_dump(sodium_crypto_aead_aes256gcm_decrypt($ciphertext, 'x' . $ad, $nonce, $key)); + try { + // Switched order + $msg2 = sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $ad, $key, $nonce); + var_dump(false); + } catch (SodiumException $ex) { + var_dump(true); + } +} else { + var_dump(true); + var_dump(true); + var_dump(false); + var_dump(true); +} +?> +--EXPECT-- +aead_chacha20poly1305: +bool(true) +bool(true) +bool(false) +bool(true) +aead_chacha20poly1305_ietf: +bool(true) +bool(true) +bool(false) +bool(true) +aead_xchacha20poly1305_ietf: +bool(true) +bool(true) +bool(false) +bool(true) +aead_aes256gcm: +bool(true) +bool(true) +bool(false) +bool(true) diff --git a/ext/sodium/tests/crypto_auth.phpt b/ext/sodium/tests/crypto_auth.phpt new file mode 100644 index 0000000000..25ddff540f --- /dev/null +++ b/ext/sodium/tests/crypto_auth.phpt @@ -0,0 +1,47 @@ +--TEST-- +Check for libsodium auth +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$msg = random_bytes(1000); +$key = random_bytes(SODIUM_CRYPTO_AUTH_KEYBYTES); +$mac = sodium_crypto_auth($msg, $key); + +// This should validate +var_dump(sodium_crypto_auth_verify($mac, $msg, $key)); + +$bad_key = random_bytes(SODIUM_CRYPTO_AUTH_KEYBYTES - 1); +try { + $mac = sodium_crypto_auth($msg, $bad_key); + echo 'Fail!', PHP_EOL; +} catch (SodiumException $ex) { + echo $ex->getMessage(), PHP_EOL; +} + +// Flip the first bit +$badmsg = $msg; +$badmsg[0] = \chr(\ord($badmsg[0]) ^ 0x80); +var_dump(sodium_crypto_auth_verify($mac, $badmsg, $key)); + +// Let's flip a bit pseudo-randomly +$badmsg = $msg; +$badmsg[$i=mt_rand(0, 999)] = \chr( + \ord($msg[$i]) ^ ( + 1 << mt_rand(0, 7) + ) +); + +var_dump(sodium_crypto_auth_verify($mac, $badmsg, $key)); + +// Now let's change a bit in the MAC +$badmac = $mac; +$badmac[0] = \chr(\ord($badmac[0]) ^ 0x80); +var_dump(sodium_crypto_auth_verify($badmac, $msg, $key)); +?> +--EXPECT-- +bool(true) +crypto_auth(): key must be CRYPTO_AUTH_KEYBYTES bytes +bool(false) +bool(false) +bool(false) diff --git a/ext/sodium/tests/crypto_box.phpt b/ext/sodium/tests/crypto_box.phpt new file mode 100644 index 0000000000..ef35714714 --- /dev/null +++ b/ext/sodium/tests/crypto_box.phpt @@ -0,0 +1,150 @@ +--TEST-- +Check for libsodium box +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$keypair = sodium_crypto_box_keypair(); +var_dump(strlen($keypair) === SODIUM_CRYPTO_BOX_KEYPAIRBYTES); +$sk = sodium_crypto_box_secretkey($keypair); +var_dump(strlen($sk) === SODIUM_CRYPTO_BOX_SECRETKEYBYTES); +$pk = sodium_crypto_box_publickey($keypair); +var_dump(strlen($pk) === SODIUM_CRYPTO_BOX_PUBLICKEYBYTES); +var_dump($pk !== $sk); +$pk2 = sodium_crypto_box_publickey_from_secretkey($sk); +var_dump($pk === $pk2); +$pk2 = sodium_crypto_scalarmult_base($sk); +var_dump($pk === $pk2); +$keypair2 = sodium_crypto_box_keypair_from_secretkey_and_publickey($sk, $pk); +var_dump($keypair === $keypair2); + +$seed_x = str_repeat('x', SODIUM_CRYPTO_BOX_SEEDBYTES); +$seed_y = str_repeat('y', SODIUM_CRYPTO_BOX_SEEDBYTES); +$alice_box_kp = sodium_crypto_box_seed_keypair($seed_x); +$bob_box_kp = sodium_crypto_box_seed_keypair($seed_y); +$message_nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES); + +$alice_box_secretkey = sodium_crypto_box_secretkey($alice_box_kp); +$bob_box_publickey = sodium_crypto_box_publickey($bob_box_kp); + +$alice_to_bob_kp = sodium_crypto_box_keypair_from_secretkey_and_publickey( + $alice_box_secretkey, + $bob_box_publickey +); + +$msg = "Here is another message, to be signed using Alice's secret key, and " . + "to be encrypted using Bob's public key. The keys will always be the same " . + "since they are derived from a fixed seeds"; + +$ciphertext = sodium_crypto_box( + $msg, + $message_nonce, + $alice_to_bob_kp +); + +try { + $ciphertext = sodium_crypto_box( + $msg, + $message_nonce, + substr($alice_to_bob_kp, 1) + ); +} catch (SodiumException $ex) { + echo $ex->getMessage(), PHP_EOL; +} + +sodium_memzero($alice_box_kp); +sodium_memzero($bob_box_kp); + +$alice_box_kp = sodium_crypto_box_seed_keypair($seed_x); +$bob_box_kp = sodium_crypto_box_seed_keypair($seed_y); + +$alice_box_publickey = sodium_crypto_box_publickey($alice_box_kp); +$bob_box_secretkey = sodium_crypto_box_secretkey($bob_box_kp); + +$bob_to_alice_kp = sodium_crypto_box_keypair_from_secretkey_and_publickey( + $bob_box_secretkey, + $alice_box_publickey +); + +$plaintext = sodium_crypto_box_open( + $ciphertext, + $message_nonce, + $bob_to_alice_kp +); + +var_dump($msg === $plaintext); + +$alice_kp = sodium_crypto_box_keypair(); +$alice_secretkey = sodium_crypto_box_secretkey($alice_kp); +$alice_publickey = sodium_crypto_box_publickey($alice_kp); + +$bob_kp = sodium_crypto_box_keypair(); +$bob_secretkey = sodium_crypto_box_secretkey($bob_kp); +$bob_publickey = sodium_crypto_box_publickey($bob_kp); + +$alice_to_bob_kp = sodium_crypto_box_keypair_from_secretkey_and_publickey + ($alice_secretkey, $bob_publickey); + +$bob_to_alice_kp = sodium_crypto_box_keypair_from_secretkey_and_publickey + ($bob_secretkey, $alice_publickey); + +$alice_to_bob_message_nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES); + +$alice_to_bob_ciphertext = sodium_crypto_box('Hi, this is Alice', + $alice_to_bob_message_nonce, + $alice_to_bob_kp); + +$alice_message_decrypted_by_bob = sodium_crypto_box_open($alice_to_bob_ciphertext, + $alice_to_bob_message_nonce, + $bob_to_alice_kp); + +$bob_to_alice_message_nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES); + +$bob_to_alice_ciphertext = sodium_crypto_box('Hi Alice! This is Bob', + $bob_to_alice_message_nonce, + $bob_to_alice_kp); + +$bob_message_decrypted_by_alice = sodium_crypto_box_open($bob_to_alice_ciphertext, + $bob_to_alice_message_nonce, + $alice_to_bob_kp); + +var_dump($alice_message_decrypted_by_bob); +var_dump($bob_message_decrypted_by_alice); + +if (SODIUM_LIBRARY_MAJOR_VERSION > 7 || + (SODIUM_LIBRARY_MAJOR_VERSION == 7 && + SODIUM_LIBRARY_MINOR_VERSION >= 5)) { + $anonymous_message_to_alice = sodium_crypto_box_seal('Anonymous message', + $alice_publickey); + + $decrypted_message = sodium_crypto_box_seal_open($anonymous_message_to_alice, + $alice_kp); +} else { + $decrypted_message = 'Anonymous message'; +} +var_dump($decrypted_message); + +$msg = sodium_hex2bin( + '7375f4094f1151640bd853cb13dbc1a0ee9e13b0287a89d34fa2f6732be9de13f88457553d'. + '768347116522d6d32c9cb353ef07aa7c83bd129b2bb5db35b28334c935b24f2639405a0604' +); +$kp = sodium_hex2bin( + '36a6c2b96a650d80bf7e025e0f58f3d636339575defb370801a54213bd54582d'. + '5aecbcf7866e7a4d58a6c1317e2b955f54ecbe2fcbbf7d262c10636ed524480c' +); +var_dump(sodium_crypto_box_seal_open($msg, $kp)); +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +crypto_box(): keypair size should be CRYPTO_BOX_KEYPAIRBYTES bytes +bool(true) +string(17) "Hi, this is Alice" +string(21) "Hi Alice! This is Bob" +string(17) "Anonymous message" +string(26) "This is for your eyes only" diff --git a/ext/sodium/tests/crypto_generichash.phpt b/ext/sodium/tests/crypto_generichash.phpt new file mode 100644 index 0000000000..364c5dc5ec --- /dev/null +++ b/ext/sodium/tests/crypto_generichash.phpt @@ -0,0 +1,61 @@ +--TEST-- +Check for libsodium generichash +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$q = sodium_crypto_generichash('msg'); +var_dump(bin2hex($q)); +$q = sodium_crypto_generichash('msg', '0123456789abcdef'); +var_dump(bin2hex($q)); +$q = sodium_crypto_generichash('msg', '0123456789abcdef', 64); +var_dump(bin2hex($q)); +$q = sodium_crypto_generichash('msg', '0123456789abcdef0123456789abcdef', 64); +var_dump(bin2hex($q)); +$state = sodium_crypto_generichash_init(); +$q = sodium_crypto_generichash_final($state); +var_dump(bin2hex($q)); +$state = sodium_crypto_generichash_init(); +sodium_crypto_generichash_update($state, 'm'); +sodium_crypto_generichash_update($state, 'sg'); +$q = sodium_crypto_generichash_final($state); +var_dump(bin2hex($q)); +$state = sodium_crypto_generichash_init('0123456789abcdef'); +sodium_crypto_generichash_update($state, 'm'); +sodium_crypto_generichash_update($state, 'sg'); +$q = sodium_crypto_generichash_final($state); +var_dump(bin2hex($q)); +$state = sodium_crypto_generichash_init('0123456789abcdef', 64); +sodium_crypto_generichash_update($state, 'm'); +sodium_crypto_generichash_update($state, 'sg'); +$state2 = '' . $state; +$q = sodium_crypto_generichash_final($state, 64); +var_dump(bin2hex($q)); +sodium_crypto_generichash_update($state2, '2'); +$q = sodium_crypto_generichash_final($state2, 64); +$exp = bin2hex($q); +var_dump($exp); +$act = bin2hex( + sodium_crypto_generichash('msg2', '0123456789abcdef', 64) +); +var_dump($act); +var_dump($exp === $act); +try { + $hash = sodium_crypto_generichash('test', '', 128); +} catch (SodiumException $ex) { + var_dump(true); +} +?> +--EXPECT-- +string(64) "96a7ed8861db0abc006f473f9e64687875f3d9df8e723adae9f53a02b2aec378" +string(64) "ba03e32a94ece425a77b350f029e0a3d37e6383158aa7cefa2b1b9470a7fcb7a" +string(128) "8ccd640462e7380010c5722d7f3c2354781d1360430197ff233509c27353fd2597c8d689bfe769467056a0655b3faba6af4e4ade248558f7c53538c4d5b94806" +string(128) "30f0e5f1e3beb7e0340976ac05a94043cce082d870e28e03c906e8fe9a88786271c6ba141eee2885e7444a870fac498cc78a13b0c53aefaec01bf38ebfe73b3f" +string(64) "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8" +string(64) "96a7ed8861db0abc006f473f9e64687875f3d9df8e723adae9f53a02b2aec378" +string(64) "ba03e32a94ece425a77b350f029e0a3d37e6383158aa7cefa2b1b9470a7fcb7a" +string(128) "8ccd640462e7380010c5722d7f3c2354781d1360430197ff233509c27353fd2597c8d689bfe769467056a0655b3faba6af4e4ade248558f7c53538c4d5b94806" +string(128) "9ef702f51114c9dc2cc7521746e8beebe0a3ca9bb29ec729e16682ca982e7f69ff70235a46659a9a6c28f92fbd990288301b9a6b5517f1f2ba6518074af19a5a" +string(128) "9ef702f51114c9dc2cc7521746e8beebe0a3ca9bb29ec729e16682ca982e7f69ff70235a46659a9a6c28f92fbd990288301b9a6b5517f1f2ba6518074af19a5a" +bool(true) +bool(true) diff --git a/ext/sodium/tests/crypto_hex.phpt b/ext/sodium/tests/crypto_hex.phpt new file mode 100644 index 0000000000..0f872ee867 --- /dev/null +++ b/ext/sodium/tests/crypto_hex.phpt @@ -0,0 +1,21 @@ +--TEST-- +Check for libsodium bin2hex +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$bin = random_bytes(random_int(1, 1000)); +$hex = sodium_bin2hex($bin); +$phphex = bin2hex($bin); +var_dump(strcasecmp($hex, $phphex)); + +$bin2 = sodium_hex2bin($hex); +var_dump($bin2 === $bin); + +$bin2 = sodium_hex2bin('[' . $hex .']', '[]'); +var_dump($bin2 === $bin); +?> +--EXPECT-- +int(0) +bool(true) +bool(true) diff --git a/ext/sodium/tests/crypto_kx.phpt b/ext/sodium/tests/crypto_kx.phpt new file mode 100644 index 0000000000..ef8c5f7a63 --- /dev/null +++ b/ext/sodium/tests/crypto_kx.phpt @@ -0,0 +1,37 @@ +--TEST-- +Check for libsodium-based key exchange +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$client_secretkey = sodium_hex2bin("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"); +$client_publickey = sodium_crypto_box_publickey_from_secretkey($client_secretkey); + +$server_secretkey = sodium_hex2bin("948f00e90a246fb5909f8648c2ac6f21515771235523266439e0d775ba0c3671"); +$server_publickey = sodium_crypto_box_publickey_from_secretkey($server_secretkey); + +$shared_key_computed_by_client = + sodium_crypto_kx($client_secretkey, $server_publickey, + $client_publickey, $server_publickey); + +$shared_key_computed_by_server = + sodium_crypto_kx($server_secretkey, $client_publickey, + $client_publickey, $server_publickey); + +var_dump(sodium_bin2hex($shared_key_computed_by_client)); +var_dump(sodium_bin2hex($shared_key_computed_by_server)); +try { + sodium_crypto_kx( + substr($client_secretkey, 1), + $server_publickey, + $client_publickey, + $server_publickey + ); +} catch (SodiumException $ex) { + var_dump(true); +} +?> +--EXPECT-- +string(64) "509a1580c2ee30c565317e29e0fea0b1c232e0ef3a7871d91dc64814b19a3bd2" +string(64) "509a1580c2ee30c565317e29e0fea0b1c232e0ef3a7871d91dc64814b19a3bd2" +bool(true) diff --git a/ext/sodium/tests/crypto_scalarmult.phpt b/ext/sodium/tests/crypto_scalarmult.phpt new file mode 100644 index 0000000000..22496cd669 --- /dev/null +++ b/ext/sodium/tests/crypto_scalarmult.phpt @@ -0,0 +1,20 @@ +--TEST-- +Check for libsodium scalarmult +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$n = sodium_hex2bin("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"); +$p = sodium_hex2bin("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"); +$q = sodium_crypto_scalarmult($n, $p); + +var_dump(sodium_bin2hex($q)); +try { + sodium_crypto_scalarmult(substr($n, 1), $p); +} catch (SodiumException $ex) { + var_dump(true); +} +?> +--EXPECT-- +string(64) "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" +bool(true) diff --git a/ext/sodium/tests/crypto_secretbox.phpt b/ext/sodium/tests/crypto_secretbox.phpt new file mode 100644 index 0000000000..f4bf53ec61 --- /dev/null +++ b/ext/sodium/tests/crypto_secretbox.phpt @@ -0,0 +1,26 @@ +--TEST-- +Check for libsodium secretbox +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); +$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); + +$a = sodium_crypto_secretbox('test', $nonce, $key); +$x = sodium_crypto_secretbox_open($a, $nonce, $key); +var_dump(bin2hex($x)); +$y = sodium_crypto_secretbox_open("\0" . $a, $nonce, $key); +var_dump($y); + +try { + sodium_crypto_secretbox('test', substr($nonce, 1), $key); +} catch (SodiumException $ex) { + var_dump(true); +} + +?> +--EXPECT-- +string(8) "74657374" +bool(false) +bool(true) diff --git a/ext/sodium/tests/crypto_shorthash.phpt b/ext/sodium/tests/crypto_shorthash.phpt new file mode 100644 index 0000000000..3398def06e --- /dev/null +++ b/ext/sodium/tests/crypto_shorthash.phpt @@ -0,0 +1,28 @@ +--TEST-- +Check for libsodium shorthash +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$m1 = 'message'; +$k1 = '0123456789ABCDEF'; +$h1 = sodium_crypto_shorthash($m1, $k1); +echo bin2hex($h1) . "\n"; +$k2 = '0123456789abcdef'; +$h2 = sodium_crypto_shorthash($m1, $k2); +echo bin2hex($h2) . "\n"; +$m2 = 'msg'; +$h3 = sodium_crypto_shorthash($m2, $k2); +echo bin2hex($h3) . "\n"; + +try { + sodium_crypto_shorthash($m1, $k1 . $k2); +} catch (SodiumException $ex) { + var_dump(true); +} +?> +--EXPECT-- +e0ad6fdbf8b9a191 +c667b37af201a2d9 +d27fa3fc70b45b72 +bool(true) diff --git a/ext/sodium/tests/crypto_sign.phpt b/ext/sodium/tests/crypto_sign.phpt new file mode 100644 index 0000000000..55fe8920bf --- /dev/null +++ b/ext/sodium/tests/crypto_sign.phpt @@ -0,0 +1,81 @@ +--TEST-- +Check for libsodium ed25519 signatures +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$keypair = sodium_crypto_sign_keypair(); +var_dump(strlen($keypair) === SODIUM_CRYPTO_SIGN_KEYPAIRBYTES); +$sk = sodium_crypto_sign_secretkey($keypair); +var_dump(strlen($sk) === SODIUM_CRYPTO_SIGN_SECRETKEYBYTES); +$pk = sodium_crypto_sign_publickey($keypair); +var_dump(strlen($pk) === SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES); +var_dump($pk !== $sk); +$keypair2 = sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk); +var_dump($keypair === $keypair2); + +$alice_kp = sodium_crypto_sign_keypair(); +$alice_secretkey = sodium_crypto_sign_secretkey($alice_kp); +$alice_publickey = sodium_crypto_sign_publickey($alice_kp); + +$msg = "Here is the message, to be signed using Alice's secret key, and " . + "to be verified using Alice's public key"; + +$msg_signed = sodium_crypto_sign($msg, $alice_secretkey); +var_dump(strlen($msg_signed) - strlen($msg) === SODIUM_CRYPTO_SIGN_BYTES); + +$msg_orig = sodium_crypto_sign_open($msg_signed, $alice_publickey); +var_dump($msg_orig === $msg); + +$seed = str_repeat('x', SODIUM_CRYPTO_SIGN_SEEDBYTES); +$alice_kp = sodium_crypto_sign_seed_keypair($seed); + +$alice_secretkey = sodium_crypto_sign_secretkey($alice_kp); +$alice_publickey = sodium_crypto_sign_publickey($alice_kp); + +$msg = "Here is another message, to be signed using Alice's secret key, and " . + "to be verified using Alice's public key, which will be always the same " . + "since they are derived from a fixed seed"; + +$msg_signed = sodium_crypto_sign($msg, $alice_secretkey); +var_dump(strlen($msg_signed) - strlen($msg) === SODIUM_CRYPTO_SIGN_BYTES); + +$msg_orig = sodium_crypto_sign_open($msg_signed, $alice_publickey); +var_dump($msg_orig === $msg); + +$signature = sodium_crypto_sign_detached($msg, $alice_secretkey); +var_dump(strlen($signature) === SODIUM_CRYPTO_SIGN_BYTES); +var_dump(sodium_crypto_sign_verify_detached($signature, + $msg, $alice_publickey)); +var_dump(sodium_crypto_sign_verify_detached($signature, + $msg . "\0", $alice_publickey)); + +$calc_pubkey = sodium_crypto_sign_publickey_from_secretkey($alice_secretkey); +var_dump(sodium_memcmp($calc_pubkey, $alice_publickey) === 0); + +$ed25519key = sodium_hex2bin("55b62f664bf1c359f58a6b91b89556f97284273510573055b9237d17f5a20564607f0626f49e63c2c8f814ed6d955bf8b005b33fd5fd56eaca93073d8eb99165"); +$curve25519key = sodium_crypto_sign_ed25519_sk_to_curve25519($ed25519key); +var_dump($curve25519key === sodium_hex2bin("381b2be5e3d38820deb1243fb58b4be654da30dd3ccde492cb88f937eb489363")); + +try { + sodium_crypto_sign($msg, substr($alice_secretkey, 1)); +} catch (SodiumException $ex) { + var_dump(true); +} +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(true) diff --git a/ext/sodium/tests/crypto_stream.phpt b/ext/sodium/tests/crypto_stream.phpt new file mode 100644 index 0000000000..7439e289b8 --- /dev/null +++ b/ext/sodium/tests/crypto_stream.phpt @@ -0,0 +1,52 @@ +--TEST-- +Check for libsodium stream +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$nonce = random_bytes(SODIUM_CRYPTO_STREAM_NONCEBYTES); +$key = random_bytes(SODIUM_CRYPTO_STREAM_KEYBYTES); + +$len = 100; +$stream = sodium_crypto_stream($len, $nonce, $key); +var_dump(strlen($stream)); + +$stream2 = sodium_crypto_stream($len, $nonce, $key); + +$nonce = random_bytes(SODIUM_CRYPTO_STREAM_NONCEBYTES); +$stream3 = sodium_crypto_stream($len, $nonce, $key); + +$key = random_bytes(SODIUM_CRYPTO_STREAM_KEYBYTES); +$stream4 = sodium_crypto_stream($len, $nonce, $key); + +var_dump($stream === $stream2); +var_dump($stream !== $stream3); +var_dump($stream !== $stream4); +var_dump($stream2 !== $stream3); +var_dump($stream2 !== $stream4); +var_dump($stream3 !== $stream4); + +$stream5 = sodium_crypto_stream_xor($stream, $nonce, $key); +var_dump($stream5 !== $stream); +$stream6 = sodium_crypto_stream_xor($stream5, $nonce, $key); + +var_dump($stream6 === $stream); + +try { + sodium_crypto_stream($len, substr($nonce, 1), $key); +} catch (SodiumException $ex) { + var_dump(true); +} + +?> +--EXPECT-- +int(100) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/sodium/tests/exception_trace_without_args.phpt b/ext/sodium/tests/exception_trace_without_args.phpt new file mode 100644 index 0000000000..c821df0eb5 --- /dev/null +++ b/ext/sodium/tests/exception_trace_without_args.phpt @@ -0,0 +1,22 @@ +--TEST-- +SodiumException backtraces do not contain function arguments +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php + +function do_memzero($x) { + sodium_memzero($x); +} + +$x = 42; +do_memzero($x); + +?> +--EXPECTF-- +Fatal error: Uncaught SodiumException: memzero: a PHP string is required in %s:%d +Stack trace: +#0 %s(%d): sodium_memzero() +#1 %s(%d): do_memzero() +#2 {main} + thrown in %s on line %d diff --git a/ext/sodium/tests/inc_add.phpt b/ext/sodium/tests/inc_add.phpt new file mode 100644 index 0000000000..2ab9b92696 --- /dev/null +++ b/ext/sodium/tests/inc_add.phpt @@ -0,0 +1,55 @@ +--TEST-- +increment and add edge cases +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php + +$notStr = 123; +try { + sodium_increment($notStr); +} catch (SodiumException $e) { + echo $e->getMessage(), "\n"; +} + +$str = "abc"; +$str2 = $str; +sodium_increment($str); +var_dump($str, $str2); + +$str = "ab" . ($x = "c"); +$str2 = $str; +sodium_increment($str); +var_dump($str, $str2); + +$addStr = "\2\0\0"; + +$notStr = 123; +try { + sodium_add($notStr, $addStr); +} catch (SodiumException $e) { + echo $e->getMessage(), "\n"; +} + +$str = "abc"; +$str2 = $str; +sodium_add($str, $addStr); +var_dump($str, $str2); + +$str = "ab" . ($x = "c"); +$str2 = $str; +sodium_add($str, $addStr); +var_dump($str, $str2); + +?> +--EXPECT-- +increment(): a PHP string is required +string(3) "bbc" +string(3) "abc" +string(3) "bbc" +string(3) "abc" +add(): PHP strings are required +string(3) "cbc" +string(3) "abc" +string(3) "cbc" +string(3) "abc" diff --git a/ext/sodium/tests/installed.phpt b/ext/sodium/tests/installed.phpt new file mode 100644 index 0000000000..43ad4fdd86 --- /dev/null +++ b/ext/sodium/tests/installed.phpt @@ -0,0 +1,21 @@ +--TEST-- +Check for libsodium presence +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +echo "libsodium extension is available"; +/* + you can add regression tests for your extension here + + the output of your test code has to be equal to the + text in the --EXPECT-- section below for the tests + to pass, differences between the output and the + expected text are interpreted as failure + + see php5/README.TESTING for further information on + writing regression tests +*/ +?> +--EXPECT-- +libsodium extension is available diff --git a/ext/sodium/tests/pwhash_argon2i.phpt b/ext/sodium/tests/pwhash_argon2i.phpt new file mode 100644 index 0000000000..eb36223b87 --- /dev/null +++ b/ext/sodium/tests/pwhash_argon2i.phpt @@ -0,0 +1,44 @@ +--TEST-- +Check for libsodium utils +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; +if (!defined('SODIUM_CRYPTO_PWHASH_SALTBYTES')) print "skip libsodium without argon2i"; ?> +--FILE-- +<?php +$passwd = 'password'; + +$hash = sodium_crypto_pwhash_str + ($passwd, SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE); +var_dump(substr($hash, 0, 9) === + SODIUM_CRYPTO_PWHASH_STRPREFIX); + +$testHash = '$argon2i$v=19$m=4096,t=3,p=1$MzE4ODFiZWFlMjAzOWUAAA$FWUV6tsyJ32qThiLi1cCsLIbf3dIOG/RwXcTzt536KY'; +$c = sodium_crypto_pwhash_str_verify($testHash, $passwd); +var_dump($c); + +$testHash = '$argon2i$v=19$m=4096,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA$JTBozgKQiCn5yKAm3Hz0vUSX/XgfqhZloNCxDWmeDr0'; +$c = sodium_crypto_pwhash_str_verify($testHash, $passwd); +var_dump($c); + +$c = sodium_crypto_pwhash_str_verify($hash, $passwd); +var_dump($c); + +$c = sodium_crypto_pwhash_str_verify($hash, 'passwd'); +var_dump($c); + +$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES); +$out_len = 100; +$key = sodium_crypto_pwhash + ($out_len, $passwd, $salt, + SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE); +var_dump(strlen($key) === $out_len); +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) diff --git a/ext/sodium/tests/pwhash_scrypt.phpt b/ext/sodium/tests/pwhash_scrypt.phpt new file mode 100644 index 0000000000..e5a204926c --- /dev/null +++ b/ext/sodium/tests/pwhash_scrypt.phpt @@ -0,0 +1,33 @@ +--TEST-- +Check for libsodium utils +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$passwd = 'test'; + +$hash = sodium_crypto_pwhash_scryptsalsa208sha256_str + ($passwd, SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE, + SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE); +var_dump(substr($hash, 0, 3) === + SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX); + +$c = sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($hash, $passwd); +var_dump($c); + +$c = sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($hash, 'passwd'); +var_dump($c); + +$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES); +$out_len = 100; +$key = sodium_crypto_pwhash_scryptsalsa208sha256 + ($out_len, $passwd, $salt, + SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE, + SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE); +var_dump(strlen($key) === $out_len); +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(true) diff --git a/ext/sodium/tests/utils.phpt b/ext/sodium/tests/utils.phpt new file mode 100644 index 0000000000..c413e01a81 --- /dev/null +++ b/ext/sodium/tests/utils.phpt @@ -0,0 +1,62 @@ +--TEST-- +Check for libsodium utils +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +$a = 'test'; +sodium_memzero($a); +if ($a !== 'test') { + echo strlen($a); +} else { + echo $a; +} +echo "\n"; +$b = 'string'; +$c = 'string'; +var_dump(!sodium_memcmp($b, $c)); +var_dump(!sodium_memcmp($b, 'String')); +$v = "\xFF\xFF\x80\x01\x02\x03\x04\x05\x06\x07"; +$v .= "\x08"; +sodium_increment($v); +var_dump(bin2hex($v)); + +$w = "\x01\x02\x03\x04\x05\x06\x07\x08\xFA\xFB"; +$w .= "\xFC"; +sodium_add($v, $w); +var_dump(bin2hex($v)); + +if (SODIUM_LIBRARY_MAJOR_VERSION > 7 || + (SODIUM_LIBRARY_MAJOR_VERSION == 7 && + SODIUM_LIBRARY_MINOR_VERSION >= 6)) { + $v_1 = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + $v_2 = ""."\x02\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + $v_1 .= ''; + var_dump(sodium_compare($v_1, $v_2)); + sodium_increment($v_1); + var_dump(sodium_compare($v_1, $v_2)); + sodium_increment($v_1); + var_dump(sodium_compare($v_1, $v_2)); +} else { + // Dummy test results for libsodium < 1.0.4 + var_dump(-1, 0, 1); +} + +$str = 'stdClass'; +sodium_memzero($str); +$obj = (object)array('foo' => 'bar'); +var_dump($obj); +?> +--EXPECT-- +0 +bool(true) +bool(false) +string(22) "0000810102030405060708" +string(22) "0102840507090b0d000305" +int(-1) +int(0) +int(1) +object(stdClass)#1 (1) { + ["foo"]=> + string(3) "bar" +} diff --git a/ext/sodium/tests/version.phpt b/ext/sodium/tests/version.phpt new file mode 100644 index 0000000000..f13345ea07 --- /dev/null +++ b/ext/sodium/tests/version.phpt @@ -0,0 +1,17 @@ +--TEST-- +Check for libsodium version +--SKIPIF-- +<?php if (!extension_loaded("sodium")) print "skip"; ?> +--FILE-- +<?php +echo strlen(SODIUM_LIBRARY_VERSION) >= 5; +echo "\n"; +echo SODIUM_LIBRARY_MAJOR_VERSION >= 4; +echo "\n"; +echo SODIUM_LIBRARY_MINOR_VERSION >= 0; +?> +--EXPECT-- +1 +1 +1 + |