xref: /php-src/ext/sodium/libsodium.c (revision fd2d8696)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Frank Denis <jedisct1@php.net>                              |
14    +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include "ext/standard/info.h"
23 #include "php_libsodium.h"
24 #include "zend_attributes.h"
25 #include "zend_exceptions.h"
26 
27 #include <sodium.h>
28 #include <stdint.h>
29 #include <string.h>
30 
31 #define PHP_SODIUM_ZSTR_TRUNCATE(zs, len) do { ZSTR_LEN(zs) = (len); } while(0)
32 
33 static zend_class_entry *sodium_exception_ce;
34 
35 #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(__i386__) || \
36 	 defined(_M_AMD64) || defined(_M_IX86) || defined(__aarch64__) || defined(_M_ARM64))
37 # define HAVE_AESGCM 1
38 #endif
39 
zend_string_checked_alloc(size_t len,int persistent)40 static zend_always_inline zend_string *zend_string_checked_alloc(size_t len, int persistent)
41 {
42 	zend_string *zs;
43 
44 	if (ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)) < len) {
45 		zend_error_noreturn(E_ERROR, "Memory allocation too large (%zu bytes)", len);
46 	}
47 	zs = zend_string_alloc(len, persistent);
48 	ZSTR_VAL(zs)[len] = 0;
49 
50 	return zs;
51 }
52 
53 #ifndef crypto_kdf_BYTES_MIN
54 # define crypto_kdf_BYTES_MIN 16
55 # define crypto_kdf_BYTES_MAX 64
56 # define crypto_kdf_CONTEXTBYTES 8
57 # define crypto_kdf_KEYBYTES 32
58 #endif
59 
60 #ifndef crypto_kx_SEEDBYTES
61 # define crypto_kx_SEEDBYTES 32
62 # define crypto_kx_SESSIONKEYBYTES 32
63 # define crypto_kx_PUBLICKEYBYTES 32
64 # define crypto_kx_SECRETKEYBYTES 32
65 #endif
66 
67 #include "libsodium_arginfo.h"
68 
69 #ifndef crypto_aead_chacha20poly1305_IETF_KEYBYTES
70 # define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_KEYBYTES
71 #endif
72 #ifndef crypto_aead_chacha20poly1305_IETF_NSECBYTES
73 # define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_NSECBYTES
74 #endif
75 #ifndef crypto_aead_chacha20poly1305_IETF_ABYTES
76 # define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ABYTES
77 #endif
78 
79 #if defined(crypto_secretstream_xchacha20poly1305_ABYTES) && SODIUM_LIBRARY_VERSION_MAJOR < 10
80 # undef crypto_secretstream_xchacha20poly1305_ABYTES
81 #endif
82 
83 #ifndef crypto_pwhash_OPSLIMIT_MIN
84 # define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_OPSLIMIT_INTERACTIVE
85 #endif
86 #ifndef crypto_pwhash_MEMLIMIT_MIN
87 # define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_MEMLIMIT_INTERACTIVE
88 #endif
89 #ifndef crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN
90 # define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE
91 #endif
92 #ifndef crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN
93 # define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE
94 #endif
95 
96 /* Load after the "standard" module in order to give it
97  * priority in registering argon2i/argon2id password hashers.
98  */
99 static const zend_module_dep sodium_deps[] = {
100 	ZEND_MOD_REQUIRED("standard")
101 	ZEND_MOD_END
102 };
103 
104 zend_module_entry sodium_module_entry = {
105 	STANDARD_MODULE_HEADER_EX,
106 	NULL,
107 	sodium_deps,
108 	"sodium",
109 	ext_functions,
110 	PHP_MINIT(sodium),
111 	PHP_MSHUTDOWN(sodium),
112 	NULL,
113 	NULL,
114 	PHP_MINFO(sodium),
115 	PHP_SODIUM_VERSION,
116 	STANDARD_MODULE_PROPERTIES
117 };
118 /* }}} */
119 
120 #ifdef COMPILE_DL_SODIUM
ZEND_GET_MODULE(sodium)121 ZEND_GET_MODULE(sodium)
122 #endif
123 
124 /* Remove argument information from backtrace to prevent information leaks */
125 static void sodium_remove_param_values_from_backtrace(zend_object *obj) {
126 	zval rv;
127 	zval *trace = zend_read_property_ex(zend_get_exception_base(obj), obj, ZSTR_KNOWN(ZEND_STR_TRACE), /* silent */ false, &rv);
128 	if (trace && Z_TYPE_P(trace) == IS_ARRAY) {
129 		zval *frame;
130 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(trace), frame) {
131 			if (Z_TYPE_P(frame) == IS_ARRAY) {
132 				zval *args = zend_hash_find(Z_ARRVAL_P(frame), ZSTR_KNOWN(ZEND_STR_ARGS));
133 				if (args) {
134 					zval_ptr_dtor(args);
135 					ZVAL_EMPTY_ARRAY(args);
136 				}
137 			}
138 		} ZEND_HASH_FOREACH_END();
139 	}
140 }
141 
sodium_exception_create_object(zend_class_entry * ce)142 static zend_object *sodium_exception_create_object(zend_class_entry *ce) {
143 	zend_object *obj = zend_ce_exception->create_object(ce);
144 	sodium_remove_param_values_from_backtrace(obj);
145 	return obj;
146 }
147 
sodium_separate_string(zval * zv)148 static void sodium_separate_string(zval *zv) {
149 	ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
150 	if (!Z_REFCOUNTED_P(zv) || Z_REFCOUNT_P(zv) > 1) {
151 		zend_string *copy = zend_string_init(Z_STRVAL_P(zv), Z_STRLEN_P(zv), 0);
152 		Z_TRY_DELREF_P(zv);
153 		ZVAL_STR(zv, copy);
154 	}
155 }
156 
PHP_MINIT_FUNCTION(sodium)157 PHP_MINIT_FUNCTION(sodium)
158 {
159 	if (sodium_init() < 0) {
160 		zend_error_noreturn(E_ERROR, "sodium_init()");
161 	}
162 
163 	sodium_exception_ce = register_class_SodiumException(zend_ce_exception);
164 	sodium_exception_ce->create_object = sodium_exception_create_object;
165 
166 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
167 	if (FAILURE == PHP_MINIT(sodium_password_hash)(INIT_FUNC_ARGS_PASSTHRU)) {
168 		return FAILURE;
169 	}
170 #endif
171 
172 	register_libsodium_symbols(module_number);
173 
174 	return SUCCESS;
175 }
176 
PHP_MSHUTDOWN_FUNCTION(sodium)177 PHP_MSHUTDOWN_FUNCTION(sodium)
178 {
179 	randombytes_close();
180 	return SUCCESS;
181 }
182 
PHP_MINFO_FUNCTION(sodium)183 PHP_MINFO_FUNCTION(sodium)
184 {
185 	php_info_print_table_start();
186 	php_info_print_table_row(2, "sodium support", "enabled");
187 	php_info_print_table_row(2, "libsodium headers version", SODIUM_VERSION_STRING);
188 	php_info_print_table_row(2, "libsodium library version", sodium_version_string());
189 	php_info_print_table_end();
190 }
191 
PHP_FUNCTION(sodium_memzero)192 PHP_FUNCTION(sodium_memzero)
193 {
194 	zval      *buf_zv;
195 
196 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
197 									"z", &buf_zv) == FAILURE) {
198 		sodium_remove_param_values_from_backtrace(EG(exception));
199 		RETURN_THROWS();
200 	}
201 	ZVAL_DEREF(buf_zv);
202 	if (Z_TYPE_P(buf_zv) != IS_STRING) {
203 		zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0);
204 		RETURN_THROWS();
205 	}
206 	if (Z_REFCOUNTED_P(buf_zv) && Z_REFCOUNT_P(buf_zv) == 1) {
207 		char *buf = Z_STRVAL(*buf_zv);
208 		size_t buf_len = Z_STRLEN(*buf_zv);
209 		if (buf_len > 0) {
210 			sodium_memzero(buf, (size_t) buf_len);
211 		}
212 	}
213 	convert_to_null(buf_zv);
214 }
215 
PHP_FUNCTION(sodium_increment)216 PHP_FUNCTION(sodium_increment)
217 {
218 	zval          *val_zv;
219 	unsigned char *val;
220 	size_t         val_len;
221 
222 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
223 									"z", &val_zv) == FAILURE) {
224 		sodium_remove_param_values_from_backtrace(EG(exception));
225 		RETURN_THROWS();
226 	}
227 	ZVAL_DEREF(val_zv);
228 	if (Z_TYPE_P(val_zv) != IS_STRING) {
229 		zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0);
230 		RETURN_THROWS();
231 	}
232 
233 	sodium_separate_string(val_zv);
234 	val = (unsigned char *) Z_STRVAL(*val_zv);
235 	val_len = Z_STRLEN(*val_zv);
236 	sodium_increment(val, val_len);
237 }
238 
PHP_FUNCTION(sodium_add)239 PHP_FUNCTION(sodium_add)
240 {
241 	zval          *val_zv;
242 	unsigned char *val;
243 	unsigned char *addv;
244 	size_t         val_len;
245 	size_t         addv_len;
246 
247 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
248 									"zs", &val_zv, &addv, &addv_len) == FAILURE) {
249 		sodium_remove_param_values_from_backtrace(EG(exception));
250 		RETURN_THROWS();
251 	}
252 	ZVAL_DEREF(val_zv);
253 	if (Z_TYPE_P(val_zv) != IS_STRING) {
254 		zend_throw_exception(sodium_exception_ce, "PHP strings are required", 0);
255 		RETURN_THROWS();
256 	}
257 
258 	sodium_separate_string(val_zv);
259 	val = (unsigned char *) Z_STRVAL(*val_zv);
260 	val_len = Z_STRLEN(*val_zv);
261 	if (val_len != addv_len) {
262 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
263 		RETURN_THROWS();
264 	}
265 	sodium_add(val, addv, val_len);
266 }
267 
PHP_FUNCTION(sodium_memcmp)268 PHP_FUNCTION(sodium_memcmp)
269 {
270 	char      *buf1;
271 	char      *buf2;
272 	size_t     len1;
273 	size_t     len2;
274 
275 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
276 									&buf1, &len1,
277 									&buf2, &len2) == FAILURE) {
278 		sodium_remove_param_values_from_backtrace(EG(exception));
279 		RETURN_THROWS();
280 	}
281 	if (len1 != len2) {
282 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
283 		RETURN_THROWS();
284 	}
285 	RETURN_LONG(sodium_memcmp(buf1, buf2, len1));
286 }
287 
PHP_FUNCTION(sodium_crypto_shorthash)288 PHP_FUNCTION(sodium_crypto_shorthash)
289 {
290 	zend_string   *hash;
291 	unsigned char *key;
292 	unsigned char *msg;
293 	size_t         key_len;
294 	size_t         msg_len;
295 
296 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
297 									&msg, &msg_len,
298 									&key, &key_len) == FAILURE) {
299 		sodium_remove_param_values_from_backtrace(EG(exception));
300 		RETURN_THROWS();
301 	}
302 	if (key_len != crypto_shorthash_KEYBYTES) {
303 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SHORTHASH_KEYBYTES bytes long");
304 		RETURN_THROWS();
305 	}
306 	hash = zend_string_alloc(crypto_shorthash_BYTES, 0);
307 	if (crypto_shorthash((unsigned char *) ZSTR_VAL(hash), msg,
308 						 (unsigned long long) msg_len, key) != 0) {
309 		zend_string_efree(hash);
310 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
311 		RETURN_THROWS();
312 	}
313 	ZSTR_VAL(hash)[crypto_shorthash_BYTES] = 0;
314 
315 	RETURN_NEW_STR(hash);
316 }
317 
PHP_FUNCTION(sodium_crypto_secretbox)318 PHP_FUNCTION(sodium_crypto_secretbox)
319 {
320 	zend_string   *ciphertext;
321 	unsigned char *key;
322 	unsigned char *msg;
323 	unsigned char *nonce;
324 	size_t         key_len;
325 	size_t         msg_len;
326 	size_t         nonce_len;
327 
328 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
329 									&msg, &msg_len,
330 									&nonce, &nonce_len,
331 									&key, &key_len) == FAILURE) {
332 		sodium_remove_param_values_from_backtrace(EG(exception));
333 		RETURN_THROWS();
334 	}
335 	if (nonce_len != crypto_secretbox_NONCEBYTES) {
336 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETBOX_NONCEBYTES bytes long");
337 		RETURN_THROWS();
338 	}
339 	if (key_len != crypto_secretbox_KEYBYTES) {
340 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long");
341 		RETURN_THROWS();
342 	}
343 	if (SIZE_MAX - msg_len <= crypto_secretbox_MACBYTES) {
344 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
345 		RETURN_THROWS();
346 	}
347 	ciphertext = zend_string_alloc((size_t) msg_len + crypto_secretbox_MACBYTES, 0);
348 	if (crypto_secretbox_easy((unsigned char *) ZSTR_VAL(ciphertext),
349 							  msg, (unsigned long long) msg_len,
350 							  nonce, key) != 0) {
351 		zend_string_efree(ciphertext);
352 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
353 		RETURN_THROWS();
354 	}
355 	ZSTR_VAL(ciphertext)[msg_len + crypto_secretbox_MACBYTES] = 0;
356 
357 	RETURN_NEW_STR(ciphertext);
358 }
359 
PHP_FUNCTION(sodium_crypto_secretbox_open)360 PHP_FUNCTION(sodium_crypto_secretbox_open)
361 {
362 	zend_string   *msg;
363 	unsigned char *key;
364 	unsigned char *ciphertext;
365 	unsigned char *nonce;
366 	size_t         key_len;
367 	size_t         ciphertext_len;
368 	size_t         nonce_len;
369 
370 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
371 									&ciphertext, &ciphertext_len,
372 									&nonce, &nonce_len,
373 									&key, &key_len) == FAILURE) {
374 		sodium_remove_param_values_from_backtrace(EG(exception));
375 		RETURN_THROWS();
376 	}
377 	if (nonce_len != crypto_secretbox_NONCEBYTES) {
378 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETBOX_NONCEBYTES bytes long");
379 		RETURN_THROWS();
380 	}
381 	if (key_len != crypto_secretbox_KEYBYTES) {
382 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long");
383 		RETURN_THROWS();
384 	}
385 	if (ciphertext_len < crypto_secretbox_MACBYTES) {
386 		RETURN_FALSE;
387 	}
388 	msg = zend_string_alloc
389 		((size_t) ciphertext_len - crypto_secretbox_MACBYTES, 0);
390 	if (crypto_secretbox_open_easy((unsigned char *) ZSTR_VAL(msg), ciphertext,
391 								   (unsigned long long) ciphertext_len,
392 								   nonce, key) != 0) {
393 		zend_string_efree(msg);
394 		RETURN_FALSE;
395 	} else {
396 		ZSTR_VAL(msg)[ciphertext_len - crypto_secretbox_MACBYTES] = 0;
397 		RETURN_NEW_STR(msg);
398 	}
399 }
400 
PHP_FUNCTION(sodium_crypto_generichash)401 PHP_FUNCTION(sodium_crypto_generichash)
402 {
403 	zend_string   *hash;
404 	unsigned char *key = NULL;
405 	unsigned char *msg;
406 	zend_long      hash_len = crypto_generichash_BYTES;
407 	size_t         key_len = 0;
408 	size_t         msg_len;
409 
410 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sl",
411 									&msg, &msg_len,
412 									&key, &key_len,
413 									&hash_len) == FAILURE) {
414 		sodium_remove_param_values_from_backtrace(EG(exception));
415 		RETURN_THROWS();
416 	}
417 	if (hash_len < crypto_generichash_BYTES_MIN ||
418 		hash_len > crypto_generichash_BYTES_MAX) {
419 		zend_throw_exception(sodium_exception_ce, "unsupported output length", 0);
420 		RETURN_THROWS();
421 	}
422 	if (key_len != 0 &&
423 		(key_len < crypto_generichash_KEYBYTES_MIN ||
424 		 key_len > crypto_generichash_KEYBYTES_MAX)) {
425 		zend_throw_exception(sodium_exception_ce, "unsupported key length", 0);
426 		RETURN_THROWS();
427 	}
428 	hash = zend_string_alloc(hash_len, 0);
429 	if (crypto_generichash((unsigned char *) ZSTR_VAL(hash), (size_t) hash_len,
430 						   msg, (unsigned long long) msg_len,
431 						   key, (size_t) key_len) != 0) {
432 		zend_string_efree(hash);
433 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
434 		RETURN_THROWS();
435 	}
436 	ZSTR_VAL(hash)[hash_len] = 0;
437 
438 	RETURN_NEW_STR(hash);
439 }
440 
PHP_FUNCTION(sodium_crypto_generichash_init)441 PHP_FUNCTION(sodium_crypto_generichash_init)
442 {
443 	crypto_generichash_state  state_tmp;
444 	zend_string              *state;
445 	unsigned char            *key = NULL;
446 	size_t                    state_len = sizeof (crypto_generichash_state);
447 	zend_long                 hash_len = crypto_generichash_BYTES;
448 	size_t                    key_len = 0;
449 
450 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sl",
451 									&key, &key_len,
452 									&hash_len) == FAILURE) {
453 		sodium_remove_param_values_from_backtrace(EG(exception));
454 		RETURN_THROWS();
455 	}
456 	if (hash_len < crypto_generichash_BYTES_MIN ||
457 		hash_len > crypto_generichash_BYTES_MAX) {
458 		zend_throw_exception(sodium_exception_ce, "unsupported output length", 0);
459 		RETURN_THROWS();
460 	}
461 	if (key_len != 0 &&
462 		(key_len < crypto_generichash_KEYBYTES_MIN ||
463 		 key_len > crypto_generichash_KEYBYTES_MAX)) {
464 		zend_throw_exception(sodium_exception_ce, "unsupported key length", 0);
465 		RETURN_THROWS();
466 	}
467 	memset(&state_tmp, 0, sizeof state_tmp);
468 	if (crypto_generichash_init((void *) &state_tmp, key, (size_t) key_len,
469 								(size_t) hash_len) != 0) {
470 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
471 		RETURN_THROWS();
472 	}
473 	state = zend_string_alloc(state_len, 0);
474 	memcpy(ZSTR_VAL(state), &state_tmp, state_len);
475 	sodium_memzero(&state_tmp, sizeof state_tmp);
476 	ZSTR_VAL(state)[state_len] = 0;
477 
478 	RETURN_STR(state);
479 }
480 
PHP_FUNCTION(sodium_crypto_generichash_update)481 PHP_FUNCTION(sodium_crypto_generichash_update)
482 {
483 	crypto_generichash_state  state_tmp;
484 	zval                     *state_zv;
485 	unsigned char            *msg;
486 	unsigned char            *state;
487 	size_t                    msg_len;
488 	size_t                    state_len;
489 
490 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs",
491 									&state_zv, &msg, &msg_len) == FAILURE) {
492 		sodium_remove_param_values_from_backtrace(EG(exception));
493 		RETURN_THROWS();
494 	}
495 	ZVAL_DEREF(state_zv);
496 	if (Z_TYPE_P(state_zv) != IS_STRING) {
497 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
498 		RETURN_THROWS();
499 	}
500 	sodium_separate_string(state_zv);
501 	state = (unsigned char *) Z_STRVAL(*state_zv);
502 	state_len = Z_STRLEN(*state_zv);
503 	if (state_len != sizeof (crypto_generichash_state)) {
504 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
505 		RETURN_THROWS();
506 	}
507 	memcpy(&state_tmp, state, sizeof state_tmp);
508 	if (crypto_generichash_update((void *) &state_tmp, msg,
509 								  (unsigned long long) msg_len) != 0) {
510 		sodium_memzero(&state_tmp, sizeof state_tmp);
511 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
512 		RETURN_THROWS();
513 	}
514 	memcpy(state, &state_tmp, state_len);
515 	sodium_memzero(&state_tmp, sizeof state_tmp);
516 
517 	RETURN_TRUE;
518 }
519 
PHP_FUNCTION(sodium_crypto_generichash_final)520 PHP_FUNCTION(sodium_crypto_generichash_final)
521 {
522 	crypto_generichash_state  state_tmp;
523 	zend_string              *hash;
524 	zval                     *state_zv;
525 	unsigned char            *state;
526 	size_t                    state_len;
527 	zend_long                 hash_len = crypto_generichash_BYTES;
528 
529 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l",
530 									&state_zv, &hash_len) == FAILURE) {
531 		sodium_remove_param_values_from_backtrace(EG(exception));
532 		RETURN_THROWS();
533 	}
534 	ZVAL_DEREF(state_zv);
535 	if (Z_TYPE_P(state_zv) != IS_STRING) {
536 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
537 		RETURN_THROWS();
538 	}
539 	sodium_separate_string(state_zv);
540 	state = (unsigned char *) Z_STRVAL(*state_zv);
541 	state_len = Z_STRLEN(*state_zv);
542 	if (state_len != sizeof (crypto_generichash_state)) {
543 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
544 		RETURN_THROWS();
545 	}
546 	if (hash_len < crypto_generichash_BYTES_MIN ||
547 		hash_len > crypto_generichash_BYTES_MAX) {
548 		zend_throw_exception(sodium_exception_ce, "unsupported output length", 0);
549 		RETURN_THROWS();
550 	}
551 	hash = zend_string_alloc(hash_len, 0);
552 	memcpy(&state_tmp, state, sizeof state_tmp);
553 	if (crypto_generichash_final((void *) &state_tmp,
554 								 (unsigned char *) ZSTR_VAL(hash),
555 								 (size_t) hash_len) != 0) {
556 		sodium_memzero(&state_tmp, sizeof state_tmp);
557 		zend_string_efree(hash);
558 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
559 		RETURN_THROWS();
560 	}
561 	sodium_memzero(&state_tmp, sizeof state_tmp);
562 	sodium_memzero(state, state_len);
563 	convert_to_null(state_zv);
564 	ZSTR_VAL(hash)[hash_len] = 0;
565 
566 	RETURN_NEW_STR(hash);
567 }
568 
PHP_FUNCTION(sodium_crypto_box_keypair)569 PHP_FUNCTION(sodium_crypto_box_keypair)
570 {
571 	zend_string *keypair;
572 	size_t       keypair_len;
573 
574 	if (zend_parse_parameters_none() == FAILURE) {
575 		RETURN_THROWS();
576 	}
577 	keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES;
578 	keypair = zend_string_alloc(keypair_len, 0);
579 	if (crypto_box_keypair((unsigned char *) ZSTR_VAL(keypair) +
580 						   crypto_box_SECRETKEYBYTES,
581 						   (unsigned char *) ZSTR_VAL(keypair)) != 0) {
582 		zend_string_efree(keypair);
583 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
584 		RETURN_THROWS();
585 	}
586 	ZSTR_VAL(keypair)[keypair_len] = 0;
587 
588 	RETURN_NEW_STR(keypair);
589 }
590 
PHP_FUNCTION(sodium_crypto_box_seed_keypair)591 PHP_FUNCTION(sodium_crypto_box_seed_keypair)
592 {
593 	zend_string   *keypair;
594 	unsigned char *seed;
595 	size_t         keypair_len;
596 	size_t         seed_len;
597 
598 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
599 									&seed, &seed_len) == FAILURE) {
600 		sodium_remove_param_values_from_backtrace(EG(exception));
601 		RETURN_THROWS();
602 	}
603 	if (seed_len != crypto_box_SEEDBYTES) {
604 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_SEEDBYTES bytes long");
605 		RETURN_THROWS();
606 	}
607 	keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES;
608 	keypair = zend_string_alloc(keypair_len, 0);
609 	if (crypto_box_seed_keypair((unsigned char *) ZSTR_VAL(keypair) +
610 								 crypto_box_SECRETKEYBYTES,
611 								 (unsigned char *) ZSTR_VAL(keypair),
612 								 seed) != 0) {
613 		zend_string_efree(keypair);
614 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
615 		RETURN_THROWS();
616 	}
617 	ZSTR_VAL(keypair)[keypair_len] = 0;
618 
619 	RETURN_NEW_STR(keypair);
620 }
621 
PHP_FUNCTION(sodium_crypto_box_keypair_from_secretkey_and_publickey)622 PHP_FUNCTION(sodium_crypto_box_keypair_from_secretkey_and_publickey)
623 {
624 	zend_string *keypair;
625 	char        *publickey;
626 	char        *secretkey;
627 	size_t       keypair_len;
628 	size_t       publickey_len;
629 	size_t       secretkey_len;
630 
631 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
632 									&secretkey, &secretkey_len,
633 									&publickey, &publickey_len) == FAILURE) {
634 		sodium_remove_param_values_from_backtrace(EG(exception));
635 		RETURN_THROWS();
636 	}
637 	if (secretkey_len != crypto_box_SECRETKEYBYTES) {
638 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_SECRETKEYBYTES bytes long");
639 		RETURN_THROWS();
640 	}
641 	if (publickey_len != crypto_box_PUBLICKEYBYTES) {
642 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_PUBLICKEYBYTES bytes long");
643 		RETURN_THROWS();
644 	}
645 	keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES;
646 	keypair = zend_string_alloc(keypair_len, 0);
647 	memcpy(ZSTR_VAL(keypair), secretkey, crypto_box_SECRETKEYBYTES);
648 	memcpy(ZSTR_VAL(keypair) + crypto_box_SECRETKEYBYTES, publickey,
649 		   crypto_box_PUBLICKEYBYTES);
650 	ZSTR_VAL(keypair)[keypair_len] = 0;
651 
652 	RETURN_STR(keypair);
653 }
654 
PHP_FUNCTION(sodium_crypto_box_secretkey)655 PHP_FUNCTION(sodium_crypto_box_secretkey)
656 {
657 	zend_string   *secretkey;
658 	unsigned char *keypair;
659 	size_t         keypair_len;
660 
661 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
662 									&keypair, &keypair_len) == FAILURE) {
663 		sodium_remove_param_values_from_backtrace(EG(exception));
664 		RETURN_THROWS();
665 	}
666 	if (keypair_len !=
667 		crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
668 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
669 		RETURN_THROWS();
670 	}
671 	secretkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0);
672 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_box_SECRETKEYBYTES);
673 	ZSTR_VAL(secretkey)[crypto_box_SECRETKEYBYTES] = 0;
674 
675 	RETURN_STR(secretkey);
676 }
677 
PHP_FUNCTION(sodium_crypto_box_publickey)678 PHP_FUNCTION(sodium_crypto_box_publickey)
679 {
680 	zend_string   *publickey;
681 	unsigned char *keypair;
682 	size_t         keypair_len;
683 
684 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
685 									&keypair, &keypair_len) == FAILURE) {
686 		sodium_remove_param_values_from_backtrace(EG(exception));
687 		RETURN_THROWS();
688 	}
689 	if (keypair_len !=
690 		crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
691 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
692 		RETURN_THROWS();
693 	}
694 	publickey = zend_string_alloc(crypto_box_PUBLICKEYBYTES, 0);
695 	memcpy(ZSTR_VAL(publickey), keypair + crypto_box_SECRETKEYBYTES,
696 		   crypto_box_PUBLICKEYBYTES);
697 	ZSTR_VAL(publickey)[crypto_box_PUBLICKEYBYTES] = 0;
698 
699 	RETURN_STR(publickey);
700 }
701 
PHP_FUNCTION(sodium_crypto_box_publickey_from_secretkey)702 PHP_FUNCTION(sodium_crypto_box_publickey_from_secretkey)
703 {
704 	zend_string   *publickey;
705 	unsigned char *secretkey;
706 	size_t         secretkey_len;
707 
708 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
709 									&secretkey, &secretkey_len) == FAILURE) {
710 		sodium_remove_param_values_from_backtrace(EG(exception));
711 		RETURN_THROWS();
712 	}
713 	if (secretkey_len != crypto_box_SECRETKEYBYTES) {
714 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_SECRETKEYBYTES bytes long");
715 		RETURN_THROWS();
716 	}
717 	publickey = zend_string_alloc(crypto_box_PUBLICKEYBYTES, 0);
718 	(void) sizeof(int[crypto_scalarmult_BYTES ==
719 					  crypto_box_PUBLICKEYBYTES ? 1 : -1]);
720 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES ==
721 					  crypto_box_SECRETKEYBYTES ? 1 : -1]);
722 	crypto_scalarmult_base((unsigned char *) ZSTR_VAL(publickey), secretkey);
723 	ZSTR_VAL(publickey)[crypto_box_PUBLICKEYBYTES] = 0;
724 
725 	RETURN_STR(publickey);
726 }
727 
PHP_FUNCTION(sodium_crypto_box)728 PHP_FUNCTION(sodium_crypto_box)
729 {
730 	zend_string   *ciphertext;
731 	unsigned char *keypair;
732 	unsigned char *msg;
733 	unsigned char *nonce;
734 	unsigned char *publickey;
735 	unsigned char *secretkey;
736 	size_t         keypair_len;
737 	size_t         msg_len;
738 	size_t         nonce_len;
739 
740 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
741 									&msg, &msg_len,
742 									&nonce, &nonce_len,
743 									&keypair, &keypair_len) == FAILURE) {
744 		sodium_remove_param_values_from_backtrace(EG(exception));
745 		RETURN_THROWS();
746 	}
747 	if (nonce_len != crypto_box_NONCEBYTES) {
748 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_NONCEBYTES bytes long");
749 		RETURN_THROWS();
750 	}
751 	if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
752 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
753 		RETURN_THROWS();
754 	}
755 	secretkey = keypair;
756 	publickey = keypair + crypto_box_SECRETKEYBYTES;
757 	if (SIZE_MAX - msg_len <= crypto_box_MACBYTES) {
758 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
759 		RETURN_THROWS();
760 	}
761 	ciphertext = zend_string_alloc((size_t) msg_len + crypto_box_MACBYTES, 0);
762 	if (crypto_box_easy((unsigned char *) ZSTR_VAL(ciphertext), msg,
763 						(unsigned long long) msg_len,
764 						nonce, publickey, secretkey) != 0) {
765 		zend_string_efree(ciphertext);
766 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
767 		RETURN_THROWS();
768 	}
769 	ZSTR_VAL(ciphertext)[msg_len + crypto_box_MACBYTES] = 0;
770 
771 	RETURN_NEW_STR(ciphertext);
772 }
773 
PHP_FUNCTION(sodium_crypto_box_open)774 PHP_FUNCTION(sodium_crypto_box_open)
775 {
776 	zend_string   *msg;
777 	unsigned char *ciphertext;
778 	unsigned char *keypair;
779 	unsigned char *nonce;
780 	unsigned char *publickey;
781 	unsigned char *secretkey;
782 	size_t         ciphertext_len;
783 	size_t         keypair_len;
784 	size_t         nonce_len;
785 
786 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
787 									&ciphertext, &ciphertext_len,
788 									&nonce, &nonce_len,
789 									&keypair, &keypair_len) == FAILURE) {
790 		sodium_remove_param_values_from_backtrace(EG(exception));
791 		RETURN_THROWS();
792 	}
793 	if (nonce_len != crypto_box_NONCEBYTES) {
794 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_NONCEBYTES bytes long");
795 		RETURN_THROWS();
796 	}
797 	if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
798 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
799 		RETURN_THROWS();
800 	}
801 	secretkey = keypair;
802 	publickey = keypair + crypto_box_SECRETKEYBYTES;
803 	if (ciphertext_len < crypto_box_MACBYTES) {
804 		RETURN_FALSE;
805 	}
806 	msg = zend_string_alloc((size_t) ciphertext_len - crypto_box_MACBYTES, 0);
807 	if (crypto_box_open_easy((unsigned char *) ZSTR_VAL(msg), ciphertext,
808 							 (unsigned long long) ciphertext_len,
809 							 nonce, publickey, secretkey) != 0) {
810 		zend_string_efree(msg);
811 		RETURN_FALSE;
812 	} else {
813 		ZSTR_VAL(msg)[ciphertext_len - crypto_box_MACBYTES] = 0;
814 		RETURN_NEW_STR(msg);
815 	}
816 }
817 
PHP_FUNCTION(sodium_crypto_box_seal)818 PHP_FUNCTION(sodium_crypto_box_seal)
819 {
820 	zend_string   *ciphertext;
821 	unsigned char *msg;
822 	unsigned char *publickey;
823 	size_t         msg_len;
824 	size_t         publickey_len;
825 
826 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
827 									&msg, &msg_len,
828 									&publickey, &publickey_len) == FAILURE) {
829 		sodium_remove_param_values_from_backtrace(EG(exception));
830 		RETURN_THROWS();
831 	}
832 	if (publickey_len != crypto_box_PUBLICKEYBYTES) {
833 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_PUBLICKEYBYTES bytes long");
834 		RETURN_THROWS();
835 	}
836 	if (SIZE_MAX - msg_len <= crypto_box_SEALBYTES) {
837 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
838 		RETURN_THROWS();
839 	}
840 	ciphertext = zend_string_alloc((size_t) msg_len + crypto_box_SEALBYTES, 0);
841 	if (crypto_box_seal((unsigned char *) ZSTR_VAL(ciphertext), msg,
842 						(unsigned long long) msg_len, publickey) != 0) {
843 		zend_string_efree(ciphertext);
844 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
845 		RETURN_THROWS();
846 	}
847 	ZSTR_VAL(ciphertext)[msg_len + crypto_box_SEALBYTES] = 0;
848 
849 	RETURN_NEW_STR(ciphertext);
850 }
851 
PHP_FUNCTION(sodium_crypto_box_seal_open)852 PHP_FUNCTION(sodium_crypto_box_seal_open)
853 {
854 	zend_string   *msg;
855 	unsigned char *ciphertext;
856 	unsigned char *keypair;
857 	unsigned char *publickey;
858 	unsigned char *secretkey;
859 	size_t         ciphertext_len;
860 	size_t         keypair_len;
861 
862 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
863 									&ciphertext, &ciphertext_len,
864 									&keypair, &keypair_len) == FAILURE) {
865 		sodium_remove_param_values_from_backtrace(EG(exception));
866 		RETURN_THROWS();
867 	}
868 	if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
869 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
870 		RETURN_THROWS();
871 	}
872 	secretkey = keypair;
873 	publickey = keypair + crypto_box_SECRETKEYBYTES;
874 	if (ciphertext_len < crypto_box_SEALBYTES) {
875 		RETURN_FALSE;
876 	}
877 	msg = zend_string_alloc((size_t) ciphertext_len - crypto_box_SEALBYTES, 0);
878 	if (crypto_box_seal_open((unsigned char *) ZSTR_VAL(msg), ciphertext,
879 							 (unsigned long long) ciphertext_len,
880 							 publickey, secretkey) != 0) {
881 		zend_string_efree(msg);
882 		RETURN_FALSE;
883 	} else {
884 		ZSTR_VAL(msg)[ciphertext_len - crypto_box_SEALBYTES] = 0;
885 		RETURN_NEW_STR(msg);
886 	}
887 }
888 
PHP_FUNCTION(sodium_crypto_sign_keypair)889 PHP_FUNCTION(sodium_crypto_sign_keypair)
890 {
891 	zend_string *keypair;
892 	size_t       keypair_len;
893 
894 	if (zend_parse_parameters_none() == FAILURE) {
895 		RETURN_THROWS();
896 	}
897 	keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES;
898 	keypair = zend_string_alloc(keypair_len, 0);
899 	if (crypto_sign_keypair((unsigned char *) ZSTR_VAL(keypair) +
900 							crypto_sign_SECRETKEYBYTES,
901 							(unsigned char *) ZSTR_VAL(keypair)) != 0) {
902 		zend_string_efree(keypair);
903 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
904 		RETURN_THROWS();
905 	}
906 	ZSTR_VAL(keypair)[keypair_len] = 0;
907 
908 	RETURN_NEW_STR(keypair);
909 }
910 
PHP_FUNCTION(sodium_crypto_sign_seed_keypair)911 PHP_FUNCTION(sodium_crypto_sign_seed_keypair)
912 {
913 	zend_string   *keypair;
914 	unsigned char *seed;
915 	size_t         keypair_len;
916 	size_t         seed_len;
917 
918 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
919 									&seed, &seed_len) == FAILURE) {
920 		sodium_remove_param_values_from_backtrace(EG(exception));
921 		RETURN_THROWS();
922 	}
923 	if (seed_len != crypto_sign_SEEDBYTES) {
924 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SEEDBYTES bytes long");
925 		RETURN_THROWS();
926 	}
927 	keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES;
928 	keypair = zend_string_alloc(keypair_len, 0);
929 	if (crypto_sign_seed_keypair((unsigned char *) ZSTR_VAL(keypair) +
930 								 crypto_sign_SECRETKEYBYTES,
931 								 (unsigned char *) ZSTR_VAL(keypair),
932 								 seed) != 0) {
933 		zend_string_efree(keypair);
934 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
935 		RETURN_THROWS();
936 	}
937 	ZSTR_VAL(keypair)[keypair_len] = 0;
938 
939 	RETURN_NEW_STR(keypair);
940 }
941 
PHP_FUNCTION(sodium_crypto_sign_keypair_from_secretkey_and_publickey)942 PHP_FUNCTION(sodium_crypto_sign_keypair_from_secretkey_and_publickey)
943 {
944 	zend_string *keypair;
945 	char        *publickey;
946 	char        *secretkey;
947 	size_t       keypair_len;
948 	size_t       publickey_len;
949 	size_t       secretkey_len;
950 
951 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
952 									&secretkey, &secretkey_len,
953 									&publickey, &publickey_len) == FAILURE) {
954 		sodium_remove_param_values_from_backtrace(EG(exception));
955 		RETURN_THROWS();
956 	}
957 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
958 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
959 		RETURN_THROWS();
960 	}
961 	if (publickey_len != crypto_sign_PUBLICKEYBYTES) {
962 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
963 		RETURN_THROWS();
964 	}
965 	keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES;
966 	keypair = zend_string_alloc(keypair_len, 0);
967 	memcpy(ZSTR_VAL(keypair), secretkey, crypto_sign_SECRETKEYBYTES);
968 	memcpy(ZSTR_VAL(keypair) + crypto_sign_SECRETKEYBYTES, publickey,
969 		   crypto_sign_PUBLICKEYBYTES);
970 	ZSTR_VAL(keypair)[keypair_len] = 0;
971 
972 	RETURN_STR(keypair);
973 }
974 
PHP_FUNCTION(sodium_crypto_sign_publickey_from_secretkey)975 PHP_FUNCTION(sodium_crypto_sign_publickey_from_secretkey)
976 {
977 	zend_string *publickey;
978 	char        *secretkey;
979 	size_t       secretkey_len;
980 
981 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
982 									&secretkey, &secretkey_len) == FAILURE) {
983 		sodium_remove_param_values_from_backtrace(EG(exception));
984 		RETURN_THROWS();
985 	}
986 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
987 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
988 		RETURN_THROWS();
989 	}
990 	publickey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
991 
992 	if (crypto_sign_ed25519_sk_to_pk((unsigned char *) ZSTR_VAL(publickey),
993 									 (const unsigned char *) secretkey) != 0) {
994 		zend_string_efree(publickey);
995 		zend_throw_exception(sodium_exception_ce,
996 				   "internal error", 0);
997 		RETURN_THROWS();
998 	}
999 	ZSTR_VAL(publickey)[crypto_sign_PUBLICKEYBYTES] = 0;
1000 
1001 	RETURN_STR(publickey);
1002 }
1003 
PHP_FUNCTION(sodium_crypto_sign_secretkey)1004 PHP_FUNCTION(sodium_crypto_sign_secretkey)
1005 {
1006 	zend_string   *secretkey;
1007 	unsigned char *keypair;
1008 	size_t         keypair_len;
1009 
1010 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1011 									&keypair, &keypair_len) == FAILURE) {
1012 		sodium_remove_param_values_from_backtrace(EG(exception));
1013 		RETURN_THROWS();
1014 	}
1015 	if (keypair_len !=
1016 		crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) {
1017 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_KEYPAIRBYTES bytes long");
1018 		RETURN_THROWS();
1019 	}
1020 	secretkey = zend_string_alloc(crypto_sign_SECRETKEYBYTES, 0);
1021 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_sign_SECRETKEYBYTES);
1022 	ZSTR_VAL(secretkey)[crypto_sign_SECRETKEYBYTES] = 0;
1023 
1024 	RETURN_STR(secretkey);
1025 }
1026 
PHP_FUNCTION(sodium_crypto_sign_publickey)1027 PHP_FUNCTION(sodium_crypto_sign_publickey)
1028 {
1029 	zend_string   *publickey;
1030 	unsigned char *keypair;
1031 	size_t         keypair_len;
1032 
1033 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1034 									&keypair, &keypair_len) == FAILURE) {
1035 		sodium_remove_param_values_from_backtrace(EG(exception));
1036 		RETURN_THROWS();
1037 	}
1038 	if (keypair_len !=
1039 		crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) {
1040 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_KEYPAIRBYTES bytes long");
1041 		RETURN_THROWS();
1042 	}
1043 	publickey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
1044 	memcpy(ZSTR_VAL(publickey), keypair + crypto_sign_SECRETKEYBYTES,
1045 		   crypto_sign_PUBLICKEYBYTES);
1046 	ZSTR_VAL(publickey)[crypto_sign_PUBLICKEYBYTES] = 0;
1047 
1048 	RETURN_STR(publickey);
1049 }
1050 
PHP_FUNCTION(sodium_crypto_sign)1051 PHP_FUNCTION(sodium_crypto_sign)
1052 {
1053 	zend_string        *msg_signed;
1054 	unsigned char      *msg;
1055 	unsigned char      *secretkey;
1056 	unsigned long long  msg_signed_real_len;
1057 	size_t              msg_len;
1058 	size_t              msg_signed_len;
1059 	size_t              secretkey_len;
1060 
1061 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1062 									&msg, &msg_len,
1063 									&secretkey, &secretkey_len) == FAILURE) {
1064 		sodium_remove_param_values_from_backtrace(EG(exception));
1065 		RETURN_THROWS();
1066 	}
1067 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
1068 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
1069 		RETURN_THROWS();
1070 	}
1071 	if (SIZE_MAX - msg_len <= crypto_sign_BYTES) {
1072 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1073 		RETURN_THROWS();
1074 	}
1075 	msg_signed_len = msg_len + crypto_sign_BYTES;
1076 	msg_signed = zend_string_alloc((size_t) msg_signed_len, 0);
1077 	if (crypto_sign((unsigned char *) ZSTR_VAL(msg_signed),
1078 					&msg_signed_real_len, msg,
1079 					(unsigned long long) msg_len, secretkey) != 0) {
1080 		zend_string_efree(msg_signed);
1081 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1082 		RETURN_THROWS();
1083 	}
1084 	if (msg_signed_real_len >= SIZE_MAX || msg_signed_real_len > msg_signed_len) {
1085 		zend_string_efree(msg_signed);
1086 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1087 		RETURN_THROWS();
1088 	}
1089 	PHP_SODIUM_ZSTR_TRUNCATE(msg_signed, (size_t) msg_signed_real_len);
1090 	ZSTR_VAL(msg_signed)[msg_signed_real_len] = 0;
1091 
1092 	RETURN_NEW_STR(msg_signed);
1093 }
1094 
PHP_FUNCTION(sodium_crypto_sign_open)1095 PHP_FUNCTION(sodium_crypto_sign_open)
1096 {
1097 	zend_string        *msg;
1098 	unsigned char      *msg_signed;
1099 	unsigned char      *publickey;
1100 	unsigned long long  msg_real_len;
1101 	size_t              msg_len;
1102 	size_t              msg_signed_len;
1103 	size_t              publickey_len;
1104 
1105 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1106 									&msg_signed, &msg_signed_len,
1107 									&publickey, &publickey_len) == FAILURE) {
1108 		sodium_remove_param_values_from_backtrace(EG(exception));
1109 		RETURN_THROWS();
1110 	}
1111 	if (publickey_len != crypto_sign_PUBLICKEYBYTES) {
1112 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
1113 		RETURN_THROWS();
1114 	}
1115 	msg_len = msg_signed_len;
1116 	if (msg_len >= SIZE_MAX) {
1117 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1118 		RETURN_THROWS();
1119 	}
1120 	msg = zend_string_alloc((size_t) msg_len, 0);
1121 	if (crypto_sign_open((unsigned char *) ZSTR_VAL(msg), &msg_real_len,
1122 						 msg_signed, (unsigned long long) msg_signed_len,
1123 						 publickey) != 0) {
1124 		zend_string_efree(msg);
1125 		RETURN_FALSE;
1126 	}
1127 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_signed_len) {
1128 		zend_string_efree(msg);
1129 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1130 		RETURN_THROWS();
1131 	}
1132 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
1133 	ZSTR_VAL(msg)[msg_real_len] = 0;
1134 
1135 	RETURN_NEW_STR(msg);
1136 }
1137 
PHP_FUNCTION(sodium_crypto_sign_detached)1138 PHP_FUNCTION(sodium_crypto_sign_detached)
1139 {
1140 	zend_string        *signature;
1141 	unsigned char      *msg;
1142 	unsigned char      *secretkey;
1143 	unsigned long long  signature_real_len;
1144 	size_t              msg_len;
1145 	size_t              secretkey_len;
1146 
1147 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1148 									&msg, &msg_len,
1149 									&secretkey, &secretkey_len) == FAILURE) {
1150 		sodium_remove_param_values_from_backtrace(EG(exception));
1151 		RETURN_THROWS();
1152 	}
1153 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
1154 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
1155 		RETURN_THROWS();
1156 	}
1157 	signature = zend_string_alloc((size_t) crypto_sign_BYTES, 0);
1158 	memset(ZSTR_VAL(signature), 0, (size_t) crypto_sign_BYTES);
1159 	if (crypto_sign_detached((unsigned char *) ZSTR_VAL(signature),
1160 							 &signature_real_len, msg,
1161 							 (unsigned long long) msg_len, secretkey) != 0) {
1162 		zend_string_efree(signature);
1163 		zend_throw_exception(sodium_exception_ce, "signature creation failed", 0);
1164 		RETURN_THROWS();
1165 	}
1166 	if (signature_real_len <= 0U || signature_real_len > crypto_sign_BYTES) {
1167 		zend_string_efree(signature);
1168 		zend_throw_exception(sodium_exception_ce, "signature has a bogus size", 0);
1169 		RETURN_THROWS();
1170 	}
1171 	PHP_SODIUM_ZSTR_TRUNCATE(signature, (size_t) signature_real_len);
1172 	ZSTR_VAL(signature)[signature_real_len] = 0;
1173 
1174 	RETURN_NEW_STR(signature);
1175 }
1176 
PHP_FUNCTION(sodium_crypto_sign_verify_detached)1177 PHP_FUNCTION(sodium_crypto_sign_verify_detached)
1178 {
1179 	unsigned char *msg;
1180 	unsigned char *publickey;
1181 	unsigned char *signature;
1182 	size_t         msg_len;
1183 	size_t         publickey_len;
1184 	size_t         signature_len;
1185 
1186 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
1187 									&signature, &signature_len,
1188 									&msg, &msg_len,
1189 									&publickey, &publickey_len) == FAILURE) {
1190 		sodium_remove_param_values_from_backtrace(EG(exception));
1191 		RETURN_THROWS();
1192 	}
1193 	if (signature_len != crypto_sign_BYTES) {
1194 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_BYTES bytes long");
1195 		RETURN_THROWS();
1196 	}
1197 	if (publickey_len != crypto_sign_PUBLICKEYBYTES) {
1198 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
1199 		RETURN_THROWS();
1200 	}
1201 	if (crypto_sign_verify_detached(signature,
1202 									msg, (unsigned long long) msg_len,
1203 									publickey) != 0) {
1204 		RETURN_FALSE;
1205 	}
1206 	RETURN_TRUE;
1207 }
1208 
PHP_FUNCTION(sodium_crypto_stream)1209 PHP_FUNCTION(sodium_crypto_stream)
1210 {
1211 	zend_string   *ciphertext;
1212 	unsigned char *key;
1213 	unsigned char *nonce;
1214 	zend_long      ciphertext_len;
1215 	size_t         key_len;
1216 	size_t         nonce_len;
1217 
1218 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lss",
1219 									&ciphertext_len,
1220 									&nonce, &nonce_len,
1221 									&key, &key_len) == FAILURE) {
1222 		sodium_remove_param_values_from_backtrace(EG(exception));
1223 		RETURN_THROWS();
1224 	}
1225 	if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX) {
1226 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1227 		RETURN_THROWS();
1228 	}
1229 	if (nonce_len != crypto_stream_NONCEBYTES) {
1230 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_NONCEBYTES bytes long");
1231 		RETURN_THROWS();
1232 	}
1233 	if (key_len != crypto_stream_KEYBYTES) {
1234 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_KEYBYTES bytes long");
1235 		RETURN_THROWS();
1236 	}
1237 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1238 	if (crypto_stream((unsigned char *) ZSTR_VAL(ciphertext),
1239 					  (unsigned long long) ciphertext_len, nonce, key) != 0) {
1240 		zend_string_efree(ciphertext);
1241 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1242 		RETURN_THROWS();
1243 	}
1244 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1245 
1246 	RETURN_NEW_STR(ciphertext);
1247 }
1248 
PHP_FUNCTION(sodium_crypto_stream_xor)1249 PHP_FUNCTION(sodium_crypto_stream_xor)
1250 {
1251 	zend_string   *ciphertext;
1252 	unsigned char *key;
1253 	unsigned char *msg;
1254 	unsigned char *nonce;
1255 	size_t         ciphertext_len;
1256 	size_t         key_len;
1257 	size_t         msg_len;
1258 	size_t         nonce_len;
1259 
1260 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
1261 									&msg, &msg_len,
1262 									&nonce, &nonce_len,
1263 									&key, &key_len) == FAILURE) {
1264 		sodium_remove_param_values_from_backtrace(EG(exception));
1265 		RETURN_THROWS();
1266 	}
1267 	if (nonce_len != crypto_stream_NONCEBYTES) {
1268 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_NONCEBYTES bytes long");
1269 		RETURN_THROWS();
1270 	}
1271 	if (key_len != crypto_stream_KEYBYTES) {
1272 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_KEYBYTES bytes long");
1273 		RETURN_THROWS();
1274 	}
1275 	ciphertext_len = msg_len;
1276 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1277 	if (crypto_stream_xor((unsigned char *) ZSTR_VAL(ciphertext), msg,
1278 						  (unsigned long long) msg_len, nonce, key) != 0) {
1279 		zend_string_efree(ciphertext);
1280 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1281 		RETURN_THROWS();
1282 	}
1283 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1284 
1285 	RETURN_NEW_STR(ciphertext);
1286 }
1287 
1288 #ifdef crypto_stream_xchacha20_KEYBYTES
PHP_FUNCTION(sodium_crypto_stream_xchacha20)1289 PHP_FUNCTION(sodium_crypto_stream_xchacha20)
1290 {
1291 	zend_string   *ciphertext;
1292 	unsigned char *key;
1293 	unsigned char *nonce;
1294 	zend_long      ciphertext_len;
1295 	size_t         key_len;
1296 	size_t         nonce_len;
1297 
1298 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lss",
1299 									&ciphertext_len,
1300 									&nonce, &nonce_len,
1301 									&key, &key_len) == FAILURE) {
1302 		sodium_remove_param_values_from_backtrace(EG(exception));
1303 		RETURN_THROWS();
1304 	}
1305 	if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX) {
1306 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1307 		RETURN_THROWS();
1308 	}
1309 	if (nonce_len != crypto_stream_xchacha20_NONCEBYTES) {
1310 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long");
1311 		RETURN_THROWS();
1312 	}
1313 	if (key_len != crypto_stream_xchacha20_KEYBYTES) {
1314 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long");
1315 		RETURN_THROWS();
1316 	}
1317 	ciphertext = zend_string_checked_alloc((size_t) ciphertext_len, 0);
1318 	if (crypto_stream_xchacha20((unsigned char *) ZSTR_VAL(ciphertext),
1319 								(unsigned long long) ciphertext_len, nonce, key) != 0) {
1320 		zend_string_free(ciphertext);
1321 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1322 		RETURN_THROWS();
1323 	}
1324 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1325 
1326 	RETURN_NEW_STR(ciphertext);
1327 }
1328 
PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor)1329 PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor)
1330 {
1331 	zend_string   *ciphertext;
1332 	unsigned char *key;
1333 	unsigned char *msg;
1334 	unsigned char *nonce;
1335 	size_t         ciphertext_len;
1336 	size_t         key_len;
1337 	size_t         msg_len;
1338 	size_t         nonce_len;
1339 
1340 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
1341 									&msg, &msg_len,
1342 									&nonce, &nonce_len,
1343 									&key, &key_len) == FAILURE) {
1344 		sodium_remove_param_values_from_backtrace(EG(exception));
1345 		RETURN_THROWS();
1346 	}
1347 	if (nonce_len != crypto_stream_xchacha20_NONCEBYTES) {
1348 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long");
1349 		RETURN_THROWS();
1350 	}
1351 	if (key_len != crypto_stream_xchacha20_KEYBYTES) {
1352 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long");
1353 		RETURN_THROWS();
1354 	}
1355 	ciphertext_len = msg_len;
1356 	ciphertext = zend_string_checked_alloc((size_t) ciphertext_len, 0);
1357 	if (crypto_stream_xchacha20_xor((unsigned char *) ZSTR_VAL(ciphertext), msg,
1358 									(unsigned long long) msg_len, nonce, key) != 0) {
1359 		zend_string_free(ciphertext);
1360 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1361 		RETURN_THROWS();
1362 	}
1363 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1364 
1365 	RETURN_NEW_STR(ciphertext);
1366 }
1367 
PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor_ic)1368 PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor_ic)
1369 {
1370 	zend_string   *ciphertext;
1371 	unsigned char *key;
1372 	unsigned char *msg;
1373 	unsigned char *nonce;
1374 	zend_long      ic;
1375 
1376 	size_t         ciphertext_len;
1377 	size_t         key_len;
1378 	size_t         msg_len;
1379 	size_t         nonce_len;
1380 
1381 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssls",
1382 									&msg, &msg_len,
1383 									&nonce, &nonce_len,
1384 									&ic,
1385 									&key, &key_len) == FAILURE) {
1386 		sodium_remove_param_values_from_backtrace(EG(exception));
1387 		RETURN_THROWS();
1388 	}
1389 	if (nonce_len != crypto_stream_xchacha20_NONCEBYTES) {
1390 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long");
1391 		RETURN_THROWS();
1392 	}
1393 	if (key_len != crypto_stream_xchacha20_KEYBYTES) {
1394 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long");
1395 		RETURN_THROWS();
1396 	}
1397 	ciphertext_len = msg_len;
1398 	ciphertext = zend_string_checked_alloc((size_t) ciphertext_len, 0);
1399 	if (crypto_stream_xchacha20_xor_ic((unsigned char *) ZSTR_VAL(ciphertext), msg,
1400 									   (unsigned long long) msg_len, nonce,
1401 									   (uint64_t) ic, key) != 0) {
1402 		zend_string_free(ciphertext);
1403 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1404 		RETURN_THROWS();
1405 	}
1406 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1407 
1408 	RETURN_NEW_STR(ciphertext);
1409 }
1410 #endif
1411 
1412 #ifdef crypto_pwhash_SALTBYTES
PHP_FUNCTION(sodium_crypto_pwhash)1413 PHP_FUNCTION(sodium_crypto_pwhash)
1414 {
1415 	zend_string   *hash;
1416 	unsigned char *salt;
1417 	char          *passwd;
1418 	zend_long      hash_len;
1419 	zend_long      memlimit;
1420 	zend_long      opslimit;
1421 	zend_long      alg;
1422 	size_t         passwd_len;
1423 	size_t         salt_len;
1424 	int            ret;
1425 
1426 	alg = (zend_long) crypto_pwhash_ALG_DEFAULT;
1427 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lssll|l",
1428 									&hash_len,
1429 									&passwd, &passwd_len,
1430 									&salt, &salt_len,
1431 									&opslimit, &memlimit, &alg) == FAILURE) {
1432 		sodium_remove_param_values_from_backtrace(EG(exception));
1433 		RETURN_THROWS();
1434 	}
1435 	if (hash_len <= 0) {
1436 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1437 		RETURN_THROWS();
1438 	}
1439 	if (hash_len >= 0xffffffff) {
1440 		zend_argument_error(sodium_exception_ce, 1, "is too large");
1441 		RETURN_THROWS();
1442 	}
1443 	if (passwd_len >= 0xffffffff) {
1444 		zend_argument_error(sodium_exception_ce, 2, "is too long");
1445 		RETURN_THROWS();
1446 	}
1447 	if (opslimit <= 0) {
1448 		zend_argument_error(sodium_exception_ce, 4, "must be greater than 0");
1449 		RETURN_THROWS();
1450 	}
1451 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1452 		zend_argument_error(sodium_exception_ce, 5, "must be greater than 0");
1453 		RETURN_THROWS();
1454 	}
1455 	if (alg != crypto_pwhash_ALG_ARGON2I13
1456 # ifdef crypto_pwhash_ALG_ARGON2ID13
1457 		&& alg != crypto_pwhash_ALG_ARGON2ID13
1458 # endif
1459 		&& alg != crypto_pwhash_ALG_DEFAULT) {
1460 		zend_throw_exception(sodium_exception_ce, "unsupported password hashing algorithm", 0);
1461 		RETURN_THROWS();
1462 	}
1463 	if (passwd_len <= 0) {
1464 		zend_error(E_WARNING, "empty password");
1465 	}
1466 	if (salt_len != crypto_pwhash_SALTBYTES) {
1467 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_PWHASH_SALTBYTES bytes long");
1468 		RETURN_THROWS();
1469 	}
1470 	if (opslimit < crypto_pwhash_OPSLIMIT_MIN) {
1471 		zend_argument_error(sodium_exception_ce, 4, "must be greater than or equal to %d", crypto_pwhash_OPSLIMIT_MIN);
1472 		RETURN_THROWS();
1473 	}
1474 	if (memlimit < crypto_pwhash_MEMLIMIT_MIN) {
1475 		zend_argument_error(sodium_exception_ce, 5, "must be greater than or equal to %d", crypto_pwhash_MEMLIMIT_MIN);
1476 	}
1477 	hash = zend_string_alloc((size_t) hash_len, 0);
1478 	ret = -1;
1479 # ifdef crypto_pwhash_ALG_ARGON2ID13
1480 	if (alg == crypto_pwhash_ALG_ARGON2ID13) {
1481 		ret = crypto_pwhash_argon2id
1482 			((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len,
1483 			  passwd, (unsigned long long) passwd_len, salt,
1484 			  (unsigned long long) opslimit, (size_t) memlimit, (int) alg);
1485 	}
1486 # endif
1487 	if (ret == -1) {
1488 		ret = crypto_pwhash
1489 			((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len,
1490 			  passwd, (unsigned long long) passwd_len, salt,
1491 			  (unsigned long long) opslimit, (size_t) memlimit, (int) alg);
1492 	}
1493 	if (ret != 0) {
1494 		zend_string_efree(hash);
1495 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1496 		RETURN_THROWS();
1497 	}
1498 	ZSTR_VAL(hash)[hash_len] = 0;
1499 
1500 	RETURN_NEW_STR(hash);
1501 }
1502 
PHP_FUNCTION(sodium_crypto_pwhash_str)1503 PHP_FUNCTION(sodium_crypto_pwhash_str)
1504 {
1505 	zend_string *hash_str;
1506 	char        *passwd;
1507 	zend_long    memlimit;
1508 	zend_long    opslimit;
1509 	size_t       passwd_len;
1510 	size_t       len;
1511 
1512 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll",
1513 									&passwd, &passwd_len,
1514 									&opslimit, &memlimit) == FAILURE) {
1515 		sodium_remove_param_values_from_backtrace(EG(exception));
1516 		RETURN_THROWS();
1517 	}
1518 	if (opslimit <= 0) {
1519 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
1520 		RETURN_THROWS();
1521 	}
1522 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1523 		zend_argument_error(sodium_exception_ce, 3, "must be greater than 0");
1524 		RETURN_THROWS();
1525 	}
1526 	if (passwd_len >= 0xffffffff) {
1527 		zend_argument_error(sodium_exception_ce, 1, "is too long");
1528 		RETURN_THROWS();
1529 	}
1530 	if (passwd_len <= 0) {
1531 		zend_error(E_WARNING, "empty password");
1532 	}
1533 	if (opslimit < crypto_pwhash_OPSLIMIT_MIN) {
1534 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to %d", crypto_pwhash_OPSLIMIT_MIN);
1535 	}
1536 	if (memlimit < crypto_pwhash_MEMLIMIT_MIN) {
1537 		zend_argument_error(sodium_exception_ce, 3, "must be greater than or equal to %d", crypto_pwhash_MEMLIMIT_MIN);
1538 	}
1539 	hash_str = zend_string_alloc(crypto_pwhash_STRBYTES - 1, 0);
1540 	if (crypto_pwhash_str
1541 		(ZSTR_VAL(hash_str), passwd, (unsigned long long) passwd_len,
1542 		 (unsigned long long) opslimit, (size_t) memlimit) != 0) {
1543 		zend_string_efree(hash_str);
1544 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1545 		RETURN_THROWS();
1546 	}
1547 	ZSTR_VAL(hash_str)[crypto_pwhash_STRBYTES - 1] = 0;
1548 
1549 	len = strlen(ZSTR_VAL(hash_str));
1550 	PHP_SODIUM_ZSTR_TRUNCATE(hash_str, len);
1551 
1552 	RETURN_NEW_STR(hash_str);
1553 }
1554 
1555 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
PHP_FUNCTION(sodium_crypto_pwhash_str_needs_rehash)1556 PHP_FUNCTION(sodium_crypto_pwhash_str_needs_rehash)
1557 {
1558 	char      *hash_str;
1559 	zend_long  memlimit;
1560 	zend_long  opslimit;
1561 	size_t     hash_str_len;
1562 
1563 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll",
1564 									&hash_str, &hash_str_len, &opslimit, &memlimit) == FAILURE) {
1565 		RETURN_THROWS();
1566 	}
1567 	if (crypto_pwhash_str_needs_rehash(hash_str, opslimit, memlimit) == 0) {
1568 		RETURN_FALSE;
1569 	}
1570 	RETURN_TRUE;
1571 }
1572 #endif
1573 
PHP_FUNCTION(sodium_crypto_pwhash_str_verify)1574 PHP_FUNCTION(sodium_crypto_pwhash_str_verify)
1575 {
1576 	char      *hash_str;
1577 	char      *passwd;
1578 	size_t     hash_str_len;
1579 	size_t     passwd_len;
1580 
1581 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1582 									&hash_str, &hash_str_len,
1583 									&passwd, &passwd_len) == FAILURE) {
1584 		sodium_remove_param_values_from_backtrace(EG(exception));
1585 		RETURN_THROWS();
1586 	}
1587 	if (passwd_len >= 0xffffffff) {
1588 		zend_argument_error(sodium_exception_ce, 2, "is too long");
1589 		RETURN_THROWS();
1590 	}
1591 	if (passwd_len <= 0) {
1592 		zend_error(E_WARNING, "empty password");
1593 	}
1594 	if (crypto_pwhash_str_verify
1595 		(hash_str, passwd, (unsigned long long) passwd_len) == 0) {
1596 		RETURN_TRUE;
1597 	}
1598 	RETURN_FALSE;
1599 }
1600 #endif
1601 
1602 #ifdef crypto_pwhash_scryptsalsa208sha256_SALTBYTES
PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256)1603 PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256)
1604 {
1605 	zend_string   *hash;
1606 	unsigned char *salt;
1607 	char          *passwd;
1608 	zend_long      hash_len;
1609 	zend_long      memlimit;
1610 	zend_long      opslimit;
1611 	size_t         passwd_len;
1612 	size_t         salt_len;
1613 
1614 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lssll",
1615 									&hash_len,
1616 									&passwd, &passwd_len,
1617 									&salt, &salt_len,
1618 									&opslimit, &memlimit) == FAILURE) {
1619 		sodium_remove_param_values_from_backtrace(EG(exception));
1620 		RETURN_THROWS();
1621 	}
1622 	if (hash_len <= 0 || hash_len >= SIZE_MAX || hash_len > 0x1fffffffe0ULL) {
1623 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1624 		RETURN_THROWS();
1625 	}
1626 	if (opslimit <= 0) {
1627 		zend_argument_error(sodium_exception_ce, 4, "must be greater than 0");
1628 		RETURN_THROWS();
1629 	}
1630 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1631 		zend_argument_error(sodium_exception_ce, 5, "must be greater than 0");
1632 		RETURN_THROWS();
1633 	}
1634 	if (passwd_len <= 0) {
1635 		zend_error(E_WARNING, "empty password");
1636 	}
1637 	if (salt_len != crypto_pwhash_scryptsalsa208sha256_SALTBYTES) {
1638 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES bytes long");
1639 		RETURN_THROWS();
1640 	}
1641 	if (opslimit < crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE) {
1642 		zend_argument_error(sodium_exception_ce, 4, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE);
1643 	}
1644 	if (memlimit < crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) {
1645 		zend_argument_error(sodium_exception_ce, 5, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);
1646 	}
1647 	hash = zend_string_alloc((size_t) hash_len, 0);
1648 	if (crypto_pwhash_scryptsalsa208sha256
1649 		((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len,
1650 		 passwd, (unsigned long long) passwd_len, salt,
1651 		 (unsigned long long) opslimit, (size_t) memlimit) != 0) {
1652 		zend_string_efree(hash);
1653 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1654 		RETURN_THROWS();
1655 	}
1656 	ZSTR_VAL(hash)[hash_len] = 0;
1657 
1658 	RETURN_NEW_STR(hash);
1659 }
1660 
PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str)1661 PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str)
1662 {
1663 	zend_string *hash_str;
1664 	char        *passwd;
1665 	zend_long    memlimit;
1666 	zend_long    opslimit;
1667 	size_t       passwd_len;
1668 
1669 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll",
1670 									&passwd, &passwd_len,
1671 									&opslimit, &memlimit) == FAILURE) {
1672 		sodium_remove_param_values_from_backtrace(EG(exception));
1673 		RETURN_THROWS();
1674 	}
1675 	if (opslimit <= 0) {
1676 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
1677 		RETURN_THROWS();
1678 	}
1679 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1680 		zend_argument_error(sodium_exception_ce, 3, "must be greater than 0");
1681 		RETURN_THROWS();
1682 	}
1683 	if (passwd_len <= 0) {
1684 		zend_error(E_WARNING, "empty password");
1685 	}
1686 	if (opslimit < crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE) {
1687 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE);
1688 	}
1689 	if (memlimit < crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) {
1690 		zend_argument_error(sodium_exception_ce, 3, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);
1691 	}
1692 	hash_str = zend_string_alloc
1693 		(crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1, 0);
1694 	if (crypto_pwhash_scryptsalsa208sha256_str
1695 		(ZSTR_VAL(hash_str), passwd, (unsigned long long) passwd_len,
1696 		 (unsigned long long) opslimit, (size_t) memlimit) != 0) {
1697 		zend_string_efree(hash_str);
1698 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1699 		RETURN_THROWS();
1700 	}
1701 	ZSTR_VAL(hash_str)[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1] = 0;
1702 
1703 	RETURN_NEW_STR(hash_str);
1704 }
1705 
PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify)1706 PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify)
1707 {
1708 	char      *hash_str;
1709 	char      *passwd;
1710 	size_t     hash_str_len;
1711 	size_t     passwd_len;
1712 
1713 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1714 									&hash_str, &hash_str_len,
1715 									&passwd, &passwd_len) == FAILURE) {
1716 		sodium_remove_param_values_from_backtrace(EG(exception));
1717 		RETURN_THROWS();
1718 	}
1719 	if (passwd_len <= 0) {
1720 		zend_error(E_WARNING, "empty password");
1721 	}
1722 	if (hash_str_len != crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1) {
1723 		zend_error(E_WARNING, "wrong size for the hashed password");
1724 		RETURN_FALSE;
1725 	}
1726 	if (crypto_pwhash_scryptsalsa208sha256_str_verify
1727 		(hash_str, passwd, (unsigned long long) passwd_len) == 0) {
1728 		RETURN_TRUE;
1729 	}
1730 	RETURN_FALSE;
1731 }
1732 #endif
1733 
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available)1734 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available)
1735 {
1736 	if (zend_parse_parameters_none() == FAILURE) {
1737 		RETURN_THROWS();
1738 	}
1739 #ifdef HAVE_AESGCM
1740 	RETURN_BOOL(crypto_aead_aes256gcm_is_available());
1741 #else
1742 	RETURN_FALSE;
1743 #endif
1744 }
1745 
1746 #ifdef HAVE_AESGCM
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_encrypt)1747 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_encrypt)
1748 {
1749 	zend_string        *ciphertext;
1750 	unsigned char      *ad;
1751 	unsigned char      *msg;
1752 	unsigned char      *npub;
1753 	unsigned char      *secretkey;
1754 	unsigned long long  ciphertext_real_len;
1755 	size_t              ad_len;
1756 	size_t              ciphertext_len;
1757 	size_t              msg_len;
1758 	size_t              npub_len;
1759 	size_t              secretkey_len;
1760 
1761 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1762 									&msg, &msg_len,
1763 									&ad, &ad_len,
1764 									&npub, &npub_len,
1765 									&secretkey, &secretkey_len) == FAILURE) {
1766 		sodium_remove_param_values_from_backtrace(EG(exception));
1767 		RETURN_THROWS();
1768 	}
1769 	if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) {
1770 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes long");
1771 		RETURN_THROWS();
1772 	}
1773 	if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) {
1774 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES bytes long");
1775 		RETURN_THROWS();
1776 	}
1777 	if (SIZE_MAX - msg_len <= crypto_aead_aes256gcm_ABYTES) {
1778 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1779 		RETURN_THROWS();
1780 	}
1781 	if ((unsigned long long) msg_len > (16ULL * ((1ULL << 32) - 2ULL)) - crypto_aead_aes256gcm_ABYTES) {
1782 		zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0);
1783 		RETURN_THROWS();
1784 	}
1785 	ciphertext_len = msg_len + crypto_aead_aes256gcm_ABYTES;
1786 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1787 	if (crypto_aead_aes256gcm_encrypt
1788 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
1789 		 (unsigned long long) msg_len,
1790 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
1791 		zend_string_efree(ciphertext);
1792 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1793 		RETURN_THROWS();
1794 	}
1795 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
1796 		ciphertext_real_len > ciphertext_len) {
1797 		zend_string_efree(ciphertext);
1798 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1799 		RETURN_THROWS();
1800 	}
1801 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
1802 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
1803 
1804 	RETURN_NEW_STR(ciphertext);
1805 }
1806 
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt)1807 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt)
1808 {
1809 	zend_string        *msg;
1810 	unsigned char      *ad;
1811 	unsigned char      *ciphertext;
1812 	unsigned char      *npub;
1813 	unsigned char      *secretkey;
1814 	unsigned long long  msg_real_len;
1815 	size_t              ad_len;
1816 	size_t              ciphertext_len;
1817 	size_t              msg_len;
1818 	size_t              npub_len;
1819 	size_t              secretkey_len;
1820 
1821 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1822 									&ciphertext, &ciphertext_len,
1823 									&ad, &ad_len,
1824 									&npub, &npub_len,
1825 									&secretkey, &secretkey_len) == FAILURE) {
1826 		sodium_remove_param_values_from_backtrace(EG(exception));
1827 		RETURN_THROWS();
1828 	}
1829 	if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) {
1830 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes long");
1831 		RETURN_THROWS();
1832 	}
1833 	if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) {
1834 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES bytes long");
1835 		RETURN_THROWS();
1836 	}
1837 	if (ciphertext_len < crypto_aead_aes256gcm_ABYTES) {
1838 		RETURN_FALSE;
1839 	}
1840 	if (ciphertext_len - crypto_aead_aes256gcm_ABYTES > 16ULL * ((1ULL << 32) - 2ULL)) {
1841 		zend_argument_error(sodium_exception_ce, 1, "is too long");
1842 		RETURN_THROWS();
1843 	}
1844 	msg_len = ciphertext_len;
1845 	if (msg_len >= SIZE_MAX) {
1846 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1847 		RETURN_THROWS();
1848 	}
1849 	msg = zend_string_alloc((size_t) msg_len, 0);
1850 	if (crypto_aead_aes256gcm_decrypt
1851 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
1852 		 ciphertext, (unsigned long long) ciphertext_len,
1853 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
1854 		zend_string_efree(msg);
1855 		RETURN_FALSE;
1856 	}
1857 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
1858 		zend_string_efree(msg);
1859 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1860 		RETURN_THROWS();
1861 	}
1862 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
1863 	ZSTR_VAL(msg)[msg_real_len] = 0;
1864 
1865 	RETURN_NEW_STR(msg);
1866 }
1867 #endif
1868 
1869 #ifdef crypto_aead_aegis128l_KEYBYTES
PHP_FUNCTION(sodium_crypto_aead_aegis128l_encrypt)1870 PHP_FUNCTION(sodium_crypto_aead_aegis128l_encrypt)
1871 {
1872 	zend_string        *ciphertext;
1873 	unsigned char      *ad;
1874 	unsigned char      *msg;
1875 	unsigned char      *npub;
1876 	unsigned char      *secretkey;
1877 	unsigned long long  ciphertext_real_len;
1878 	size_t              ad_len;
1879 	size_t              ciphertext_len;
1880 	size_t              msg_len;
1881 	size_t              npub_len;
1882 	size_t              secretkey_len;
1883 
1884 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1885 							  &msg, &msg_len,
1886 							  &ad, &ad_len,
1887 							  &npub, &npub_len,
1888 							  &secretkey, &secretkey_len) == FAILURE) {
1889 		sodium_remove_param_values_from_backtrace(EG(exception));
1890 		RETURN_THROWS();
1891 	}
1892 	if (npub_len != crypto_aead_aegis128l_NPUBBYTES) {
1893 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AEGIS128L_NPUBBYTES bytes long");
1894 		RETURN_THROWS();
1895 	}
1896 	if (secretkey_len != crypto_aead_aegis128l_KEYBYTES) {
1897 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES bytes long");
1898 		RETURN_THROWS();
1899 	}
1900 	if (SIZE_MAX - msg_len <= crypto_aead_aegis128l_ABYTES) {
1901 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1902 		RETURN_THROWS();
1903 	}
1904 	ciphertext_len = msg_len + crypto_aead_aegis128l_ABYTES;
1905 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1906 	if (crypto_aead_aegis128l_encrypt
1907 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
1908 		 (unsigned long long) msg_len,
1909 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
1910 		zend_string_efree(ciphertext);
1911 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1912 		RETURN_THROWS();
1913 	}
1914 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
1915 		ciphertext_real_len > ciphertext_len) {
1916 		zend_string_efree(ciphertext);
1917 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1918 		RETURN_THROWS();
1919 	}
1920 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
1921 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
1922 
1923 	RETURN_NEW_STR(ciphertext);
1924 }
1925 
PHP_FUNCTION(sodium_crypto_aead_aegis128l_decrypt)1926 PHP_FUNCTION(sodium_crypto_aead_aegis128l_decrypt)
1927 {
1928 	zend_string        *msg;
1929 	unsigned char      *ad;
1930 	unsigned char      *ciphertext;
1931 	unsigned char      *npub;
1932 	unsigned char      *secretkey;
1933 	unsigned long long  msg_real_len;
1934 	size_t              ad_len;
1935 	size_t              ciphertext_len;
1936 	size_t              msg_len;
1937 	size_t              npub_len;
1938 	size_t              secretkey_len;
1939 
1940 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1941 							  &ciphertext, &ciphertext_len,
1942 							  &ad, &ad_len,
1943 							  &npub, &npub_len,
1944 							  &secretkey, &secretkey_len) == FAILURE) {
1945 		sodium_remove_param_values_from_backtrace(EG(exception));
1946 		RETURN_THROWS();
1947 	}
1948 	if (npub_len != crypto_aead_aegis128l_NPUBBYTES) {
1949 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AEGIS128L_NPUBBYTES bytes long");
1950 		RETURN_THROWS();
1951 	}
1952 	if (secretkey_len != crypto_aead_aegis128l_KEYBYTES) {
1953 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES bytes long");
1954 		RETURN_THROWS();
1955 	}
1956 	if (ciphertext_len < crypto_aead_aegis128l_ABYTES) {
1957 		RETURN_FALSE;
1958 	}
1959 	msg_len = ciphertext_len;
1960 	if (msg_len >= SIZE_MAX) {
1961 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1962 		RETURN_THROWS();
1963 	}
1964 	msg = zend_string_alloc((size_t) msg_len, 0);
1965 	if (crypto_aead_aegis128l_decrypt
1966 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
1967 		 ciphertext, (unsigned long long) ciphertext_len,
1968 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
1969 		zend_string_efree(msg);
1970 		RETURN_FALSE;
1971 	}
1972 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
1973 		zend_string_efree(msg);
1974 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1975 		RETURN_THROWS();
1976 	}
1977 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
1978 	ZSTR_VAL(msg)[msg_real_len] = 0;
1979 
1980 	RETURN_NEW_STR(msg);
1981 }
1982 #endif
1983 
1984 #ifdef crypto_aead_aegis256_KEYBYTES
PHP_FUNCTION(sodium_crypto_aead_aegis256_encrypt)1985 PHP_FUNCTION(sodium_crypto_aead_aegis256_encrypt)
1986 {
1987 	zend_string        *ciphertext;
1988 	unsigned char      *ad;
1989 	unsigned char      *msg;
1990 	unsigned char      *npub;
1991 	unsigned char      *secretkey;
1992 	unsigned long long  ciphertext_real_len;
1993 	size_t              ad_len;
1994 	size_t              ciphertext_len;
1995 	size_t              msg_len;
1996 	size_t              npub_len;
1997 	size_t              secretkey_len;
1998 
1999 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2000 							  &msg, &msg_len,
2001 							  &ad, &ad_len,
2002 							  &npub, &npub_len,
2003 							  &secretkey, &secretkey_len) == FAILURE) {
2004 		sodium_remove_param_values_from_backtrace(EG(exception));
2005 		RETURN_THROWS();
2006 	}
2007 	if (npub_len != crypto_aead_aegis256_NPUBBYTES) {
2008 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AEGIS256_NPUBBYTES bytes long");
2009 		RETURN_THROWS();
2010 	}
2011 	if (secretkey_len != crypto_aead_aegis256_KEYBYTES) {
2012 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AEGIS256_KEYBYTES bytes long");
2013 		RETURN_THROWS();
2014 	}
2015 	if (SIZE_MAX - msg_len <= crypto_aead_aegis256_ABYTES) {
2016 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2017 		RETURN_THROWS();
2018 	}
2019 	ciphertext_len = msg_len + crypto_aead_aegis256_ABYTES;
2020 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
2021 	if (crypto_aead_aegis256_encrypt
2022 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
2023 		 (unsigned long long) msg_len,
2024 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
2025 		zend_string_efree(ciphertext);
2026 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2027 		RETURN_THROWS();
2028 	}
2029 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
2030 		ciphertext_real_len > ciphertext_len) {
2031 		zend_string_efree(ciphertext);
2032 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2033 		RETURN_THROWS();
2034 	}
2035 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
2036 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
2037 
2038 	RETURN_NEW_STR(ciphertext);
2039 }
2040 
PHP_FUNCTION(sodium_crypto_aead_aegis256_decrypt)2041 PHP_FUNCTION(sodium_crypto_aead_aegis256_decrypt)
2042 {
2043 	zend_string        *msg;
2044 	unsigned char      *ad;
2045 	unsigned char      *ciphertext;
2046 	unsigned char      *npub;
2047 	unsigned char      *secretkey;
2048 	unsigned long long  msg_real_len;
2049 	size_t              ad_len;
2050 	size_t              ciphertext_len;
2051 	size_t              msg_len;
2052 	size_t              npub_len;
2053 	size_t              secretkey_len;
2054 
2055 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2056 							  &ciphertext, &ciphertext_len,
2057 							  &ad, &ad_len,
2058 							  &npub, &npub_len,
2059 							  &secretkey, &secretkey_len) == FAILURE) {
2060 		sodium_remove_param_values_from_backtrace(EG(exception));
2061 		RETURN_THROWS();
2062 	}
2063 	if (npub_len != crypto_aead_aegis256_NPUBBYTES) {
2064 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AEGIS256_NPUBBYTES bytes long");
2065 		RETURN_THROWS();
2066 	}
2067 	if (secretkey_len != crypto_aead_aegis256_KEYBYTES) {
2068 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AEGIS256_KEYBYTES bytes long");
2069 		RETURN_THROWS();
2070 	}
2071 	if (ciphertext_len < crypto_aead_aegis256_ABYTES) {
2072 		RETURN_FALSE;
2073 	}
2074 	msg_len = ciphertext_len;
2075 	if (msg_len >= SIZE_MAX) {
2076 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2077 		RETURN_THROWS();
2078 	}
2079 	msg = zend_string_alloc((size_t) msg_len, 0);
2080 	if (crypto_aead_aegis256_decrypt
2081 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
2082 		 ciphertext, (unsigned long long) ciphertext_len,
2083 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
2084 		zend_string_efree(msg);
2085 		RETURN_FALSE;
2086 	}
2087 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
2088 		zend_string_efree(msg);
2089 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2090 		RETURN_THROWS();
2091 	}
2092 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
2093 	ZSTR_VAL(msg)[msg_real_len] = 0;
2094 
2095 	RETURN_NEW_STR(msg);
2096 }
2097 #endif
2098 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_encrypt)2099 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_encrypt)
2100 {
2101 	zend_string        *ciphertext;
2102 	unsigned char      *ad;
2103 	unsigned char      *msg;
2104 	unsigned char      *npub;
2105 	unsigned char      *secretkey;
2106 	unsigned long long  ciphertext_real_len;
2107 	size_t              ad_len;
2108 	size_t              ciphertext_len;
2109 	size_t              msg_len;
2110 	size_t              npub_len;
2111 	size_t              secretkey_len;
2112 
2113 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2114 							  &msg, &msg_len,
2115 							  &ad, &ad_len,
2116 							  &npub, &npub_len,
2117 							  &secretkey, &secretkey_len) == FAILURE) {
2118 		sodium_remove_param_values_from_backtrace(EG(exception));
2119 		RETURN_THROWS();
2120 	}
2121 	if (npub_len != crypto_aead_chacha20poly1305_NPUBBYTES) {
2122 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes long");
2123 		RETURN_THROWS();
2124 	}
2125 	if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) {
2126 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes long");
2127 		RETURN_THROWS();
2128 	}
2129 	if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_ABYTES) {
2130 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2131 		RETURN_THROWS();
2132 	}
2133 	ciphertext_len = msg_len + crypto_aead_chacha20poly1305_ABYTES;
2134 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
2135 	if (crypto_aead_chacha20poly1305_encrypt
2136 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
2137 		 (unsigned long long) msg_len,
2138 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
2139 		zend_string_efree(ciphertext);
2140 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2141 		RETURN_THROWS();
2142 	}
2143 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
2144 		ciphertext_real_len > ciphertext_len) {
2145 		zend_string_efree(ciphertext);
2146 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2147 		RETURN_THROWS();
2148 	}
2149 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
2150 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
2151 
2152 	RETURN_NEW_STR(ciphertext);
2153 }
2154 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_decrypt)2155 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_decrypt)
2156 {
2157 	zend_string        *msg;
2158 	unsigned char      *ad;
2159 	unsigned char      *ciphertext;
2160 	unsigned char      *npub;
2161 	unsigned char      *secretkey;
2162 	unsigned long long  msg_real_len;
2163 	size_t              ad_len;
2164 	size_t              ciphertext_len;
2165 	size_t              msg_len;
2166 	size_t              npub_len;
2167 	size_t              secretkey_len;
2168 
2169 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2170 									&ciphertext, &ciphertext_len,
2171 									&ad, &ad_len,
2172 									&npub, &npub_len,
2173 									&secretkey, &secretkey_len) == FAILURE) {
2174 		sodium_remove_param_values_from_backtrace(EG(exception));
2175 		RETURN_THROWS();
2176 	}
2177 	if (npub_len != crypto_aead_chacha20poly1305_NPUBBYTES) {
2178 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes long");
2179 		RETURN_THROWS();
2180 	}
2181 	if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) {
2182 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes long");
2183 		RETURN_THROWS();
2184 	}
2185 	if (ciphertext_len < crypto_aead_chacha20poly1305_ABYTES) {
2186 		RETURN_FALSE;
2187 	}
2188 	msg_len = ciphertext_len;
2189 	if (msg_len >= SIZE_MAX) {
2190 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2191 		RETURN_THROWS();
2192 	}
2193 	msg = zend_string_alloc((size_t) msg_len, 0);
2194 	if (crypto_aead_chacha20poly1305_decrypt
2195 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
2196 		 ciphertext, (unsigned long long) ciphertext_len,
2197 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
2198 		zend_string_efree(msg);
2199 		RETURN_FALSE;
2200 	}
2201 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
2202 		zend_string_efree(msg);
2203 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2204 		RETURN_THROWS();
2205 	}
2206 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
2207 	ZSTR_VAL(msg)[msg_real_len] = 0;
2208 
2209 	RETURN_NEW_STR(msg);
2210 }
2211 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_encrypt)2212 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_encrypt)
2213 {
2214 	zend_string        *ciphertext;
2215 	unsigned char      *ad;
2216 	unsigned char      *msg;
2217 	unsigned char      *npub;
2218 	unsigned char      *secretkey;
2219 	unsigned long long  ciphertext_real_len;
2220 	size_t              ad_len;
2221 	size_t              ciphertext_len;
2222 	size_t              msg_len;
2223 	size_t              npub_len;
2224 	size_t              secretkey_len;
2225 
2226 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2227 									&msg, &msg_len,
2228 									&ad, &ad_len,
2229 									&npub, &npub_len,
2230 									&secretkey, &secretkey_len) == FAILURE) {
2231 		sodium_remove_param_values_from_backtrace(EG(exception));
2232 		RETURN_THROWS();
2233 	}
2234 	if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) {
2235 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2236 		RETURN_THROWS();
2237 	}
2238 	if (secretkey_len != crypto_aead_chacha20poly1305_IETF_KEYBYTES) {
2239 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes long");
2240 		RETURN_THROWS();
2241 	}
2242 	if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_IETF_ABYTES) {
2243 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2244 		RETURN_THROWS();
2245 	}
2246 	if ((unsigned long long) msg_len > 64ULL * (1ULL << 32) - 64ULL) {
2247 		zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0);
2248 		RETURN_THROWS();
2249 	}
2250 	ciphertext_len = msg_len + crypto_aead_chacha20poly1305_IETF_ABYTES;
2251 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
2252 	if (crypto_aead_chacha20poly1305_ietf_encrypt
2253 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
2254 		 (unsigned long long) msg_len,
2255 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
2256 		zend_string_efree(ciphertext);
2257 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2258 		RETURN_THROWS();
2259 	}
2260 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
2261 		ciphertext_real_len > ciphertext_len) {
2262 		zend_string_efree(ciphertext);
2263 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2264 		RETURN_THROWS();
2265 	}
2266 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
2267 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
2268 
2269 	RETURN_NEW_STR(ciphertext);
2270 }
2271 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_decrypt)2272 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_decrypt)
2273 {
2274 	zend_string        *msg;
2275 	unsigned char      *ad;
2276 	unsigned char      *ciphertext;
2277 	unsigned char      *npub;
2278 	unsigned char      *secretkey;
2279 	unsigned long long  msg_real_len;
2280 	size_t              ad_len;
2281 	size_t              ciphertext_len;
2282 	size_t              msg_len;
2283 	size_t              npub_len;
2284 	size_t              secretkey_len;
2285 
2286 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2287 									&ciphertext, &ciphertext_len,
2288 									&ad, &ad_len,
2289 									&npub, &npub_len,
2290 									&secretkey, &secretkey_len) == FAILURE) {
2291 		sodium_remove_param_values_from_backtrace(EG(exception));
2292 		RETURN_THROWS();
2293 	}
2294 	if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) {
2295 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2296 		RETURN_THROWS();
2297 	}
2298 	if (secretkey_len != crypto_aead_chacha20poly1305_IETF_KEYBYTES) {
2299 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes long");
2300 		RETURN_THROWS();
2301 	}
2302 	msg_len = ciphertext_len;
2303 	if (msg_len >= SIZE_MAX) {
2304 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2305 		RETURN_THROWS();
2306 	}
2307 	if (ciphertext_len < crypto_aead_chacha20poly1305_IETF_ABYTES) {
2308 		RETURN_FALSE;
2309 	}
2310 	if ((unsigned long long) ciphertext_len -
2311 		crypto_aead_chacha20poly1305_IETF_ABYTES > 64ULL * (1ULL << 32) - 64ULL) {
2312 		zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0);
2313 		RETURN_THROWS();
2314 	}
2315 	msg = zend_string_alloc((size_t) msg_len, 0);
2316 	if (crypto_aead_chacha20poly1305_ietf_decrypt
2317 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
2318 		 ciphertext, (unsigned long long) ciphertext_len,
2319 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
2320 		zend_string_efree(msg);
2321 		RETURN_FALSE;
2322 	}
2323 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
2324 		zend_string_efree(msg);
2325 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2326 		RETURN_THROWS();
2327 	}
2328 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
2329 	ZSTR_VAL(msg)[msg_real_len] = 0;
2330 
2331 	RETURN_NEW_STR(msg);
2332 }
2333 
2334 #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt)2335 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt)
2336 {
2337 	zend_string        *ciphertext;
2338 	unsigned char      *ad;
2339 	unsigned char      *msg;
2340 	unsigned char      *npub;
2341 	unsigned char      *secretkey;
2342 	unsigned long long  ciphertext_real_len;
2343 	size_t              ad_len;
2344 	size_t              ciphertext_len;
2345 	size_t              msg_len;
2346 	size_t              npub_len;
2347 	size_t              secretkey_len;
2348 
2349 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2350 									&msg, &msg_len,
2351 									&ad, &ad_len,
2352 									&npub, &npub_len,
2353 									&secretkey, &secretkey_len) == FAILURE) {
2354 		sodium_remove_param_values_from_backtrace(EG(exception));
2355 		RETURN_THROWS();
2356 	}
2357 	if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) {
2358 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2359 		RETURN_THROWS();
2360 	}
2361 	if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) {
2362 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES bytes long");
2363 		RETURN_THROWS();
2364 	}
2365 	if (SIZE_MAX - msg_len <= crypto_aead_xchacha20poly1305_IETF_ABYTES) {
2366 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2367 		RETURN_THROWS();
2368 	}
2369 	ciphertext_len = msg_len + crypto_aead_xchacha20poly1305_IETF_ABYTES;
2370 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
2371 	if (crypto_aead_xchacha20poly1305_ietf_encrypt
2372 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
2373 		 (unsigned long long) msg_len,
2374 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
2375 		zend_string_efree(ciphertext);
2376 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2377 		RETURN_THROWS();
2378 	}
2379 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
2380 		ciphertext_real_len > ciphertext_len) {
2381 		zend_string_efree(ciphertext);
2382 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2383 		RETURN_THROWS();
2384 	}
2385 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
2386 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
2387 
2388 	RETURN_NEW_STR(ciphertext);
2389 }
2390 
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt)2391 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt)
2392 {
2393 	zend_string        *msg;
2394 	unsigned char      *ad;
2395 	unsigned char      *ciphertext;
2396 	unsigned char      *npub;
2397 	unsigned char      *secretkey;
2398 	unsigned long long  msg_real_len;
2399 	size_t              ad_len;
2400 	size_t              ciphertext_len;
2401 	size_t              msg_len;
2402 	size_t              npub_len;
2403 	size_t              secretkey_len;
2404 
2405 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2406 									&ciphertext, &ciphertext_len,
2407 									&ad, &ad_len,
2408 									&npub, &npub_len,
2409 									&secretkey, &secretkey_len) == FAILURE) {
2410 		sodium_remove_param_values_from_backtrace(EG(exception));
2411 		RETURN_THROWS();
2412 	}
2413 	if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) {
2414 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2415 		RETURN_THROWS();
2416 	}
2417 	if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) {
2418 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES bytes long");
2419 		RETURN_THROWS();
2420 	}
2421 	if (ciphertext_len < crypto_aead_xchacha20poly1305_IETF_ABYTES) {
2422 		RETURN_FALSE;
2423 	}
2424 	msg_len = ciphertext_len;
2425 	if (msg_len - crypto_aead_xchacha20poly1305_IETF_ABYTES >= SIZE_MAX) {
2426 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2427 		RETURN_THROWS();
2428 	}
2429 	if ((unsigned long long) ciphertext_len -
2430 		crypto_aead_xchacha20poly1305_IETF_ABYTES > 64ULL * (1ULL << 32) - 64ULL) {
2431 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2432 		RETURN_THROWS();
2433 	}
2434 	msg = zend_string_alloc((size_t) msg_len, 0);
2435 	if (crypto_aead_xchacha20poly1305_ietf_decrypt
2436 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
2437 		 ciphertext, (unsigned long long) ciphertext_len,
2438 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
2439 		zend_string_efree(msg);
2440 		RETURN_FALSE;
2441 	}
2442 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
2443 		zend_string_efree(msg);
2444 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2445 		RETURN_THROWS();
2446 	}
2447 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
2448 	ZSTR_VAL(msg)[msg_real_len] = 0;
2449 
2450 	RETURN_NEW_STR(msg);
2451 }
2452 #endif
2453 
PHP_FUNCTION(sodium_bin2hex)2454 PHP_FUNCTION(sodium_bin2hex)
2455 {
2456 	zend_string   *hex;
2457 	unsigned char *bin;
2458 	size_t         bin_len;
2459 	size_t         hex_len;
2460 
2461 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2462 									&bin, &bin_len) == FAILURE) {
2463 		sodium_remove_param_values_from_backtrace(EG(exception));
2464 		RETURN_THROWS();
2465 	}
2466 	if (bin_len >= SIZE_MAX / 2U) {
2467 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2468 		RETURN_THROWS();
2469 	}
2470 	hex_len = bin_len * 2U;
2471 	hex = zend_string_alloc((size_t) hex_len, 0);
2472 	sodium_bin2hex(ZSTR_VAL(hex), hex_len + 1U, bin, bin_len);
2473 	ZSTR_VAL(hex)[hex_len] = 0;
2474 
2475 	RETURN_STR(hex);
2476 }
2477 
PHP_FUNCTION(sodium_hex2bin)2478 PHP_FUNCTION(sodium_hex2bin)
2479 {
2480 	zend_string   *bin;
2481 	const char    *end;
2482 	char          *hex;
2483 	char          *ignore = NULL;
2484 	size_t         bin_real_len;
2485 	size_t         bin_len;
2486 	size_t         hex_len;
2487 	size_t         ignore_len = 0;
2488 
2489 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s",
2490 									&hex, &hex_len,
2491 									&ignore, &ignore_len) == FAILURE) {
2492 		sodium_remove_param_values_from_backtrace(EG(exception));
2493 		RETURN_THROWS();
2494 	}
2495 	bin_len = hex_len / 2;
2496 	bin = zend_string_alloc(bin_len, 0);
2497 	if (sodium_hex2bin((unsigned char *) ZSTR_VAL(bin), bin_len, hex, hex_len,
2498 					   ignore, &bin_real_len, &end) != 0 ||
2499 		end != hex + hex_len) {
2500 		zend_string_efree(bin);
2501 		zend_argument_error(sodium_exception_ce, 1, "must be a valid hexadecimal string");
2502 		RETURN_THROWS();
2503 	}
2504 	if (bin_real_len >= SIZE_MAX || bin_real_len > bin_len) {
2505 		zend_string_efree(bin);
2506 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2507 		RETURN_THROWS();
2508 	}
2509 	PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len);
2510 	ZSTR_VAL(bin)[bin_real_len] = 0;
2511 
2512 	RETURN_NEW_STR(bin);
2513 }
2514 
2515 #ifdef sodium_base64_VARIANT_ORIGINAL
PHP_FUNCTION(sodium_bin2base64)2516 PHP_FUNCTION(sodium_bin2base64)
2517 {
2518 	zend_string   *b64;
2519 	unsigned char *bin;
2520 	zend_long      variant;
2521 	size_t         bin_len;
2522 	size_t         b64_len;
2523 
2524 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
2525 									&bin, &bin_len, &variant) == FAILURE) {
2526 		sodium_remove_param_values_from_backtrace(EG(exception));
2527 		RETURN_THROWS();
2528 	}
2529 	if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) {
2530 		zend_argument_error(sodium_exception_ce, 2, "must be a valid base64 variant identifier");
2531 		RETURN_THROWS();
2532 	}
2533 	if (bin_len >= SIZE_MAX / 4U * 3U - 3U - 1U) {
2534 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2535 		RETURN_THROWS();
2536 	}
2537 	b64_len = sodium_base64_ENCODED_LEN(bin_len, variant);
2538 	b64 = zend_string_alloc((size_t) b64_len - 1U, 0);
2539 	sodium_bin2base64(ZSTR_VAL(b64), b64_len, bin, bin_len, (int) variant);
2540 
2541 	RETURN_STR(b64);
2542 }
2543 
PHP_FUNCTION(sodium_base642bin)2544 PHP_FUNCTION(sodium_base642bin)
2545 {
2546 	zend_string   *bin;
2547 	char          *b64;
2548 	const char    *end;
2549 	char          *ignore = NULL;
2550 	zend_long      variant;
2551 	size_t         bin_real_len;
2552 	size_t         bin_len;
2553 	size_t         b64_len;
2554 	size_t         ignore_len = 0;
2555 
2556 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s",
2557 									&b64, &b64_len, &variant,
2558 									&ignore, &ignore_len) == FAILURE) {
2559 		sodium_remove_param_values_from_backtrace(EG(exception));
2560 		RETURN_THROWS();
2561 	}
2562 	if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) {
2563 		zend_argument_error(sodium_exception_ce, 2, "must be a valid base64 variant identifier");
2564 		RETURN_THROWS();
2565 	}
2566 	bin_len = b64_len / 4U * 3U + 2U;
2567 	bin = zend_string_alloc(bin_len, 0);
2568 	if (sodium_base642bin((unsigned char *) ZSTR_VAL(bin), bin_len,
2569 						  b64, b64_len,
2570 						  ignore, &bin_real_len, &end, (int) variant) != 0 ||
2571 		end != b64 + b64_len) {
2572 		zend_string_efree(bin);
2573 		zend_argument_error(sodium_exception_ce, 1, "must be a valid base64 string");
2574 		RETURN_THROWS();
2575 	}
2576 	if (bin_real_len >= SIZE_MAX || bin_real_len > bin_len) {
2577 		zend_string_efree(bin);
2578 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2579 		RETURN_THROWS();
2580 	}
2581 	PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len);
2582 	ZSTR_VAL(bin)[bin_real_len] = 0;
2583 
2584 	RETURN_NEW_STR(bin);
2585 }
2586 #endif
2587 
PHP_FUNCTION(sodium_crypto_scalarmult)2588 PHP_FUNCTION(sodium_crypto_scalarmult)
2589 {
2590 	zend_string   *q;
2591 	unsigned char *n;
2592 	unsigned char *p;
2593 	size_t         n_len;
2594 	size_t         p_len;
2595 
2596 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2597 									&n, &n_len, &p, &p_len) == FAILURE) {
2598 		sodium_remove_param_values_from_backtrace(EG(exception));
2599 		RETURN_THROWS();
2600 	}
2601 	if (n_len != crypto_scalarmult_SCALARBYTES) {
2602 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SCALARMULT_SCALARBYTES bytes long");
2603 		RETURN_THROWS();
2604 	}
2605 	if (p_len != crypto_scalarmult_BYTES) {
2606 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SCALARMULT_SCALARBYTES bytes long");
2607 		RETURN_THROWS();
2608 	}
2609 	q = zend_string_alloc(crypto_scalarmult_BYTES, 0);
2610 	if (crypto_scalarmult((unsigned char *) ZSTR_VAL(q), n, p) != 0) {
2611 		zend_string_efree(q);
2612 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2613 		RETURN_THROWS();
2614 	}
2615 	ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0;
2616 
2617 	RETURN_NEW_STR(q);
2618 }
2619 
2620 #ifdef crypto_core_ristretto255_HASHBYTES
PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255)2621 PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255)
2622 {
2623 	zend_string   *q;
2624 	unsigned char *n;
2625 	unsigned char *p;
2626 	size_t         n_len;
2627 	size_t         p_len;
2628 
2629 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2630 									&n, &n_len, &p, &p_len) == FAILURE) {
2631 		sodium_remove_param_values_from_backtrace(EG(exception));
2632 		RETURN_THROWS();
2633 	}
2634 	if (n_len != crypto_scalarmult_ristretto255_SCALARBYTES) {
2635 		zend_argument_error(sodium_exception_ce, 1,
2636 							"must be SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES bytes long");
2637 		RETURN_THROWS();
2638 	}
2639 	if (p_len != crypto_scalarmult_ristretto255_BYTES) {
2640 		zend_argument_error(sodium_exception_ce, 2,
2641 							"must be SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES bytes long");
2642 		RETURN_THROWS();
2643 	}
2644 	q = zend_string_alloc(crypto_scalarmult_ristretto255_BYTES, 0);
2645 	if (crypto_scalarmult_ristretto255((unsigned char *) ZSTR_VAL(q), n, p) != 0) {
2646 		zend_string_efree(q);
2647 		zend_throw_exception(sodium_exception_ce, "Result is identity element", 0);
2648 		RETURN_THROWS();
2649 	}
2650 	ZSTR_VAL(q)[crypto_scalarmult_ristretto255_BYTES] = 0;
2651 
2652 	RETURN_NEW_STR(q);
2653 }
2654 
PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255_base)2655 PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255_base)
2656 {
2657 	zend_string   *q;
2658 	unsigned char *n;
2659 	size_t         n_len;
2660 
2661 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2662 							  &n, &n_len) == FAILURE) {
2663 		sodium_remove_param_values_from_backtrace(EG(exception));
2664 		RETURN_THROWS();
2665 	}
2666 	if (n_len != crypto_scalarmult_ristretto255_SCALARBYTES) {
2667 		zend_argument_error(sodium_exception_ce, 1,
2668 							"must be SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES bytes long");
2669 		RETURN_THROWS();
2670 	}
2671 	q = zend_string_alloc(crypto_scalarmult_ristretto255_BYTES, 0);
2672 	if (crypto_scalarmult_ristretto255_base((unsigned char *) ZSTR_VAL(q), n) != 0) {
2673 		zend_string_efree(q);
2674 		zend_argument_error(sodium_exception_ce, 1, "must not be zero", 0);
2675 		RETURN_THROWS();
2676 	}
2677 	ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0;
2678 
2679 	RETURN_NEW_STR(q);
2680 }
2681 #endif
2682 
PHP_FUNCTION(sodium_crypto_kx_seed_keypair)2683 PHP_FUNCTION(sodium_crypto_kx_seed_keypair)
2684 {
2685 	unsigned char *sk;
2686 	unsigned char *pk;
2687 	unsigned char *seed;
2688 	size_t         seed_len;
2689 	zend_string   *keypair;
2690 
2691 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2692 									&seed, &seed_len) == FAILURE) {
2693 		sodium_remove_param_values_from_backtrace(EG(exception));
2694 		RETURN_THROWS();
2695 	}
2696 	if (seed_len != crypto_kx_SEEDBYTES) {
2697 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_SEEDBYTES bytes long");
2698 		RETURN_THROWS();
2699 	}
2700 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2701 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2702 	keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0);
2703 	sk = (unsigned char *) ZSTR_VAL(keypair);
2704 	pk = sk + crypto_kx_SECRETKEYBYTES;
2705 	crypto_generichash(sk, crypto_kx_SECRETKEYBYTES,
2706 					   seed, crypto_kx_SEEDBYTES, NULL, 0);
2707 	if (crypto_scalarmult_base(pk, sk) != 0) {
2708 		zend_string_efree(keypair);
2709 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2710 		RETURN_THROWS();
2711 	}
2712 	ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0;
2713 	RETURN_STR(keypair);
2714 }
2715 
PHP_FUNCTION(sodium_crypto_kx_keypair)2716 PHP_FUNCTION(sodium_crypto_kx_keypair)
2717 {
2718 	unsigned char *sk;
2719 	unsigned char *pk;
2720 	zend_string   *keypair;
2721 
2722 	if (zend_parse_parameters_none() == FAILURE) {
2723 		RETURN_THROWS();
2724 	}
2725 	keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0);
2726 	sk = (unsigned char *) ZSTR_VAL(keypair);
2727 	pk = sk + crypto_kx_SECRETKEYBYTES;
2728 	randombytes_buf(sk, crypto_kx_SECRETKEYBYTES);
2729 	if (crypto_scalarmult_base(pk, sk) != 0) {
2730 		zend_string_efree(keypair);
2731 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2732 		RETURN_THROWS();
2733 	}
2734 	ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0;
2735 	RETURN_STR(keypair);
2736 }
2737 
PHP_FUNCTION(sodium_crypto_kx_secretkey)2738 PHP_FUNCTION(sodium_crypto_kx_secretkey)
2739 {
2740 	zend_string   *secretkey;
2741 	unsigned char *keypair;
2742 	size_t         keypair_len;
2743 
2744 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2745 									&keypair, &keypair_len) == FAILURE) {
2746 		sodium_remove_param_values_from_backtrace(EG(exception));
2747 		RETURN_THROWS();
2748 	}
2749 	if (keypair_len !=
2750 		crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2751 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2752 		RETURN_THROWS();
2753 	}
2754 	secretkey = zend_string_alloc(crypto_kx_SECRETKEYBYTES, 0);
2755 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_kx_SECRETKEYBYTES);
2756 	ZSTR_VAL(secretkey)[crypto_kx_SECRETKEYBYTES] = 0;
2757 
2758 	RETURN_STR(secretkey);
2759 }
2760 
PHP_FUNCTION(sodium_crypto_kx_publickey)2761 PHP_FUNCTION(sodium_crypto_kx_publickey)
2762 {
2763 	zend_string   *publickey;
2764 	unsigned char *keypair;
2765 	size_t         keypair_len;
2766 
2767 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2768 									&keypair, &keypair_len) == FAILURE) {
2769 		sodium_remove_param_values_from_backtrace(EG(exception));
2770 		RETURN_THROWS();
2771 	}
2772 	if (keypair_len !=
2773 		crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2774 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2775 		RETURN_THROWS();
2776 	}
2777 	publickey = zend_string_alloc(crypto_kx_PUBLICKEYBYTES, 0);
2778 	memcpy(ZSTR_VAL(publickey), keypair + crypto_kx_SECRETKEYBYTES,
2779 		   crypto_kx_PUBLICKEYBYTES);
2780 	ZSTR_VAL(publickey)[crypto_kx_PUBLICKEYBYTES] = 0;
2781 
2782 	RETURN_STR(publickey);
2783 }
2784 
PHP_FUNCTION(sodium_crypto_kx_client_session_keys)2785 PHP_FUNCTION(sodium_crypto_kx_client_session_keys)
2786 {
2787 	crypto_generichash_state h;
2788 	unsigned char  q[crypto_scalarmult_BYTES];
2789 	unsigned char *keypair;
2790 	unsigned char *client_sk;
2791 	unsigned char *client_pk;
2792 	unsigned char *server_pk;
2793 	unsigned char  session_keys[2 * crypto_kx_SESSIONKEYBYTES];
2794 	size_t         keypair_len;
2795 	size_t         server_pk_len;
2796 
2797 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2798 									&keypair, &keypair_len,
2799 									&server_pk, &server_pk_len) == FAILURE) {
2800 		sodium_remove_param_values_from_backtrace(EG(exception));
2801 		RETURN_THROWS();
2802 	}
2803 	if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2804 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2805 		RETURN_THROWS();
2806 	}
2807 	if (server_pk_len != crypto_kx_PUBLICKEYBYTES) {
2808 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes long");
2809 		RETURN_THROWS();
2810 	}
2811 	client_sk = &keypair[0];
2812 	client_pk = &keypair[crypto_kx_SECRETKEYBYTES];
2813 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2814 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2815 	if (crypto_scalarmult(q, client_sk, server_pk) != 0) {
2816 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2817 		RETURN_THROWS();
2818 	}
2819 	crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES);
2820 	crypto_generichash_update(&h, q, sizeof q);
2821 	sodium_memzero(q, sizeof q);
2822 	crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES);
2823 	crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES);
2824 	crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES);
2825 	sodium_memzero(&h, sizeof h);
2826 	array_init(return_value);
2827 	add_next_index_stringl(return_value,
2828 						   (const char *) session_keys,
2829 						   crypto_kx_SESSIONKEYBYTES);
2830 	add_next_index_stringl(return_value,
2831 						   (const char *) session_keys + crypto_kx_SESSIONKEYBYTES,
2832 						   crypto_kx_SESSIONKEYBYTES);
2833 }
2834 
PHP_FUNCTION(sodium_crypto_kx_server_session_keys)2835 PHP_FUNCTION(sodium_crypto_kx_server_session_keys)
2836 {
2837 	crypto_generichash_state h;
2838 	unsigned char  q[crypto_scalarmult_BYTES];
2839 	unsigned char *keypair;
2840 	unsigned char *server_sk;
2841 	unsigned char *server_pk;
2842 	unsigned char *client_pk;
2843 	unsigned char  session_keys[2 * crypto_kx_SESSIONKEYBYTES];
2844 	size_t         keypair_len;
2845 	size_t         client_pk_len;
2846 
2847 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2848 									&keypair, &keypair_len,
2849 									&client_pk, &client_pk_len) == FAILURE) {
2850 		sodium_remove_param_values_from_backtrace(EG(exception));
2851 		RETURN_THROWS();
2852 	}
2853 	if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2854 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2855 		RETURN_THROWS();
2856 	}
2857 	if (client_pk_len != crypto_kx_PUBLICKEYBYTES) {
2858 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes long");
2859 		RETURN_THROWS();
2860 	}
2861 	server_sk = &keypair[0];
2862 	server_pk = &keypair[crypto_kx_SECRETKEYBYTES];
2863 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2864 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2865 	if (crypto_scalarmult(q, server_sk, client_pk) != 0) {
2866 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2867 		RETURN_THROWS();
2868 	}
2869 	crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES);
2870 	crypto_generichash_update(&h, q, sizeof q);
2871 	sodium_memzero(q, sizeof q);
2872 	crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES);
2873 	crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES);
2874 	crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES);
2875 	sodium_memzero(&h, sizeof h);
2876 	array_init(return_value);
2877 	add_next_index_stringl(return_value,
2878 						   (const char *) session_keys + crypto_kx_SESSIONKEYBYTES,
2879 						   crypto_kx_SESSIONKEYBYTES);
2880 	add_next_index_stringl(return_value,
2881 						   (const char *) session_keys,
2882 						   crypto_kx_SESSIONKEYBYTES);
2883 }
2884 
PHP_FUNCTION(sodium_crypto_auth)2885 PHP_FUNCTION(sodium_crypto_auth)
2886 {
2887 	zend_string *mac;
2888 	char        *key;
2889 	char        *msg;
2890 	size_t       msg_len;
2891 	size_t       key_len;
2892 
2893 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2894 									&msg, &msg_len,
2895 									&key, &key_len) == FAILURE) {
2896 		sodium_remove_param_values_from_backtrace(EG(exception));
2897 		RETURN_THROWS();
2898 	}
2899 	if (key_len != crypto_auth_KEYBYTES) {
2900 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes long");
2901 		RETURN_THROWS();
2902 	}
2903 	mac = zend_string_alloc(crypto_auth_BYTES, 0);
2904 	if (crypto_auth((unsigned char *) ZSTR_VAL(mac),
2905 					(const unsigned char *) msg, msg_len,
2906 					(const unsigned char *) key) != 0) {
2907 		zend_string_efree(mac);
2908 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2909 		RETURN_THROWS();
2910 	}
2911 	ZSTR_VAL(mac)[crypto_auth_BYTES] = 0;
2912 
2913 	RETURN_STR(mac);
2914 }
2915 
PHP_FUNCTION(sodium_crypto_auth_verify)2916 PHP_FUNCTION(sodium_crypto_auth_verify)
2917 {
2918 	char      *mac;
2919 	char      *key;
2920 	char      *msg;
2921 	size_t     mac_len;
2922 	size_t     msg_len;
2923 	size_t     key_len;
2924 
2925 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
2926 									&mac, &mac_len,
2927 									&msg, &msg_len,
2928 									&key, &key_len) == FAILURE) {
2929 		sodium_remove_param_values_from_backtrace(EG(exception));
2930 		RETURN_THROWS();
2931 	}
2932 	if (key_len != crypto_auth_KEYBYTES) {
2933 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes long");
2934 		RETURN_THROWS();
2935 	}
2936 	if (mac_len != crypto_auth_BYTES) {
2937 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_AUTH_BYTES bytes long");
2938 		RETURN_THROWS();
2939 	}
2940 	if (crypto_auth_verify((const unsigned char *) mac,
2941 						   (const unsigned char *) msg, msg_len,
2942 						   (const unsigned char *) key) != 0) {
2943 		RETURN_FALSE;
2944 	}
2945 	RETURN_TRUE;
2946 }
2947 
PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)2948 PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)
2949 {
2950 	zend_string *ecdhkey;
2951 	char        *eddsakey;
2952 	size_t       eddsakey_len;
2953 
2954 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2955 									&eddsakey, &eddsakey_len) == FAILURE) {
2956 		sodium_remove_param_values_from_backtrace(EG(exception));
2957 		RETURN_THROWS();
2958 	}
2959 	if (eddsakey_len != crypto_sign_SECRETKEYBYTES) {
2960 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
2961 		RETURN_THROWS();
2962 	}
2963 	ecdhkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0);
2964 
2965 	if (crypto_sign_ed25519_sk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey),
2966 											 (const unsigned char *) eddsakey) != 0) {
2967 		zend_string_efree(ecdhkey);
2968 		zend_throw_exception(sodium_exception_ce, "conversion failed", 0);
2969 		RETURN_THROWS();
2970 	}
2971 	ZSTR_VAL(ecdhkey)[crypto_box_SECRETKEYBYTES] = 0;
2972 
2973 	RETURN_STR(ecdhkey);
2974 }
2975 
PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519)2976 PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519)
2977 {
2978 	zend_string *ecdhkey;
2979 	char        *eddsakey;
2980 	size_t       eddsakey_len;
2981 
2982 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2983 									&eddsakey, &eddsakey_len) == FAILURE) {
2984 		sodium_remove_param_values_from_backtrace(EG(exception));
2985 		RETURN_THROWS();
2986 	}
2987 	if (eddsakey_len != crypto_sign_PUBLICKEYBYTES) {
2988 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
2989 		RETURN_THROWS();
2990 	}
2991 	ecdhkey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
2992 
2993 	if (crypto_sign_ed25519_pk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey),
2994 											 (const unsigned char *) eddsakey) != 0) {
2995 		zend_string_efree(ecdhkey);
2996 		zend_throw_exception(sodium_exception_ce, "conversion failed", 0);
2997 		RETURN_THROWS();
2998 	}
2999 	ZSTR_VAL(ecdhkey)[crypto_box_PUBLICKEYBYTES] = 0;
3000 
3001 	RETURN_STR(ecdhkey);
3002 }
3003 
PHP_FUNCTION(sodium_compare)3004 PHP_FUNCTION(sodium_compare)
3005 {
3006 	char      *buf1;
3007 	char      *buf2;
3008 	size_t     len1;
3009 	size_t     len2;
3010 
3011 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3012 									&buf1, &len1,
3013 									&buf2, &len2) == FAILURE) {
3014 		sodium_remove_param_values_from_backtrace(EG(exception));
3015 		RETURN_THROWS();
3016 	}
3017 	if (len1 != len2) {
3018 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
3019 		RETURN_THROWS();
3020 	} else {
3021 		RETURN_LONG(sodium_compare((const unsigned char *) buf1,
3022 								   (const unsigned char *) buf2, (size_t) len1));
3023 	}
3024 }
3025 
3026 #ifdef HAVE_AESGCM
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen)3027 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen)
3028 {
3029 	unsigned char key[crypto_aead_aes256gcm_KEYBYTES];
3030 
3031 	if (zend_parse_parameters_none() == FAILURE) {
3032 		RETURN_THROWS();
3033 	}
3034 	randombytes_buf(key, sizeof key);
3035 	RETURN_STRINGL((const char *) key, sizeof key);
3036 }
3037 #endif
3038 
3039 #ifdef crypto_aead_aegis128l_KEYBYTES
PHP_FUNCTION(sodium_crypto_aead_aegis128l_keygen)3040 PHP_FUNCTION(sodium_crypto_aead_aegis128l_keygen)
3041 {
3042 	unsigned char key[crypto_aead_aegis128l_KEYBYTES];
3043 
3044 	if (zend_parse_parameters_none() == FAILURE) {
3045 		RETURN_THROWS();
3046 	}
3047 	crypto_aead_aegis128l_keygen(key);
3048 	RETURN_STRINGL((const char *) key, sizeof key);
3049 }
3050 #endif
3051 
3052 #ifdef crypto_aead_aegis256_KEYBYTES
PHP_FUNCTION(sodium_crypto_aead_aegis256_keygen)3053 PHP_FUNCTION(sodium_crypto_aead_aegis256_keygen)
3054 {
3055 	unsigned char key[crypto_aead_aegis256_KEYBYTES];
3056 
3057 	if (zend_parse_parameters_none() == FAILURE) {
3058 		RETURN_THROWS();
3059 	}
3060 	crypto_aead_aegis256_keygen(key);
3061 	RETURN_STRINGL((const char *) key, sizeof key);
3062 }
3063 #endif
3064 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen)3065 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen)
3066 {
3067 	unsigned char key[crypto_aead_chacha20poly1305_KEYBYTES];
3068 
3069 	if (zend_parse_parameters_none() == FAILURE) {
3070 		RETURN_THROWS();
3071 	}
3072 	randombytes_buf(key, sizeof key);
3073 	RETURN_STRINGL((const char *) key, sizeof key);
3074 }
3075 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen)3076 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen)
3077 {
3078 	unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES];
3079 
3080 	if (zend_parse_parameters_none() == FAILURE) {
3081 		RETURN_THROWS();
3082 	}
3083 	randombytes_buf(key, sizeof key);
3084 	RETURN_STRINGL((const char *) key, sizeof key);
3085 }
3086 
3087 #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen)3088 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen)
3089 {
3090 	unsigned char key[crypto_aead_xchacha20poly1305_IETF_KEYBYTES];
3091 
3092 	if (zend_parse_parameters_none() == FAILURE) {
3093 		RETURN_THROWS();
3094 	}
3095 	randombytes_buf(key, sizeof key);
3096 	RETURN_STRINGL((const char *) key, sizeof key);
3097 }
3098 #endif
3099 
PHP_FUNCTION(sodium_crypto_auth_keygen)3100 PHP_FUNCTION(sodium_crypto_auth_keygen)
3101 {
3102 	unsigned char key[crypto_auth_KEYBYTES];
3103 
3104 	if (zend_parse_parameters_none() == FAILURE) {
3105 		RETURN_THROWS();
3106 	}
3107 	randombytes_buf(key, sizeof key);
3108 	RETURN_STRINGL((const char *) key, sizeof key);
3109 }
3110 
PHP_FUNCTION(sodium_crypto_generichash_keygen)3111 PHP_FUNCTION(sodium_crypto_generichash_keygen)
3112 {
3113 	unsigned char key[crypto_generichash_KEYBYTES];
3114 
3115 	if (zend_parse_parameters_none() == FAILURE) {
3116 		RETURN_THROWS();
3117 	}
3118 	randombytes_buf(key, sizeof key);
3119 	RETURN_STRINGL((const char *) key, sizeof key);
3120 }
3121 
PHP_FUNCTION(sodium_crypto_kdf_keygen)3122 PHP_FUNCTION(sodium_crypto_kdf_keygen)
3123 {
3124 	unsigned char key[crypto_kdf_KEYBYTES];
3125 
3126 	if (zend_parse_parameters_none() == FAILURE) {
3127 		RETURN_THROWS();
3128 	}
3129 	randombytes_buf(key, sizeof key);
3130 	RETURN_STRINGL((const char *) key, sizeof key);
3131 }
3132 
PHP_FUNCTION(sodium_crypto_secretbox_keygen)3133 PHP_FUNCTION(sodium_crypto_secretbox_keygen)
3134 {
3135 	unsigned char key[crypto_secretbox_KEYBYTES];
3136 
3137 	if (zend_parse_parameters_none() == FAILURE) {
3138 		RETURN_THROWS();
3139 	}
3140 	randombytes_buf(key, sizeof key);
3141 	RETURN_STRINGL((const char *) key, sizeof key);
3142 }
3143 
PHP_FUNCTION(sodium_crypto_shorthash_keygen)3144 PHP_FUNCTION(sodium_crypto_shorthash_keygen)
3145 {
3146 	unsigned char key[crypto_shorthash_KEYBYTES];
3147 
3148 	if (zend_parse_parameters_none() == FAILURE) {
3149 		RETURN_THROWS();
3150 	}
3151 	randombytes_buf(key, sizeof key);
3152 	RETURN_STRINGL((const char *) key, sizeof key);
3153 }
3154 
PHP_FUNCTION(sodium_crypto_stream_keygen)3155 PHP_FUNCTION(sodium_crypto_stream_keygen)
3156 {
3157 	unsigned char key[crypto_stream_KEYBYTES];
3158 
3159 	if (zend_parse_parameters_none() == FAILURE) {
3160 		RETURN_THROWS();
3161 	}
3162 	randombytes_buf(key, sizeof key);
3163 	RETURN_STRINGL((const char *) key, sizeof key);
3164 }
3165 #ifdef crypto_stream_xchacha20_KEYBYTES
PHP_FUNCTION(sodium_crypto_stream_xchacha20_keygen)3166 PHP_FUNCTION(sodium_crypto_stream_xchacha20_keygen)
3167 {
3168 	unsigned char key[crypto_stream_xchacha20_KEYBYTES];
3169 
3170 	if (zend_parse_parameters_none() == FAILURE) {
3171 		return;
3172 	}
3173 	randombytes_buf(key, sizeof key);
3174 	RETURN_STRINGL((const char *) key, sizeof key);
3175 }
3176 #endif
3177 
PHP_FUNCTION(sodium_crypto_kdf_derive_from_key)3178 PHP_FUNCTION(sodium_crypto_kdf_derive_from_key)
3179 {
3180 	unsigned char  ctx_padded[crypto_generichash_blake2b_PERSONALBYTES];
3181 #ifndef crypto_kdf_PRIMITIVE
3182 	unsigned char  salt[crypto_generichash_blake2b_SALTBYTES];
3183 #endif
3184 	char          *ctx;
3185 	char          *key;
3186 	zend_string   *subkey;
3187 	zend_long      subkey_id;
3188 	zend_long      subkey_len;
3189 	size_t         ctx_len;
3190 	size_t         key_len;
3191 
3192 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "llss",
3193 									&subkey_len,
3194 									&subkey_id,
3195 									&ctx, &ctx_len,
3196 									&key, &key_len) == FAILURE) {
3197 		sodium_remove_param_values_from_backtrace(EG(exception));
3198 		RETURN_THROWS();
3199 	}
3200 	if (subkey_len < crypto_kdf_BYTES_MIN) {
3201 		zend_argument_error(sodium_exception_ce, 1, "must be greater than or equal to SODIUM_CRYPTO_KDF_BYTES_MIN");
3202 		RETURN_THROWS();
3203 	}
3204 	if (subkey_len > crypto_kdf_BYTES_MAX || subkey_len > SIZE_MAX) {
3205 		zend_argument_error(sodium_exception_ce, 1, "must be less than or equal to SODIUM_CRYPTO_KDF_BYTES_MAX");
3206 		RETURN_THROWS();
3207 	}
3208 	if (subkey_id < 0) {
3209 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to 0");
3210 		RETURN_THROWS();
3211 	}
3212 	if (ctx_len != crypto_kdf_CONTEXTBYTES) {
3213 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes long");
3214 		RETURN_THROWS();
3215 	}
3216 	if (key_len != crypto_kdf_KEYBYTES) {
3217 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_KDF_BYTES_MIN bytes long");
3218 		RETURN_THROWS();
3219 	}
3220 	memcpy(ctx_padded, ctx, crypto_kdf_CONTEXTBYTES);
3221 	memset(ctx_padded + crypto_kdf_CONTEXTBYTES, 0, sizeof ctx_padded - crypto_kdf_CONTEXTBYTES);
3222 	subkey = zend_string_alloc((size_t) subkey_len, 0);
3223 #ifdef crypto_kdf_PRIMITIVE
3224 	crypto_kdf_derive_from_key((unsigned char *) ZSTR_VAL(subkey),
3225 							   (size_t) subkey_len, (uint64_t) subkey_id,
3226 							   ctx, (const unsigned char *) key);
3227 #else
3228 	salt[0] = (unsigned char) (((uint64_t) subkey_id)      );
3229 	salt[1] = (unsigned char) (((uint64_t) subkey_id) >>  8);
3230 	salt[2] = (unsigned char) (((uint64_t) subkey_id) >> 16);
3231 	salt[3] = (unsigned char) (((uint64_t) subkey_id) >> 24);
3232 	salt[4] = (unsigned char) (((uint64_t) subkey_id) >> 32);
3233 	salt[5] = (unsigned char) (((uint64_t) subkey_id) >> 40);
3234 	salt[6] = (unsigned char) (((uint64_t) subkey_id) >> 48);
3235 	salt[7] = (unsigned char) (((uint64_t) subkey_id) >> 56);
3236 	memset(salt + 8, 0, (sizeof salt) - 8);
3237 	crypto_generichash_blake2b_salt_personal((unsigned char *) ZSTR_VAL(subkey),
3238 											 (size_t) subkey_len,
3239 											 NULL, 0,
3240 											 (const unsigned char *) key,
3241 											 crypto_kdf_KEYBYTES,
3242 											 salt, ctx_padded);
3243 #endif
3244 	ZSTR_VAL(subkey)[subkey_len] = 0;
3245 
3246 	RETURN_STR(subkey);
3247 }
3248 
PHP_FUNCTION(sodium_pad)3249 PHP_FUNCTION(sodium_pad)
3250 {
3251 	zend_string    *padded;
3252 	char           *unpadded;
3253 	zend_long       blocksize;
3254 	volatile size_t st;
3255 	size_t          i, j, k;
3256 	size_t          unpadded_len;
3257 	size_t          xpadlen;
3258 	size_t          xpadded_len;
3259 
3260 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
3261 									&unpadded, &unpadded_len, &blocksize) == FAILURE) {
3262 		sodium_remove_param_values_from_backtrace(EG(exception));
3263 		RETURN_THROWS();
3264 	}
3265 	if (blocksize <= 0) {
3266 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
3267 		RETURN_THROWS();
3268 	}
3269 	if (blocksize > SIZE_MAX) {
3270 		zend_argument_error(sodium_exception_ce, 2, "is too large");
3271 		RETURN_THROWS();
3272 	}
3273 	xpadlen = blocksize - 1U;
3274 	if ((blocksize & (blocksize - 1U)) == 0U) {
3275 		xpadlen -= unpadded_len & ((size_t) blocksize - 1U);
3276 	} else {
3277 		xpadlen -= unpadded_len % (size_t) blocksize;
3278 	}
3279 	if ((size_t) SIZE_MAX - unpadded_len <= xpadlen) {
3280 		zend_throw_exception(sodium_exception_ce, "input is too large", 0);
3281 		RETURN_THROWS();
3282 	}
3283 	xpadded_len = unpadded_len + xpadlen;
3284 	padded = zend_string_alloc(xpadded_len + 1U, 0);
3285 	if (unpadded_len > 0) {
3286 		st = 1U;
3287 		i = 0U;
3288 		k = unpadded_len;
3289 		for (j = 0U; j <= xpadded_len; j++) {
3290 			ZSTR_VAL(padded)[j] = unpadded[i];
3291 			k -= st;
3292 			st = (size_t) (~(((( (((uint64_t) k) >> 48) | (((uint64_t) k) >> 32) |
3293 								 (k >> 16) | k) & 0xffff) - 1U) >> 16)) & 1U;
3294 			i += st;
3295 		}
3296 	}
3297 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
3298 	if (sodium_pad(NULL, (unsigned char *) ZSTR_VAL(padded), unpadded_len,
3299 				   (size_t) blocksize, xpadded_len + 1U) != 0) {
3300 		zend_string_efree(padded);
3301 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3302 		RETURN_THROWS();
3303 	}
3304 #else
3305 	{
3306 		char                   *tail;
3307 		volatile unsigned char  mask;
3308 		unsigned char           barrier_mask;
3309 
3310 		tail = &ZSTR_VAL(padded)[xpadded_len];
3311 		mask = 0U;
3312 		for (i = 0; i < blocksize; i++) {
3313 			barrier_mask = (unsigned char)
3314 				(((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
3315 			tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
3316 			mask |= barrier_mask;
3317 		}
3318 	}
3319 #endif
3320 	ZSTR_VAL(padded)[xpadded_len + 1U] = 0;
3321 
3322 	RETURN_STR(padded);
3323 }
3324 
PHP_FUNCTION(sodium_unpad)3325 PHP_FUNCTION(sodium_unpad)
3326 {
3327 	zend_string *unpadded;
3328 	char        *padded;
3329 	size_t       padded_len;
3330 	size_t       unpadded_len;
3331 	zend_long    blocksize;
3332 	int          ret;
3333 
3334 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
3335 									&padded, &padded_len, &blocksize) == FAILURE) {
3336 		sodium_remove_param_values_from_backtrace(EG(exception));
3337 		RETURN_THROWS();
3338 	}
3339 	if (blocksize <= 0) {
3340 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
3341 		RETURN_THROWS();
3342 	}
3343 	if (blocksize > SIZE_MAX) {
3344 		zend_argument_error(sodium_exception_ce, 2, "is too large");
3345 		RETURN_THROWS();
3346 	}
3347 	if (padded_len < blocksize) {
3348 		zend_argument_error(sodium_exception_ce, 1, "must be at least as long as the block size");
3349 		RETURN_THROWS();
3350 	}
3351 
3352 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
3353 	ret = sodium_unpad(&unpadded_len, (const unsigned char *) padded,
3354 					   padded_len, (size_t) blocksize);
3355 #else
3356 	{
3357 		const char      *tail;
3358 		unsigned char    acc = 0U;
3359 		unsigned char    c;
3360 		unsigned char    valid = 0U;
3361 		volatile size_t  pad_len = 0U;
3362 		size_t           i;
3363 		size_t           is_barrier;
3364 
3365 		tail = &padded[padded_len - 1U];
3366 
3367 		for (i = 0U; i < (size_t) blocksize; i++) {
3368 			c = tail[-i];
3369 			is_barrier =
3370 				(( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
3371 			acc |= c;
3372 			pad_len |= i & (1U + ~is_barrier);
3373 			valid |= (unsigned char) is_barrier;
3374 		}
3375 		unpadded_len = padded_len - 1U - pad_len;
3376 		ret = (int) (valid - 1U);
3377 	}
3378 #endif
3379 	if (ret != 0 || unpadded_len > LONG_MAX) {
3380 		zend_throw_exception(sodium_exception_ce, "invalid padding", 0);
3381 		RETURN_THROWS();
3382 	}
3383 	unpadded = zend_string_init(padded, padded_len, 0);
3384 	PHP_SODIUM_ZSTR_TRUNCATE(unpadded, unpadded_len);
3385 	ZSTR_VAL(unpadded)[unpadded_len] = 0;
3386 	RETURN_STR(unpadded);
3387 }
3388 
3389 #ifdef crypto_secretstream_xchacha20poly1305_ABYTES
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen)3390 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen)
3391 {
3392 	unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES];
3393 
3394 	if (zend_parse_parameters_none() == FAILURE) {
3395 		RETURN_THROWS();
3396 	}
3397 	randombytes_buf(key, sizeof key);
3398 	RETURN_STRINGL((const char *) key, sizeof key);
3399 }
3400 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push)3401 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push)
3402 {
3403 	crypto_secretstream_xchacha20poly1305_state  state;
3404 	unsigned char                                header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
3405 	unsigned char                               *key;
3406 	size_t                                       key_len;
3407 
3408 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3409 									&key, &key_len) == FAILURE) {
3410 		sodium_remove_param_values_from_backtrace(EG(exception));
3411 		RETURN_THROWS();
3412 	}
3413 	if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
3414 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes long");
3415 		RETURN_THROWS();
3416 	}
3417 	if (crypto_secretstream_xchacha20poly1305_init_push(&state,
3418 														header, key) != 0) {
3419 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3420 		RETURN_THROWS();
3421 	}
3422 	array_init(return_value);
3423 	add_next_index_stringl(return_value, (const char *) &state, sizeof state);
3424 	add_next_index_stringl(return_value, (const char *) header, sizeof header);
3425 }
3426 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push)3427 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push)
3428 {
3429 	zval               *state_zv;
3430 	zend_string        *c;
3431 	unsigned char      *ad = NULL;
3432 	unsigned char      *msg;
3433 	unsigned char      *state;
3434 	unsigned long long  c_real_len;
3435 	zend_long           tag = crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
3436 	size_t              ad_len = (size_t) 0U;
3437 	size_t              c_len;
3438 	size_t              msg_len;
3439 	size_t              state_len;
3440 
3441 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|sl",
3442 									&state_zv,
3443 									&msg, &msg_len, &ad, &ad_len, &tag) == FAILURE) {
3444 		sodium_remove_param_values_from_backtrace(EG(exception));
3445 		RETURN_THROWS();
3446 	}
3447 	ZVAL_DEREF(state_zv);
3448 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3449 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3450 		RETURN_THROWS();
3451 	}
3452 	sodium_separate_string(state_zv);
3453 	state = (unsigned char *) Z_STRVAL(*state_zv);
3454 	state_len = Z_STRLEN(*state_zv);
3455 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3456 		zend_argument_error(sodium_exception_ce, 1, "must have a correct length");
3457 		RETURN_THROWS();
3458 	}
3459 	if (msg_len > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX ||
3460 		msg_len > SIZE_MAX - crypto_secretstream_xchacha20poly1305_ABYTES) {
3461 		zend_argument_error(sodium_exception_ce, 2, "must be at most SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes long");
3462 		RETURN_THROWS();
3463 	}
3464 	if (tag < 0 || tag > 255) {
3465 		zend_argument_error(sodium_exception_ce, 4, "must be in the range of 0-255");
3466 		RETURN_THROWS();
3467 	}
3468 	c_len = msg_len + crypto_secretstream_xchacha20poly1305_ABYTES;
3469 	c = zend_string_alloc((size_t) c_len, 0);
3470 	if (crypto_secretstream_xchacha20poly1305_push
3471 		((void *) state, (unsigned char *) ZSTR_VAL(c), &c_real_len,
3472 		 msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len,
3473 		 (unsigned char) tag) != 0) {
3474 		zend_string_efree(c);
3475 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3476 		RETURN_THROWS();
3477 	}
3478 	if (c_real_len <= 0U || c_real_len >= SIZE_MAX || c_real_len > c_len) {
3479 		zend_string_efree(c);
3480 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
3481 		RETURN_THROWS();
3482 	}
3483 	PHP_SODIUM_ZSTR_TRUNCATE(c, (size_t) c_real_len);
3484 	ZSTR_VAL(c)[c_real_len] = 0;
3485 
3486 	RETURN_NEW_STR(c);
3487 }
3488 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull)3489 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull)
3490 {
3491 	crypto_secretstream_xchacha20poly1305_state  state;
3492 	unsigned char                               *header;
3493 	unsigned char                               *key;
3494 	size_t                                       header_len;
3495 	size_t                                       key_len;
3496 
3497 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3498 									&header, &header_len,
3499 									&key, &key_len) == FAILURE) {
3500 		sodium_remove_param_values_from_backtrace(EG(exception));
3501 		RETURN_THROWS();
3502 	}
3503 	if (header_len != crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
3504 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes long");
3505 		RETURN_THROWS();
3506 	}
3507 	if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
3508 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes long");
3509 		RETURN_THROWS();
3510 	}
3511 	if (crypto_secretstream_xchacha20poly1305_init_pull(&state,
3512 														header, key) != 0) {
3513 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3514 		RETURN_THROWS();
3515 	}
3516 	RETURN_STRINGL((const char *) &state, sizeof state);
3517 }
3518 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull)3519 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull)
3520 {
3521 	zval               *state_zv;
3522 	zend_string        *msg;
3523 	unsigned char      *ad = NULL;
3524 	unsigned char      *c;
3525 	unsigned char      *state;
3526 	unsigned long long  msg_real_len;
3527 	size_t              ad_len = (size_t) 0U;
3528 	size_t              msg_len;
3529 	size_t              c_len;
3530 	size_t              state_len;
3531 	unsigned char       tag;
3532 
3533 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|s",
3534 									&state_zv,
3535 									&c, &c_len, &ad, &ad_len) == FAILURE) {
3536 		sodium_remove_param_values_from_backtrace(EG(exception));
3537 		RETURN_THROWS();
3538 	}
3539 	ZVAL_DEREF(state_zv);
3540 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3541 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3542 		RETURN_THROWS();
3543 	}
3544 	sodium_separate_string(state_zv);
3545 	state = (unsigned char *) Z_STRVAL(*state_zv);
3546 	state_len = Z_STRLEN(*state_zv);
3547 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3548 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
3549 		RETURN_THROWS();
3550 	}
3551 	if (c_len < crypto_secretstream_xchacha20poly1305_ABYTES) {
3552 		RETURN_FALSE;
3553 	}
3554 	msg_len = c_len - crypto_secretstream_xchacha20poly1305_ABYTES;
3555 	msg = zend_string_alloc((size_t) msg_len, 0);
3556 	if (crypto_secretstream_xchacha20poly1305_pull
3557 		((void *) state, (unsigned char *) ZSTR_VAL(msg), &msg_real_len, &tag,
3558 		 c, (unsigned long long) c_len, ad, (unsigned long long) ad_len) != 0) {
3559 		zend_string_efree(msg);
3560 		RETURN_FALSE;
3561 	}
3562 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
3563 		zend_string_efree(msg);
3564 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
3565 		RETURN_THROWS();
3566 	}
3567 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
3568 	ZSTR_VAL(msg)[msg_real_len] = 0;
3569 	array_init(return_value);
3570 	add_next_index_str(return_value, msg);
3571 	add_next_index_long(return_value, (long) tag);
3572 }
3573 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey)3574 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey)
3575 {
3576 	zval          *state_zv;
3577 	unsigned char *state;
3578 	size_t         state_len;
3579 
3580 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &state_zv) == FAILURE) {
3581 		sodium_remove_param_values_from_backtrace(EG(exception));
3582 		RETURN_THROWS();
3583 	}
3584 	ZVAL_DEREF(state_zv);
3585 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3586 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3587 		RETURN_THROWS();
3588 	}
3589 	sodium_separate_string(state_zv);
3590 	state = (unsigned char *) Z_STRVAL(*state_zv);
3591 	state_len = Z_STRLEN(*state_zv);
3592 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3593 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
3594 		RETURN_THROWS();
3595 	}
3596 	crypto_secretstream_xchacha20poly1305_rekey((void *) state);
3597 }
3598 #endif
3599 
3600 #ifdef crypto_core_ristretto255_HASHBYTES
PHP_FUNCTION(sodium_crypto_core_ristretto255_add)3601 PHP_FUNCTION(sodium_crypto_core_ristretto255_add)
3602 {
3603 	zend_string   *r;
3604 	unsigned char *p;
3605 	unsigned char *q;
3606 	size_t         p_len;
3607 	size_t         q_len;
3608 
3609 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3610 									&p, &p_len, &q, &q_len) == FAILURE) {
3611 		sodium_remove_param_values_from_backtrace(EG(exception));
3612 		RETURN_THROWS();
3613 	}
3614 	if (p_len != crypto_core_ristretto255_BYTES) {
3615 		zend_argument_error(sodium_exception_ce, 1,
3616 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3617 		RETURN_THROWS();
3618 	}
3619 	if (q_len != crypto_core_ristretto255_BYTES) {
3620 		zend_argument_error(sodium_exception_ce, 2,
3621 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3622 		RETURN_THROWS();
3623 	}
3624 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3625 	if (crypto_core_ristretto255_add((unsigned char *) ZSTR_VAL(r), p, q) != 0) {
3626 		zend_string_efree(r);
3627 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3628 		RETURN_THROWS();
3629 	}
3630 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3631 	RETURN_NEW_STR(r);
3632 }
3633 
PHP_FUNCTION(sodium_crypto_core_ristretto255_from_hash)3634 PHP_FUNCTION(sodium_crypto_core_ristretto255_from_hash)
3635 {
3636 	zend_string   *r;
3637 	unsigned char *s;
3638 	size_t         s_len;
3639 
3640 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3641 							  &s, &s_len) == FAILURE) {
3642 		sodium_remove_param_values_from_backtrace(EG(exception));
3643 		RETURN_THROWS();
3644 	}
3645 	if (s_len != crypto_core_ristretto255_HASHBYTES) {
3646 		zend_argument_error(sodium_exception_ce, 1,
3647 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES bytes long");
3648 		RETURN_THROWS();
3649 	}
3650 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3651 	if (crypto_core_ristretto255_from_hash((unsigned char *) ZSTR_VAL(r), s) != 0) {
3652 		zend_string_efree(r);
3653 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3654 		RETURN_THROWS();
3655 	}
3656 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3657 	RETURN_NEW_STR(r);
3658 }
3659 
PHP_FUNCTION(sodium_crypto_core_ristretto255_is_valid_point)3660 PHP_FUNCTION(sodium_crypto_core_ristretto255_is_valid_point)
3661 {
3662 	unsigned char *s;
3663 	size_t         s_len;
3664 
3665 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3666 							  &s, &s_len) == FAILURE) {
3667 		sodium_remove_param_values_from_backtrace(EG(exception));
3668 		RETURN_THROWS();
3669 	}
3670 	if (s_len != crypto_core_ristretto255_BYTES) {
3671 		zend_argument_error(sodium_exception_ce, 1,
3672 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3673 		RETURN_THROWS();
3674 	}
3675 	RETURN_BOOL(crypto_core_ristretto255_is_valid_point(s));
3676 }
3677 
PHP_FUNCTION(sodium_crypto_core_ristretto255_random)3678 PHP_FUNCTION(sodium_crypto_core_ristretto255_random)
3679 {
3680 	zend_string   *r;
3681 
3682 	if (zend_parse_parameters_none() == FAILURE) {
3683 		RETURN_THROWS();
3684 	}
3685 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3686 	crypto_core_ristretto255_random((unsigned char *) ZSTR_VAL(r));
3687 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3688 	RETURN_NEW_STR(r);
3689 }
3690 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_add)3691 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_add)
3692 {
3693 	zend_string   *r;
3694 	unsigned char *p;
3695 	unsigned char *q;
3696 	size_t         p_len;
3697 	size_t         q_len;
3698 
3699 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3700 									&p, &p_len, &q, &q_len) == FAILURE) {
3701 		sodium_remove_param_values_from_backtrace(EG(exception));
3702 		RETURN_THROWS();
3703 	}
3704 	if (p_len != crypto_core_ristretto255_SCALARBYTES) {
3705 		zend_argument_error(sodium_exception_ce, 1,
3706 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3707 		RETURN_THROWS();
3708 	}
3709 	if (q_len != crypto_core_ristretto255_SCALARBYTES) {
3710 		zend_argument_error(sodium_exception_ce, 2,
3711 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3712 		RETURN_THROWS();
3713 	}
3714 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3715 	crypto_core_ristretto255_scalar_add((unsigned char *) ZSTR_VAL(r), p, q);
3716 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3717 	RETURN_NEW_STR(r);
3718 }
3719 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_complement)3720 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_complement)
3721 {
3722 	zend_string   *r;
3723 	unsigned char *s;
3724 	size_t         s_len;
3725 
3726 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3727 							  &s, &s_len) == FAILURE) {
3728 		sodium_remove_param_values_from_backtrace(EG(exception));
3729 		RETURN_THROWS();
3730 	}
3731 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3732 		zend_argument_error(sodium_exception_ce, 1,
3733 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3734 		RETURN_THROWS();
3735 	}
3736 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3737 	crypto_core_ristretto255_scalar_complement((unsigned char *) ZSTR_VAL(r), s);
3738 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3739 	RETURN_NEW_STR(r);
3740 }
3741 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_invert)3742 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_invert)
3743 {
3744 	zend_string   *r;
3745 	unsigned char *s;
3746 	size_t         s_len;
3747 
3748 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3749 							  &s, &s_len) == FAILURE) {
3750 		sodium_remove_param_values_from_backtrace(EG(exception));
3751 		RETURN_THROWS();
3752 	}
3753 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3754 		zend_argument_error(sodium_exception_ce, 1,
3755 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3756 		RETURN_THROWS();
3757 	}
3758 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3759 	if (crypto_core_ristretto255_scalar_invert((unsigned char *) ZSTR_VAL(r), s) != 0) {
3760 		zend_string_efree(r);
3761 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3762 		RETURN_THROWS();
3763 	}
3764 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3765 	RETURN_NEW_STR(r);
3766 }
3767 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_mul)3768 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_mul)
3769 {
3770 	zend_string   *r;
3771 	unsigned char *x;
3772 	unsigned char *y;
3773 	size_t         x_len;
3774 	size_t         y_len;
3775 
3776 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3777 									&x, &x_len, &y, &y_len) == FAILURE) {
3778 		sodium_remove_param_values_from_backtrace(EG(exception));
3779 		RETURN_THROWS();
3780 	}
3781 	if (x_len != crypto_core_ristretto255_SCALARBYTES) {
3782 		zend_argument_error(sodium_exception_ce, 1,
3783 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3784 		RETURN_THROWS();
3785 	}
3786 	if (y_len != crypto_core_ristretto255_SCALARBYTES) {
3787 		zend_argument_error(sodium_exception_ce, 2,
3788 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3789 		RETURN_THROWS();
3790 	}
3791 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3792 	crypto_core_ristretto255_scalar_mul((unsigned char *) ZSTR_VAL(r), x, y);
3793 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3794 	RETURN_NEW_STR(r);
3795 }
3796 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_negate)3797 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_negate)
3798 {
3799 	zend_string   *r;
3800 	unsigned char *s;
3801 	size_t         s_len;
3802 
3803 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3804 							  &s, &s_len) == FAILURE) {
3805 		sodium_remove_param_values_from_backtrace(EG(exception));
3806 		RETURN_THROWS();
3807 	}
3808 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3809 		zend_argument_error(sodium_exception_ce, 1,
3810 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3811 		RETURN_THROWS();
3812 	}
3813 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3814 	crypto_core_ristretto255_scalar_negate((unsigned char *) ZSTR_VAL(r), s);
3815 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3816 	RETURN_NEW_STR(r);
3817 }
3818 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_random)3819 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_random)
3820 {
3821 	zend_string   *r;
3822 
3823 	if (zend_parse_parameters_none() == FAILURE) {
3824 		RETURN_THROWS();
3825 	};
3826 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3827 	crypto_core_ristretto255_scalar_random((unsigned char *) ZSTR_VAL(r));
3828 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3829 	RETURN_NEW_STR(r);
3830 }
3831 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_reduce)3832 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_reduce)
3833 {
3834 	zend_string   *r;
3835 	unsigned char *s;
3836 	size_t         s_len;
3837 
3838 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3839 							  &s, &s_len) == FAILURE) {
3840 		sodium_remove_param_values_from_backtrace(EG(exception));
3841 		RETURN_THROWS();
3842 	}
3843 	if (s_len != crypto_core_ristretto255_NONREDUCEDSCALARBYTES) {
3844 		zend_argument_error(sodium_exception_ce, 1,
3845 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES bytes long");
3846 		RETURN_THROWS();
3847 	}
3848 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3849 	crypto_core_ristretto255_scalar_reduce((unsigned char *) ZSTR_VAL(r), s);
3850 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3851 	RETURN_NEW_STR(r);
3852 }
3853 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_sub)3854 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_sub)
3855 {
3856 	zend_string   *r;
3857 	unsigned char *p;
3858 	unsigned char *q;
3859 	size_t         p_len;
3860 	size_t         q_len;
3861 
3862 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3863 									&p, &p_len, &q, &q_len) == FAILURE) {
3864 		sodium_remove_param_values_from_backtrace(EG(exception));
3865 		RETURN_THROWS();
3866 	}
3867 	if (p_len != crypto_core_ristretto255_SCALARBYTES) {
3868 		zend_argument_error(sodium_exception_ce, 1,
3869 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3870 		RETURN_THROWS();
3871 	}
3872 	if (q_len != crypto_core_ristretto255_SCALARBYTES) {
3873 		zend_argument_error(sodium_exception_ce, 2,
3874 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3875 		RETURN_THROWS();
3876 	}
3877 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3878 	crypto_core_ristretto255_scalar_sub((unsigned char *) ZSTR_VAL(r), p, q);
3879 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3880 	RETURN_NEW_STR(r);
3881 }
3882 
PHP_FUNCTION(sodium_crypto_core_ristretto255_sub)3883 PHP_FUNCTION(sodium_crypto_core_ristretto255_sub)
3884 {
3885 	zend_string   *r;
3886 	unsigned char *p;
3887 	unsigned char *q;
3888 	size_t         p_len;
3889 	size_t         q_len;
3890 
3891 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3892 									&p, &p_len, &q, &q_len) == FAILURE) {
3893 		sodium_remove_param_values_from_backtrace(EG(exception));
3894 		RETURN_THROWS();
3895 	}
3896 	if (p_len != crypto_core_ristretto255_BYTES) {
3897 		zend_argument_error(sodium_exception_ce, 1,
3898 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3899 		RETURN_THROWS();
3900 	}
3901 	if (q_len != crypto_core_ristretto255_BYTES) {
3902 		zend_argument_error(sodium_exception_ce, 2,
3903 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3904 		RETURN_THROWS();
3905 	}
3906 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3907 	if (crypto_core_ristretto255_sub((unsigned char *) ZSTR_VAL(r), p, q) != 0) {
3908 		zend_string_efree(r);
3909 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3910 		RETURN_THROWS();
3911 	}
3912 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3913 	RETURN_NEW_STR(r);
3914 }
3915 #endif
3916