xref: /php-src/ext/sodium/libsodium.c (revision 1816403d)
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 "php_ini.h"
23 #include "ext/standard/info.h"
24 #include "php_libsodium.h"
25 #include "zend_attributes.h"
26 #include "zend_exceptions.h"
27 
28 #include <sodium.h>
29 #include <stdint.h>
30 #include <string.h>
31 
32 #define PHP_SODIUM_ZSTR_TRUNCATE(zs, len) do { ZSTR_LEN(zs) = (len); } while(0)
33 
34 static zend_class_entry *sodium_exception_ce;
35 
36 #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(__i386__) || \
37 	 defined(_M_AMD64) || defined(_M_IX86) || defined(__aarch64__) || defined(_M_ARM64))
38 # define HAVE_AESGCM 1
39 #endif
40 
zend_string_checked_alloc(size_t len,int persistent)41 static zend_always_inline zend_string *zend_string_checked_alloc(size_t len, int persistent)
42 {
43 	zend_string *zs;
44 
45 	if (ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)) < len) {
46 		zend_error_noreturn(E_ERROR, "Memory allocation too large (%zu bytes)", len);
47 	}
48 	zs = zend_string_alloc(len, persistent);
49 	ZSTR_VAL(zs)[len] = 0;
50 
51 	return zs;
52 }
53 
54 #ifndef crypto_kdf_BYTES_MIN
55 # define crypto_kdf_BYTES_MIN 16
56 # define crypto_kdf_BYTES_MAX 64
57 # define crypto_kdf_CONTEXTBYTES 8
58 # define crypto_kdf_KEYBYTES 32
59 #endif
60 
61 #ifndef crypto_kx_SEEDBYTES
62 # define crypto_kx_SEEDBYTES 32
63 # define crypto_kx_SESSIONKEYBYTES 32
64 # define crypto_kx_PUBLICKEYBYTES 32
65 # define crypto_kx_SECRETKEYBYTES 32
66 #endif
67 
68 #include "libsodium_arginfo.h"
69 
70 #ifndef crypto_aead_chacha20poly1305_IETF_KEYBYTES
71 # define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_KEYBYTES
72 #endif
73 #ifndef crypto_aead_chacha20poly1305_IETF_NSECBYTES
74 # define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_NSECBYTES
75 #endif
76 #ifndef crypto_aead_chacha20poly1305_IETF_ABYTES
77 # define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ABYTES
78 #endif
79 
80 #if defined(crypto_secretstream_xchacha20poly1305_ABYTES) && SODIUM_LIBRARY_VERSION_MAJOR < 10
81 # undef crypto_secretstream_xchacha20poly1305_ABYTES
82 #endif
83 
84 #ifndef crypto_pwhash_OPSLIMIT_MIN
85 # define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_OPSLIMIT_INTERACTIVE
86 #endif
87 #ifndef crypto_pwhash_MEMLIMIT_MIN
88 # define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_MEMLIMIT_INTERACTIVE
89 #endif
90 #ifndef crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN
91 # define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE
92 #endif
93 #ifndef crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN
94 # define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE
95 #endif
96 
97 /* Load after the "standard" module in order to give it
98  * priority in registering argon2i/argon2id password hashers.
99  */
100 static const zend_module_dep sodium_deps[] = {
101 	ZEND_MOD_REQUIRED("standard")
102 	ZEND_MOD_END
103 };
104 
105 zend_module_entry sodium_module_entry = {
106 	STANDARD_MODULE_HEADER_EX,
107 	NULL,
108 	sodium_deps,
109 	"sodium",
110 	ext_functions,
111 	PHP_MINIT(sodium),
112 	PHP_MSHUTDOWN(sodium),
113 	NULL,
114 	NULL,
115 	PHP_MINFO(sodium),
116 	PHP_SODIUM_VERSION,
117 	STANDARD_MODULE_PROPERTIES
118 };
119 /* }}} */
120 
121 #ifdef COMPILE_DL_SODIUM
ZEND_GET_MODULE(sodium)122 ZEND_GET_MODULE(sodium)
123 #endif
124 
125 /* Remove argument information from backtrace to prevent information leaks */
126 static void sodium_remove_param_values_from_backtrace(zend_object *obj) {
127 	zval rv;
128 	zval *trace = zend_read_property_ex(zend_get_exception_base(obj), obj, ZSTR_KNOWN(ZEND_STR_TRACE), /* silent */ false, &rv);
129 	if (trace && Z_TYPE_P(trace) == IS_ARRAY) {
130 		zval *frame;
131 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(trace), frame) {
132 			if (Z_TYPE_P(frame) == IS_ARRAY) {
133 				zval *args = zend_hash_find(Z_ARRVAL_P(frame), ZSTR_KNOWN(ZEND_STR_ARGS));
134 				if (args) {
135 					zval_ptr_dtor(args);
136 					ZVAL_EMPTY_ARRAY(args);
137 				}
138 			}
139 		} ZEND_HASH_FOREACH_END();
140 	}
141 }
142 
sodium_exception_create_object(zend_class_entry * ce)143 static zend_object *sodium_exception_create_object(zend_class_entry *ce) {
144 	zend_object *obj = zend_ce_exception->create_object(ce);
145 	sodium_remove_param_values_from_backtrace(obj);
146 	return obj;
147 }
148 
sodium_separate_string(zval * zv)149 static void sodium_separate_string(zval *zv) {
150 	ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
151 	if (!Z_REFCOUNTED_P(zv) || Z_REFCOUNT_P(zv) > 1) {
152 		zend_string *copy = zend_string_init(Z_STRVAL_P(zv), Z_STRLEN_P(zv), 0);
153 		Z_TRY_DELREF_P(zv);
154 		ZVAL_STR(zv, copy);
155 	}
156 }
157 
PHP_MINIT_FUNCTION(sodium)158 PHP_MINIT_FUNCTION(sodium)
159 {
160 	if (sodium_init() < 0) {
161 		zend_error_noreturn(E_ERROR, "sodium_init()");
162 	}
163 
164 	sodium_exception_ce = register_class_SodiumException(zend_ce_exception);
165 	sodium_exception_ce->create_object = sodium_exception_create_object;
166 
167 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
168 	if (FAILURE == PHP_MINIT(sodium_password_hash)(INIT_FUNC_ARGS_PASSTHRU)) {
169 		return FAILURE;
170 	}
171 #endif
172 
173 	register_libsodium_symbols(module_number);
174 
175 	return SUCCESS;
176 }
177 
PHP_MSHUTDOWN_FUNCTION(sodium)178 PHP_MSHUTDOWN_FUNCTION(sodium)
179 {
180 	randombytes_close();
181 	return SUCCESS;
182 }
183 
PHP_MINFO_FUNCTION(sodium)184 PHP_MINFO_FUNCTION(sodium)
185 {
186 	php_info_print_table_start();
187 	php_info_print_table_row(2, "sodium support", "enabled");
188 	php_info_print_table_row(2, "libsodium headers version", SODIUM_VERSION_STRING);
189 	php_info_print_table_row(2, "libsodium library version", sodium_version_string());
190 	php_info_print_table_end();
191 }
192 
PHP_FUNCTION(sodium_memzero)193 PHP_FUNCTION(sodium_memzero)
194 {
195 	zval      *buf_zv;
196 
197 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
198 									"z", &buf_zv) == FAILURE) {
199 		sodium_remove_param_values_from_backtrace(EG(exception));
200 		RETURN_THROWS();
201 	}
202 	ZVAL_DEREF(buf_zv);
203 	if (Z_TYPE_P(buf_zv) != IS_STRING) {
204 		zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0);
205 		RETURN_THROWS();
206 	}
207 	if (Z_REFCOUNTED_P(buf_zv) && Z_REFCOUNT_P(buf_zv) == 1) {
208 		char *buf = Z_STRVAL(*buf_zv);
209 		size_t buf_len = Z_STRLEN(*buf_zv);
210 		if (buf_len > 0) {
211 			sodium_memzero(buf, (size_t) buf_len);
212 		}
213 	}
214 	convert_to_null(buf_zv);
215 }
216 
PHP_FUNCTION(sodium_increment)217 PHP_FUNCTION(sodium_increment)
218 {
219 	zval          *val_zv;
220 	unsigned char *val;
221 	size_t         val_len;
222 
223 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
224 									"z", &val_zv) == FAILURE) {
225 		sodium_remove_param_values_from_backtrace(EG(exception));
226 		RETURN_THROWS();
227 	}
228 	ZVAL_DEREF(val_zv);
229 	if (Z_TYPE_P(val_zv) != IS_STRING) {
230 		zend_throw_exception(sodium_exception_ce, "a PHP string is required", 0);
231 		RETURN_THROWS();
232 	}
233 
234 	sodium_separate_string(val_zv);
235 	val = (unsigned char *) Z_STRVAL(*val_zv);
236 	val_len = Z_STRLEN(*val_zv);
237 	sodium_increment(val, val_len);
238 }
239 
PHP_FUNCTION(sodium_add)240 PHP_FUNCTION(sodium_add)
241 {
242 	zval          *val_zv;
243 	unsigned char *val;
244 	unsigned char *addv;
245 	size_t         val_len;
246 	size_t         addv_len;
247 
248 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
249 									"zs", &val_zv, &addv, &addv_len) == FAILURE) {
250 		sodium_remove_param_values_from_backtrace(EG(exception));
251 		RETURN_THROWS();
252 	}
253 	ZVAL_DEREF(val_zv);
254 	if (Z_TYPE_P(val_zv) != IS_STRING) {
255 		zend_throw_exception(sodium_exception_ce, "PHP strings are required", 0);
256 		RETURN_THROWS();
257 	}
258 
259 	sodium_separate_string(val_zv);
260 	val = (unsigned char *) Z_STRVAL(*val_zv);
261 	val_len = Z_STRLEN(*val_zv);
262 	if (val_len != addv_len) {
263 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
264 		RETURN_THROWS();
265 	}
266 	sodium_add(val, addv, val_len);
267 }
268 
PHP_FUNCTION(sodium_memcmp)269 PHP_FUNCTION(sodium_memcmp)
270 {
271 	char      *buf1;
272 	char      *buf2;
273 	size_t     len1;
274 	size_t     len2;
275 
276 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
277 									&buf1, &len1,
278 									&buf2, &len2) == FAILURE) {
279 		sodium_remove_param_values_from_backtrace(EG(exception));
280 		RETURN_THROWS();
281 	}
282 	if (len1 != len2) {
283 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
284 		RETURN_THROWS();
285 	}
286 	RETURN_LONG(sodium_memcmp(buf1, buf2, len1));
287 }
288 
PHP_FUNCTION(sodium_crypto_shorthash)289 PHP_FUNCTION(sodium_crypto_shorthash)
290 {
291 	zend_string   *hash;
292 	unsigned char *key;
293 	unsigned char *msg;
294 	size_t         key_len;
295 	size_t         msg_len;
296 
297 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
298 									&msg, &msg_len,
299 									&key, &key_len) == FAILURE) {
300 		sodium_remove_param_values_from_backtrace(EG(exception));
301 		RETURN_THROWS();
302 	}
303 	if (key_len != crypto_shorthash_KEYBYTES) {
304 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SHORTHASH_KEYBYTES bytes long");
305 		RETURN_THROWS();
306 	}
307 	hash = zend_string_alloc(crypto_shorthash_BYTES, 0);
308 	if (crypto_shorthash((unsigned char *) ZSTR_VAL(hash), msg,
309 						 (unsigned long long) msg_len, key) != 0) {
310 		zend_string_efree(hash);
311 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
312 		RETURN_THROWS();
313 	}
314 	ZSTR_VAL(hash)[crypto_shorthash_BYTES] = 0;
315 
316 	RETURN_NEW_STR(hash);
317 }
318 
PHP_FUNCTION(sodium_crypto_secretbox)319 PHP_FUNCTION(sodium_crypto_secretbox)
320 {
321 	zend_string   *ciphertext;
322 	unsigned char *key;
323 	unsigned char *msg;
324 	unsigned char *nonce;
325 	size_t         key_len;
326 	size_t         msg_len;
327 	size_t         nonce_len;
328 
329 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
330 									&msg, &msg_len,
331 									&nonce, &nonce_len,
332 									&key, &key_len) == FAILURE) {
333 		sodium_remove_param_values_from_backtrace(EG(exception));
334 		RETURN_THROWS();
335 	}
336 	if (nonce_len != crypto_secretbox_NONCEBYTES) {
337 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETBOX_NONCEBYTES bytes long");
338 		RETURN_THROWS();
339 	}
340 	if (key_len != crypto_secretbox_KEYBYTES) {
341 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long");
342 		RETURN_THROWS();
343 	}
344 	if (SIZE_MAX - msg_len <= crypto_secretbox_MACBYTES) {
345 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
346 		RETURN_THROWS();
347 	}
348 	ciphertext = zend_string_alloc((size_t) msg_len + crypto_secretbox_MACBYTES, 0);
349 	if (crypto_secretbox_easy((unsigned char *) ZSTR_VAL(ciphertext),
350 							  msg, (unsigned long long) msg_len,
351 							  nonce, key) != 0) {
352 		zend_string_efree(ciphertext);
353 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
354 		RETURN_THROWS();
355 	}
356 	ZSTR_VAL(ciphertext)[msg_len + crypto_secretbox_MACBYTES] = 0;
357 
358 	RETURN_NEW_STR(ciphertext);
359 }
360 
PHP_FUNCTION(sodium_crypto_secretbox_open)361 PHP_FUNCTION(sodium_crypto_secretbox_open)
362 {
363 	zend_string   *msg;
364 	unsigned char *key;
365 	unsigned char *ciphertext;
366 	unsigned char *nonce;
367 	size_t         key_len;
368 	size_t         ciphertext_len;
369 	size_t         nonce_len;
370 
371 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
372 									&ciphertext, &ciphertext_len,
373 									&nonce, &nonce_len,
374 									&key, &key_len) == FAILURE) {
375 		sodium_remove_param_values_from_backtrace(EG(exception));
376 		RETURN_THROWS();
377 	}
378 	if (nonce_len != crypto_secretbox_NONCEBYTES) {
379 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETBOX_NONCEBYTES bytes long");
380 		RETURN_THROWS();
381 	}
382 	if (key_len != crypto_secretbox_KEYBYTES) {
383 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long");
384 		RETURN_THROWS();
385 	}
386 	if (ciphertext_len < crypto_secretbox_MACBYTES) {
387 		RETURN_FALSE;
388 	}
389 	msg = zend_string_alloc
390 		((size_t) ciphertext_len - crypto_secretbox_MACBYTES, 0);
391 	if (crypto_secretbox_open_easy((unsigned char *) ZSTR_VAL(msg), ciphertext,
392 								   (unsigned long long) ciphertext_len,
393 								   nonce, key) != 0) {
394 		zend_string_efree(msg);
395 		RETURN_FALSE;
396 	} else {
397 		ZSTR_VAL(msg)[ciphertext_len - crypto_secretbox_MACBYTES] = 0;
398 		RETURN_NEW_STR(msg);
399 	}
400 }
401 
PHP_FUNCTION(sodium_crypto_generichash)402 PHP_FUNCTION(sodium_crypto_generichash)
403 {
404 	zend_string   *hash;
405 	unsigned char *key = NULL;
406 	unsigned char *msg;
407 	zend_long      hash_len = crypto_generichash_BYTES;
408 	size_t         key_len = 0;
409 	size_t         msg_len;
410 
411 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sl",
412 									&msg, &msg_len,
413 									&key, &key_len,
414 									&hash_len) == FAILURE) {
415 		sodium_remove_param_values_from_backtrace(EG(exception));
416 		RETURN_THROWS();
417 	}
418 	if (hash_len < crypto_generichash_BYTES_MIN ||
419 		hash_len > crypto_generichash_BYTES_MAX) {
420 		zend_throw_exception(sodium_exception_ce, "unsupported output length", 0);
421 		RETURN_THROWS();
422 	}
423 	if (key_len != 0 &&
424 		(key_len < crypto_generichash_KEYBYTES_MIN ||
425 		 key_len > crypto_generichash_KEYBYTES_MAX)) {
426 		zend_throw_exception(sodium_exception_ce, "unsupported key length", 0);
427 		RETURN_THROWS();
428 	}
429 	hash = zend_string_alloc(hash_len, 0);
430 	if (crypto_generichash((unsigned char *) ZSTR_VAL(hash), (size_t) hash_len,
431 						   msg, (unsigned long long) msg_len,
432 						   key, (size_t) key_len) != 0) {
433 		zend_string_efree(hash);
434 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
435 		RETURN_THROWS();
436 	}
437 	ZSTR_VAL(hash)[hash_len] = 0;
438 
439 	RETURN_NEW_STR(hash);
440 }
441 
PHP_FUNCTION(sodium_crypto_generichash_init)442 PHP_FUNCTION(sodium_crypto_generichash_init)
443 {
444 	crypto_generichash_state  state_tmp;
445 	zend_string              *state;
446 	unsigned char            *key = NULL;
447 	size_t                    state_len = sizeof (crypto_generichash_state);
448 	zend_long                 hash_len = crypto_generichash_BYTES;
449 	size_t                    key_len = 0;
450 
451 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sl",
452 									&key, &key_len,
453 									&hash_len) == FAILURE) {
454 		sodium_remove_param_values_from_backtrace(EG(exception));
455 		RETURN_THROWS();
456 	}
457 	if (hash_len < crypto_generichash_BYTES_MIN ||
458 		hash_len > crypto_generichash_BYTES_MAX) {
459 		zend_throw_exception(sodium_exception_ce, "unsupported output length", 0);
460 		RETURN_THROWS();
461 	}
462 	if (key_len != 0 &&
463 		(key_len < crypto_generichash_KEYBYTES_MIN ||
464 		 key_len > crypto_generichash_KEYBYTES_MAX)) {
465 		zend_throw_exception(sodium_exception_ce, "unsupported key length", 0);
466 		RETURN_THROWS();
467 	}
468 	memset(&state_tmp, 0, sizeof state_tmp);
469 	if (crypto_generichash_init((void *) &state_tmp, key, (size_t) key_len,
470 								(size_t) hash_len) != 0) {
471 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
472 		RETURN_THROWS();
473 	}
474 	state = zend_string_alloc(state_len, 0);
475 	memcpy(ZSTR_VAL(state), &state_tmp, state_len);
476 	sodium_memzero(&state_tmp, sizeof state_tmp);
477 	ZSTR_VAL(state)[state_len] = 0;
478 
479 	RETURN_STR(state);
480 }
481 
PHP_FUNCTION(sodium_crypto_generichash_update)482 PHP_FUNCTION(sodium_crypto_generichash_update)
483 {
484 	crypto_generichash_state  state_tmp;
485 	zval                     *state_zv;
486 	unsigned char            *msg;
487 	unsigned char            *state;
488 	size_t                    msg_len;
489 	size_t                    state_len;
490 
491 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs",
492 									&state_zv, &msg, &msg_len) == FAILURE) {
493 		sodium_remove_param_values_from_backtrace(EG(exception));
494 		RETURN_THROWS();
495 	}
496 	ZVAL_DEREF(state_zv);
497 	if (Z_TYPE_P(state_zv) != IS_STRING) {
498 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
499 		RETURN_THROWS();
500 	}
501 	sodium_separate_string(state_zv);
502 	state = (unsigned char *) Z_STRVAL(*state_zv);
503 	state_len = Z_STRLEN(*state_zv);
504 	if (state_len != sizeof (crypto_generichash_state)) {
505 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
506 		RETURN_THROWS();
507 	}
508 	memcpy(&state_tmp, state, sizeof state_tmp);
509 	if (crypto_generichash_update((void *) &state_tmp, msg,
510 								  (unsigned long long) msg_len) != 0) {
511 		sodium_memzero(&state_tmp, sizeof state_tmp);
512 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
513 		RETURN_THROWS();
514 	}
515 	memcpy(state, &state_tmp, state_len);
516 	sodium_memzero(&state_tmp, sizeof state_tmp);
517 
518 	RETURN_TRUE;
519 }
520 
PHP_FUNCTION(sodium_crypto_generichash_final)521 PHP_FUNCTION(sodium_crypto_generichash_final)
522 {
523 	crypto_generichash_state  state_tmp;
524 	zend_string              *hash;
525 	zval                     *state_zv;
526 	unsigned char            *state;
527 	size_t                    state_len;
528 	zend_long                 hash_len = crypto_generichash_BYTES;
529 
530 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l",
531 									&state_zv, &hash_len) == FAILURE) {
532 		sodium_remove_param_values_from_backtrace(EG(exception));
533 		RETURN_THROWS();
534 	}
535 	ZVAL_DEREF(state_zv);
536 	if (Z_TYPE_P(state_zv) != IS_STRING) {
537 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
538 		RETURN_THROWS();
539 	}
540 	sodium_separate_string(state_zv);
541 	state = (unsigned char *) Z_STRVAL(*state_zv);
542 	state_len = Z_STRLEN(*state_zv);
543 	if (state_len != sizeof (crypto_generichash_state)) {
544 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
545 		RETURN_THROWS();
546 	}
547 	if (hash_len < crypto_generichash_BYTES_MIN ||
548 		hash_len > crypto_generichash_BYTES_MAX) {
549 		zend_throw_exception(sodium_exception_ce, "unsupported output length", 0);
550 		RETURN_THROWS();
551 	}
552 	hash = zend_string_alloc(hash_len, 0);
553 	memcpy(&state_tmp, state, sizeof state_tmp);
554 	if (crypto_generichash_final((void *) &state_tmp,
555 								 (unsigned char *) ZSTR_VAL(hash),
556 								 (size_t) hash_len) != 0) {
557 		sodium_memzero(&state_tmp, sizeof state_tmp);
558 		zend_string_efree(hash);
559 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
560 		RETURN_THROWS();
561 	}
562 	sodium_memzero(&state_tmp, sizeof state_tmp);
563 	sodium_memzero(state, state_len);
564 	convert_to_null(state_zv);
565 	ZSTR_VAL(hash)[hash_len] = 0;
566 
567 	RETURN_NEW_STR(hash);
568 }
569 
PHP_FUNCTION(sodium_crypto_box_keypair)570 PHP_FUNCTION(sodium_crypto_box_keypair)
571 {
572 	zend_string *keypair;
573 	size_t       keypair_len;
574 
575 	if (zend_parse_parameters_none() == FAILURE) {
576 		RETURN_THROWS();
577 	}
578 	keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES;
579 	keypair = zend_string_alloc(keypair_len, 0);
580 	if (crypto_box_keypair((unsigned char *) ZSTR_VAL(keypair) +
581 						   crypto_box_SECRETKEYBYTES,
582 						   (unsigned char *) ZSTR_VAL(keypair)) != 0) {
583 		zend_string_efree(keypair);
584 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
585 		RETURN_THROWS();
586 	}
587 	ZSTR_VAL(keypair)[keypair_len] = 0;
588 
589 	RETURN_NEW_STR(keypair);
590 }
591 
PHP_FUNCTION(sodium_crypto_box_seed_keypair)592 PHP_FUNCTION(sodium_crypto_box_seed_keypair)
593 {
594 	zend_string   *keypair;
595 	unsigned char *seed;
596 	size_t         keypair_len;
597 	size_t         seed_len;
598 
599 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
600 									&seed, &seed_len) == FAILURE) {
601 		sodium_remove_param_values_from_backtrace(EG(exception));
602 		RETURN_THROWS();
603 	}
604 	if (seed_len != crypto_box_SEEDBYTES) {
605 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_SEEDBYTES bytes long");
606 		RETURN_THROWS();
607 	}
608 	keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES;
609 	keypair = zend_string_alloc(keypair_len, 0);
610 	if (crypto_box_seed_keypair((unsigned char *) ZSTR_VAL(keypair) +
611 								 crypto_box_SECRETKEYBYTES,
612 								 (unsigned char *) ZSTR_VAL(keypair),
613 								 seed) != 0) {
614 		zend_string_efree(keypair);
615 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
616 		RETURN_THROWS();
617 	}
618 	ZSTR_VAL(keypair)[keypair_len] = 0;
619 
620 	RETURN_NEW_STR(keypair);
621 }
622 
PHP_FUNCTION(sodium_crypto_box_keypair_from_secretkey_and_publickey)623 PHP_FUNCTION(sodium_crypto_box_keypair_from_secretkey_and_publickey)
624 {
625 	zend_string *keypair;
626 	char        *publickey;
627 	char        *secretkey;
628 	size_t       keypair_len;
629 	size_t       publickey_len;
630 	size_t       secretkey_len;
631 
632 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
633 									&secretkey, &secretkey_len,
634 									&publickey, &publickey_len) == FAILURE) {
635 		sodium_remove_param_values_from_backtrace(EG(exception));
636 		RETURN_THROWS();
637 	}
638 	if (secretkey_len != crypto_box_SECRETKEYBYTES) {
639 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_SECRETKEYBYTES bytes long");
640 		RETURN_THROWS();
641 	}
642 	if (publickey_len != crypto_box_PUBLICKEYBYTES) {
643 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_PUBLICKEYBYTES bytes long");
644 		RETURN_THROWS();
645 	}
646 	keypair_len = crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES;
647 	keypair = zend_string_alloc(keypair_len, 0);
648 	memcpy(ZSTR_VAL(keypair), secretkey, crypto_box_SECRETKEYBYTES);
649 	memcpy(ZSTR_VAL(keypair) + crypto_box_SECRETKEYBYTES, publickey,
650 		   crypto_box_PUBLICKEYBYTES);
651 	ZSTR_VAL(keypair)[keypair_len] = 0;
652 
653 	RETURN_STR(keypair);
654 }
655 
PHP_FUNCTION(sodium_crypto_box_secretkey)656 PHP_FUNCTION(sodium_crypto_box_secretkey)
657 {
658 	zend_string   *secretkey;
659 	unsigned char *keypair;
660 	size_t         keypair_len;
661 
662 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
663 									&keypair, &keypair_len) == FAILURE) {
664 		sodium_remove_param_values_from_backtrace(EG(exception));
665 		RETURN_THROWS();
666 	}
667 	if (keypair_len !=
668 		crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
669 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
670 		RETURN_THROWS();
671 	}
672 	secretkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0);
673 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_box_SECRETKEYBYTES);
674 	ZSTR_VAL(secretkey)[crypto_box_SECRETKEYBYTES] = 0;
675 
676 	RETURN_STR(secretkey);
677 }
678 
PHP_FUNCTION(sodium_crypto_box_publickey)679 PHP_FUNCTION(sodium_crypto_box_publickey)
680 {
681 	zend_string   *publickey;
682 	unsigned char *keypair;
683 	size_t         keypair_len;
684 
685 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
686 									&keypair, &keypair_len) == FAILURE) {
687 		sodium_remove_param_values_from_backtrace(EG(exception));
688 		RETURN_THROWS();
689 	}
690 	if (keypair_len !=
691 		crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
692 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
693 		RETURN_THROWS();
694 	}
695 	publickey = zend_string_alloc(crypto_box_PUBLICKEYBYTES, 0);
696 	memcpy(ZSTR_VAL(publickey), keypair + crypto_box_SECRETKEYBYTES,
697 		   crypto_box_PUBLICKEYBYTES);
698 	ZSTR_VAL(publickey)[crypto_box_PUBLICKEYBYTES] = 0;
699 
700 	RETURN_STR(publickey);
701 }
702 
PHP_FUNCTION(sodium_crypto_box_publickey_from_secretkey)703 PHP_FUNCTION(sodium_crypto_box_publickey_from_secretkey)
704 {
705 	zend_string   *publickey;
706 	unsigned char *secretkey;
707 	size_t         secretkey_len;
708 
709 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
710 									&secretkey, &secretkey_len) == FAILURE) {
711 		sodium_remove_param_values_from_backtrace(EG(exception));
712 		RETURN_THROWS();
713 	}
714 	if (secretkey_len != crypto_box_SECRETKEYBYTES) {
715 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_BOX_SECRETKEYBYTES bytes long");
716 		RETURN_THROWS();
717 	}
718 	publickey = zend_string_alloc(crypto_box_PUBLICKEYBYTES, 0);
719 	(void) sizeof(int[crypto_scalarmult_BYTES ==
720 					  crypto_box_PUBLICKEYBYTES ? 1 : -1]);
721 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES ==
722 					  crypto_box_SECRETKEYBYTES ? 1 : -1]);
723 	crypto_scalarmult_base((unsigned char *) ZSTR_VAL(publickey), secretkey);
724 	ZSTR_VAL(publickey)[crypto_box_PUBLICKEYBYTES] = 0;
725 
726 	RETURN_STR(publickey);
727 }
728 
PHP_FUNCTION(sodium_crypto_box)729 PHP_FUNCTION(sodium_crypto_box)
730 {
731 	zend_string   *ciphertext;
732 	unsigned char *keypair;
733 	unsigned char *msg;
734 	unsigned char *nonce;
735 	unsigned char *publickey;
736 	unsigned char *secretkey;
737 	size_t         keypair_len;
738 	size_t         msg_len;
739 	size_t         nonce_len;
740 
741 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
742 									&msg, &msg_len,
743 									&nonce, &nonce_len,
744 									&keypair, &keypair_len) == FAILURE) {
745 		sodium_remove_param_values_from_backtrace(EG(exception));
746 		RETURN_THROWS();
747 	}
748 	if (nonce_len != crypto_box_NONCEBYTES) {
749 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_NONCEBYTES bytes long");
750 		RETURN_THROWS();
751 	}
752 	if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
753 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
754 		RETURN_THROWS();
755 	}
756 	secretkey = keypair;
757 	publickey = keypair + crypto_box_SECRETKEYBYTES;
758 	if (SIZE_MAX - msg_len <= crypto_box_MACBYTES) {
759 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
760 		RETURN_THROWS();
761 	}
762 	ciphertext = zend_string_alloc((size_t) msg_len + crypto_box_MACBYTES, 0);
763 	if (crypto_box_easy((unsigned char *) ZSTR_VAL(ciphertext), msg,
764 						(unsigned long long) msg_len,
765 						nonce, publickey, secretkey) != 0) {
766 		zend_string_efree(ciphertext);
767 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
768 		RETURN_THROWS();
769 	}
770 	ZSTR_VAL(ciphertext)[msg_len + crypto_box_MACBYTES] = 0;
771 
772 	RETURN_NEW_STR(ciphertext);
773 }
774 
PHP_FUNCTION(sodium_crypto_box_open)775 PHP_FUNCTION(sodium_crypto_box_open)
776 {
777 	zend_string   *msg;
778 	unsigned char *ciphertext;
779 	unsigned char *keypair;
780 	unsigned char *nonce;
781 	unsigned char *publickey;
782 	unsigned char *secretkey;
783 	size_t         ciphertext_len;
784 	size_t         keypair_len;
785 	size_t         nonce_len;
786 
787 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
788 									&ciphertext, &ciphertext_len,
789 									&nonce, &nonce_len,
790 									&keypair, &keypair_len) == FAILURE) {
791 		sodium_remove_param_values_from_backtrace(EG(exception));
792 		RETURN_THROWS();
793 	}
794 	if (nonce_len != crypto_box_NONCEBYTES) {
795 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_NONCEBYTES bytes long");
796 		RETURN_THROWS();
797 	}
798 	if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
799 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
800 		RETURN_THROWS();
801 	}
802 	secretkey = keypair;
803 	publickey = keypair + crypto_box_SECRETKEYBYTES;
804 	if (ciphertext_len < crypto_box_MACBYTES) {
805 		RETURN_FALSE;
806 	}
807 	msg = zend_string_alloc((size_t) ciphertext_len - crypto_box_MACBYTES, 0);
808 	if (crypto_box_open_easy((unsigned char *) ZSTR_VAL(msg), ciphertext,
809 							 (unsigned long long) ciphertext_len,
810 							 nonce, publickey, secretkey) != 0) {
811 		zend_string_efree(msg);
812 		RETURN_FALSE;
813 	} else {
814 		ZSTR_VAL(msg)[ciphertext_len - crypto_box_MACBYTES] = 0;
815 		RETURN_NEW_STR(msg);
816 	}
817 }
818 
PHP_FUNCTION(sodium_crypto_box_seal)819 PHP_FUNCTION(sodium_crypto_box_seal)
820 {
821 	zend_string   *ciphertext;
822 	unsigned char *msg;
823 	unsigned char *publickey;
824 	size_t         msg_len;
825 	size_t         publickey_len;
826 
827 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
828 									&msg, &msg_len,
829 									&publickey, &publickey_len) == FAILURE) {
830 		sodium_remove_param_values_from_backtrace(EG(exception));
831 		RETURN_THROWS();
832 	}
833 	if (publickey_len != crypto_box_PUBLICKEYBYTES) {
834 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_PUBLICKEYBYTES bytes long");
835 		RETURN_THROWS();
836 	}
837 	if (SIZE_MAX - msg_len <= crypto_box_SEALBYTES) {
838 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
839 		RETURN_THROWS();
840 	}
841 	ciphertext = zend_string_alloc((size_t) msg_len + crypto_box_SEALBYTES, 0);
842 	if (crypto_box_seal((unsigned char *) ZSTR_VAL(ciphertext), msg,
843 						(unsigned long long) msg_len, publickey) != 0) {
844 		zend_string_efree(ciphertext);
845 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
846 		RETURN_THROWS();
847 	}
848 	ZSTR_VAL(ciphertext)[msg_len + crypto_box_SEALBYTES] = 0;
849 
850 	RETURN_NEW_STR(ciphertext);
851 }
852 
PHP_FUNCTION(sodium_crypto_box_seal_open)853 PHP_FUNCTION(sodium_crypto_box_seal_open)
854 {
855 	zend_string   *msg;
856 	unsigned char *ciphertext;
857 	unsigned char *keypair;
858 	unsigned char *publickey;
859 	unsigned char *secretkey;
860 	size_t         ciphertext_len;
861 	size_t         keypair_len;
862 
863 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
864 									&ciphertext, &ciphertext_len,
865 									&keypair, &keypair_len) == FAILURE) {
866 		sodium_remove_param_values_from_backtrace(EG(exception));
867 		RETURN_THROWS();
868 	}
869 	if (keypair_len != crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES) {
870 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_BOX_KEYPAIRBYTES bytes long");
871 		RETURN_THROWS();
872 	}
873 	secretkey = keypair;
874 	publickey = keypair + crypto_box_SECRETKEYBYTES;
875 	if (ciphertext_len < crypto_box_SEALBYTES) {
876 		RETURN_FALSE;
877 	}
878 	msg = zend_string_alloc((size_t) ciphertext_len - crypto_box_SEALBYTES, 0);
879 	if (crypto_box_seal_open((unsigned char *) ZSTR_VAL(msg), ciphertext,
880 							 (unsigned long long) ciphertext_len,
881 							 publickey, secretkey) != 0) {
882 		zend_string_efree(msg);
883 		RETURN_FALSE;
884 	} else {
885 		ZSTR_VAL(msg)[ciphertext_len - crypto_box_SEALBYTES] = 0;
886 		RETURN_NEW_STR(msg);
887 	}
888 }
889 
PHP_FUNCTION(sodium_crypto_sign_keypair)890 PHP_FUNCTION(sodium_crypto_sign_keypair)
891 {
892 	zend_string *keypair;
893 	size_t       keypair_len;
894 
895 	if (zend_parse_parameters_none() == FAILURE) {
896 		RETURN_THROWS();
897 	}
898 	keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES;
899 	keypair = zend_string_alloc(keypair_len, 0);
900 	if (crypto_sign_keypair((unsigned char *) ZSTR_VAL(keypair) +
901 							crypto_sign_SECRETKEYBYTES,
902 							(unsigned char *) ZSTR_VAL(keypair)) != 0) {
903 		zend_string_efree(keypair);
904 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
905 		RETURN_THROWS();
906 	}
907 	ZSTR_VAL(keypair)[keypair_len] = 0;
908 
909 	RETURN_NEW_STR(keypair);
910 }
911 
PHP_FUNCTION(sodium_crypto_sign_seed_keypair)912 PHP_FUNCTION(sodium_crypto_sign_seed_keypair)
913 {
914 	zend_string   *keypair;
915 	unsigned char *seed;
916 	size_t         keypair_len;
917 	size_t         seed_len;
918 
919 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
920 									&seed, &seed_len) == FAILURE) {
921 		sodium_remove_param_values_from_backtrace(EG(exception));
922 		RETURN_THROWS();
923 	}
924 	if (seed_len != crypto_sign_SEEDBYTES) {
925 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SEEDBYTES bytes long");
926 		RETURN_THROWS();
927 	}
928 	keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES;
929 	keypair = zend_string_alloc(keypair_len, 0);
930 	if (crypto_sign_seed_keypair((unsigned char *) ZSTR_VAL(keypair) +
931 								 crypto_sign_SECRETKEYBYTES,
932 								 (unsigned char *) ZSTR_VAL(keypair),
933 								 seed) != 0) {
934 		zend_string_efree(keypair);
935 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
936 		RETURN_THROWS();
937 	}
938 	ZSTR_VAL(keypair)[keypair_len] = 0;
939 
940 	RETURN_NEW_STR(keypair);
941 }
942 
PHP_FUNCTION(sodium_crypto_sign_keypair_from_secretkey_and_publickey)943 PHP_FUNCTION(sodium_crypto_sign_keypair_from_secretkey_and_publickey)
944 {
945 	zend_string *keypair;
946 	char        *publickey;
947 	char        *secretkey;
948 	size_t       keypair_len;
949 	size_t       publickey_len;
950 	size_t       secretkey_len;
951 
952 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
953 									&secretkey, &secretkey_len,
954 									&publickey, &publickey_len) == FAILURE) {
955 		sodium_remove_param_values_from_backtrace(EG(exception));
956 		RETURN_THROWS();
957 	}
958 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
959 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
960 		RETURN_THROWS();
961 	}
962 	if (publickey_len != crypto_sign_PUBLICKEYBYTES) {
963 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
964 		RETURN_THROWS();
965 	}
966 	keypair_len = crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES;
967 	keypair = zend_string_alloc(keypair_len, 0);
968 	memcpy(ZSTR_VAL(keypair), secretkey, crypto_sign_SECRETKEYBYTES);
969 	memcpy(ZSTR_VAL(keypair) + crypto_sign_SECRETKEYBYTES, publickey,
970 		   crypto_sign_PUBLICKEYBYTES);
971 	ZSTR_VAL(keypair)[keypair_len] = 0;
972 
973 	RETURN_STR(keypair);
974 }
975 
PHP_FUNCTION(sodium_crypto_sign_publickey_from_secretkey)976 PHP_FUNCTION(sodium_crypto_sign_publickey_from_secretkey)
977 {
978 	zend_string *publickey;
979 	char        *secretkey;
980 	size_t       secretkey_len;
981 
982 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
983 									&secretkey, &secretkey_len) == FAILURE) {
984 		sodium_remove_param_values_from_backtrace(EG(exception));
985 		RETURN_THROWS();
986 	}
987 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
988 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
989 		RETURN_THROWS();
990 	}
991 	publickey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
992 
993 	if (crypto_sign_ed25519_sk_to_pk((unsigned char *) ZSTR_VAL(publickey),
994 									 (const unsigned char *) secretkey) != 0) {
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_throw_exception(sodium_exception_ce, "internal error", 0);
2709 		RETURN_THROWS();
2710 	}
2711 	ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0;
2712 	RETURN_STR(keypair);
2713 }
2714 
PHP_FUNCTION(sodium_crypto_kx_keypair)2715 PHP_FUNCTION(sodium_crypto_kx_keypair)
2716 {
2717 	unsigned char *sk;
2718 	unsigned char *pk;
2719 	zend_string   *keypair;
2720 
2721 	if (zend_parse_parameters_none() == FAILURE) {
2722 		RETURN_THROWS();
2723 	}
2724 	keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0);
2725 	sk = (unsigned char *) ZSTR_VAL(keypair);
2726 	pk = sk + crypto_kx_SECRETKEYBYTES;
2727 	randombytes_buf(sk, crypto_kx_SECRETKEYBYTES);
2728 	if (crypto_scalarmult_base(pk, sk) != 0) {
2729 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2730 		RETURN_THROWS();
2731 	}
2732 	ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0;
2733 	RETURN_STR(keypair);
2734 }
2735 
PHP_FUNCTION(sodium_crypto_kx_secretkey)2736 PHP_FUNCTION(sodium_crypto_kx_secretkey)
2737 {
2738 	zend_string   *secretkey;
2739 	unsigned char *keypair;
2740 	size_t         keypair_len;
2741 
2742 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2743 									&keypair, &keypair_len) == FAILURE) {
2744 		sodium_remove_param_values_from_backtrace(EG(exception));
2745 		RETURN_THROWS();
2746 	}
2747 	if (keypair_len !=
2748 		crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2749 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2750 		RETURN_THROWS();
2751 	}
2752 	secretkey = zend_string_alloc(crypto_kx_SECRETKEYBYTES, 0);
2753 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_kx_SECRETKEYBYTES);
2754 	ZSTR_VAL(secretkey)[crypto_kx_SECRETKEYBYTES] = 0;
2755 
2756 	RETURN_STR(secretkey);
2757 }
2758 
PHP_FUNCTION(sodium_crypto_kx_publickey)2759 PHP_FUNCTION(sodium_crypto_kx_publickey)
2760 {
2761 	zend_string   *publickey;
2762 	unsigned char *keypair;
2763 	size_t         keypair_len;
2764 
2765 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2766 									&keypair, &keypair_len) == FAILURE) {
2767 		sodium_remove_param_values_from_backtrace(EG(exception));
2768 		RETURN_THROWS();
2769 	}
2770 	if (keypair_len !=
2771 		crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2772 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2773 		RETURN_THROWS();
2774 	}
2775 	publickey = zend_string_alloc(crypto_kx_PUBLICKEYBYTES, 0);
2776 	memcpy(ZSTR_VAL(publickey), keypair + crypto_kx_SECRETKEYBYTES,
2777 		   crypto_kx_PUBLICKEYBYTES);
2778 	ZSTR_VAL(publickey)[crypto_kx_PUBLICKEYBYTES] = 0;
2779 
2780 	RETURN_STR(publickey);
2781 }
2782 
PHP_FUNCTION(sodium_crypto_kx_client_session_keys)2783 PHP_FUNCTION(sodium_crypto_kx_client_session_keys)
2784 {
2785 	crypto_generichash_state h;
2786 	unsigned char  q[crypto_scalarmult_BYTES];
2787 	unsigned char *keypair;
2788 	unsigned char *client_sk;
2789 	unsigned char *client_pk;
2790 	unsigned char *server_pk;
2791 	unsigned char  session_keys[2 * crypto_kx_SESSIONKEYBYTES];
2792 	size_t         keypair_len;
2793 	size_t         server_pk_len;
2794 
2795 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2796 									&keypair, &keypair_len,
2797 									&server_pk, &server_pk_len) == FAILURE) {
2798 		sodium_remove_param_values_from_backtrace(EG(exception));
2799 		RETURN_THROWS();
2800 	}
2801 	if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2802 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2803 		RETURN_THROWS();
2804 	}
2805 	if (server_pk_len != crypto_kx_PUBLICKEYBYTES) {
2806 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes long");
2807 		RETURN_THROWS();
2808 	}
2809 	client_sk = &keypair[0];
2810 	client_pk = &keypair[crypto_kx_SECRETKEYBYTES];
2811 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2812 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2813 	if (crypto_scalarmult(q, client_sk, server_pk) != 0) {
2814 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2815 		RETURN_THROWS();
2816 	}
2817 	crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES);
2818 	crypto_generichash_update(&h, q, sizeof q);
2819 	sodium_memzero(q, sizeof q);
2820 	crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES);
2821 	crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES);
2822 	crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES);
2823 	sodium_memzero(&h, sizeof h);
2824 	array_init(return_value);
2825 	add_next_index_stringl(return_value,
2826 						   (const char *) session_keys,
2827 						   crypto_kx_SESSIONKEYBYTES);
2828 	add_next_index_stringl(return_value,
2829 						   (const char *) session_keys + crypto_kx_SESSIONKEYBYTES,
2830 						   crypto_kx_SESSIONKEYBYTES);
2831 }
2832 
PHP_FUNCTION(sodium_crypto_kx_server_session_keys)2833 PHP_FUNCTION(sodium_crypto_kx_server_session_keys)
2834 {
2835 	crypto_generichash_state h;
2836 	unsigned char  q[crypto_scalarmult_BYTES];
2837 	unsigned char *keypair;
2838 	unsigned char *server_sk;
2839 	unsigned char *server_pk;
2840 	unsigned char *client_pk;
2841 	unsigned char  session_keys[2 * crypto_kx_SESSIONKEYBYTES];
2842 	size_t         keypair_len;
2843 	size_t         client_pk_len;
2844 
2845 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2846 									&keypair, &keypair_len,
2847 									&client_pk, &client_pk_len) == FAILURE) {
2848 		sodium_remove_param_values_from_backtrace(EG(exception));
2849 		RETURN_THROWS();
2850 	}
2851 	if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2852 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2853 		RETURN_THROWS();
2854 	}
2855 	if (client_pk_len != crypto_kx_PUBLICKEYBYTES) {
2856 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes long");
2857 		RETURN_THROWS();
2858 	}
2859 	server_sk = &keypair[0];
2860 	server_pk = &keypair[crypto_kx_SECRETKEYBYTES];
2861 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2862 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2863 	if (crypto_scalarmult(q, server_sk, client_pk) != 0) {
2864 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2865 		RETURN_THROWS();
2866 	}
2867 	crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES);
2868 	crypto_generichash_update(&h, q, sizeof q);
2869 	sodium_memzero(q, sizeof q);
2870 	crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES);
2871 	crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES);
2872 	crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES);
2873 	sodium_memzero(&h, sizeof h);
2874 	array_init(return_value);
2875 	add_next_index_stringl(return_value,
2876 						   (const char *) session_keys + crypto_kx_SESSIONKEYBYTES,
2877 						   crypto_kx_SESSIONKEYBYTES);
2878 	add_next_index_stringl(return_value,
2879 						   (const char *) session_keys,
2880 						   crypto_kx_SESSIONKEYBYTES);
2881 }
2882 
PHP_FUNCTION(sodium_crypto_auth)2883 PHP_FUNCTION(sodium_crypto_auth)
2884 {
2885 	zend_string *mac;
2886 	char        *key;
2887 	char        *msg;
2888 	size_t       msg_len;
2889 	size_t       key_len;
2890 
2891 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2892 									&msg, &msg_len,
2893 									&key, &key_len) == FAILURE) {
2894 		sodium_remove_param_values_from_backtrace(EG(exception));
2895 		RETURN_THROWS();
2896 	}
2897 	if (key_len != crypto_auth_KEYBYTES) {
2898 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes long");
2899 		RETURN_THROWS();
2900 	}
2901 	mac = zend_string_alloc(crypto_auth_BYTES, 0);
2902 	if (crypto_auth((unsigned char *) ZSTR_VAL(mac),
2903 					(const unsigned char *) msg, msg_len,
2904 					(const unsigned char *) key) != 0) {
2905 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2906 		RETURN_THROWS();
2907 	}
2908 	ZSTR_VAL(mac)[crypto_auth_BYTES] = 0;
2909 
2910 	RETURN_STR(mac);
2911 }
2912 
PHP_FUNCTION(sodium_crypto_auth_verify)2913 PHP_FUNCTION(sodium_crypto_auth_verify)
2914 {
2915 	char      *mac;
2916 	char      *key;
2917 	char      *msg;
2918 	size_t     mac_len;
2919 	size_t     msg_len;
2920 	size_t     key_len;
2921 
2922 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
2923 									&mac, &mac_len,
2924 									&msg, &msg_len,
2925 									&key, &key_len) == FAILURE) {
2926 		sodium_remove_param_values_from_backtrace(EG(exception));
2927 		RETURN_THROWS();
2928 	}
2929 	if (key_len != crypto_auth_KEYBYTES) {
2930 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes long");
2931 		RETURN_THROWS();
2932 	}
2933 	if (mac_len != crypto_auth_BYTES) {
2934 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_AUTH_BYTES bytes long");
2935 		RETURN_THROWS();
2936 	}
2937 	if (crypto_auth_verify((const unsigned char *) mac,
2938 						   (const unsigned char *) msg, msg_len,
2939 						   (const unsigned char *) key) != 0) {
2940 		RETURN_FALSE;
2941 	}
2942 	RETURN_TRUE;
2943 }
2944 
PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)2945 PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)
2946 {
2947 	zend_string *ecdhkey;
2948 	char        *eddsakey;
2949 	size_t       eddsakey_len;
2950 
2951 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2952 									&eddsakey, &eddsakey_len) == FAILURE) {
2953 		sodium_remove_param_values_from_backtrace(EG(exception));
2954 		RETURN_THROWS();
2955 	}
2956 	if (eddsakey_len != crypto_sign_SECRETKEYBYTES) {
2957 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
2958 		RETURN_THROWS();
2959 	}
2960 	ecdhkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0);
2961 
2962 	if (crypto_sign_ed25519_sk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey),
2963 											 (const unsigned char *) eddsakey) != 0) {
2964 		zend_throw_exception(sodium_exception_ce, "conversion failed", 0);
2965 		RETURN_THROWS();
2966 	}
2967 	ZSTR_VAL(ecdhkey)[crypto_box_SECRETKEYBYTES] = 0;
2968 
2969 	RETURN_STR(ecdhkey);
2970 }
2971 
PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519)2972 PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519)
2973 {
2974 	zend_string *ecdhkey;
2975 	char        *eddsakey;
2976 	size_t       eddsakey_len;
2977 
2978 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2979 									&eddsakey, &eddsakey_len) == FAILURE) {
2980 		sodium_remove_param_values_from_backtrace(EG(exception));
2981 		RETURN_THROWS();
2982 	}
2983 	if (eddsakey_len != crypto_sign_PUBLICKEYBYTES) {
2984 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
2985 		RETURN_THROWS();
2986 	}
2987 	ecdhkey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
2988 
2989 	if (crypto_sign_ed25519_pk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey),
2990 											 (const unsigned char *) eddsakey) != 0) {
2991 		zend_throw_exception(sodium_exception_ce, "conversion failed", 0);
2992 		RETURN_THROWS();
2993 	}
2994 	ZSTR_VAL(ecdhkey)[crypto_box_PUBLICKEYBYTES] = 0;
2995 
2996 	RETURN_STR(ecdhkey);
2997 }
2998 
PHP_FUNCTION(sodium_compare)2999 PHP_FUNCTION(sodium_compare)
3000 {
3001 	char      *buf1;
3002 	char      *buf2;
3003 	size_t     len1;
3004 	size_t     len2;
3005 
3006 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3007 									&buf1, &len1,
3008 									&buf2, &len2) == FAILURE) {
3009 		sodium_remove_param_values_from_backtrace(EG(exception));
3010 		RETURN_THROWS();
3011 	}
3012 	if (len1 != len2) {
3013 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
3014 		RETURN_THROWS();
3015 	} else {
3016 		RETURN_LONG(sodium_compare((const unsigned char *) buf1,
3017 								   (const unsigned char *) buf2, (size_t) len1));
3018 	}
3019 }
3020 
3021 #ifdef HAVE_AESGCM
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen)3022 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen)
3023 {
3024 	unsigned char key[crypto_aead_aes256gcm_KEYBYTES];
3025 
3026 	if (zend_parse_parameters_none() == FAILURE) {
3027 		RETURN_THROWS();
3028 	}
3029 	randombytes_buf(key, sizeof key);
3030 	RETURN_STRINGL((const char *) key, sizeof key);
3031 }
3032 #endif
3033 
3034 #ifdef crypto_aead_aegis128l_KEYBYTES
PHP_FUNCTION(sodium_crypto_aead_aegis128l_keygen)3035 PHP_FUNCTION(sodium_crypto_aead_aegis128l_keygen)
3036 {
3037 	unsigned char key[crypto_aead_aegis128l_KEYBYTES];
3038 
3039 	if (zend_parse_parameters_none() == FAILURE) {
3040 		RETURN_THROWS();
3041 	}
3042 	crypto_aead_aegis128l_keygen(key);
3043 	RETURN_STRINGL((const char *) key, sizeof key);
3044 }
3045 #endif
3046 
3047 #ifdef crypto_aead_aegis256_KEYBYTES
PHP_FUNCTION(sodium_crypto_aead_aegis256_keygen)3048 PHP_FUNCTION(sodium_crypto_aead_aegis256_keygen)
3049 {
3050 	unsigned char key[crypto_aead_aegis256_KEYBYTES];
3051 
3052 	if (zend_parse_parameters_none() == FAILURE) {
3053 		RETURN_THROWS();
3054 	}
3055 	crypto_aead_aegis256_keygen(key);
3056 	RETURN_STRINGL((const char *) key, sizeof key);
3057 }
3058 #endif
3059 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen)3060 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen)
3061 {
3062 	unsigned char key[crypto_aead_chacha20poly1305_KEYBYTES];
3063 
3064 	if (zend_parse_parameters_none() == FAILURE) {
3065 		RETURN_THROWS();
3066 	}
3067 	randombytes_buf(key, sizeof key);
3068 	RETURN_STRINGL((const char *) key, sizeof key);
3069 }
3070 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen)3071 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen)
3072 {
3073 	unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES];
3074 
3075 	if (zend_parse_parameters_none() == FAILURE) {
3076 		RETURN_THROWS();
3077 	}
3078 	randombytes_buf(key, sizeof key);
3079 	RETURN_STRINGL((const char *) key, sizeof key);
3080 }
3081 
3082 #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen)3083 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen)
3084 {
3085 	unsigned char key[crypto_aead_xchacha20poly1305_IETF_KEYBYTES];
3086 
3087 	if (zend_parse_parameters_none() == FAILURE) {
3088 		RETURN_THROWS();
3089 	}
3090 	randombytes_buf(key, sizeof key);
3091 	RETURN_STRINGL((const char *) key, sizeof key);
3092 }
3093 #endif
3094 
PHP_FUNCTION(sodium_crypto_auth_keygen)3095 PHP_FUNCTION(sodium_crypto_auth_keygen)
3096 {
3097 	unsigned char key[crypto_auth_KEYBYTES];
3098 
3099 	if (zend_parse_parameters_none() == FAILURE) {
3100 		RETURN_THROWS();
3101 	}
3102 	randombytes_buf(key, sizeof key);
3103 	RETURN_STRINGL((const char *) key, sizeof key);
3104 }
3105 
PHP_FUNCTION(sodium_crypto_generichash_keygen)3106 PHP_FUNCTION(sodium_crypto_generichash_keygen)
3107 {
3108 	unsigned char key[crypto_generichash_KEYBYTES];
3109 
3110 	if (zend_parse_parameters_none() == FAILURE) {
3111 		RETURN_THROWS();
3112 	}
3113 	randombytes_buf(key, sizeof key);
3114 	RETURN_STRINGL((const char *) key, sizeof key);
3115 }
3116 
PHP_FUNCTION(sodium_crypto_kdf_keygen)3117 PHP_FUNCTION(sodium_crypto_kdf_keygen)
3118 {
3119 	unsigned char key[crypto_kdf_KEYBYTES];
3120 
3121 	if (zend_parse_parameters_none() == FAILURE) {
3122 		RETURN_THROWS();
3123 	}
3124 	randombytes_buf(key, sizeof key);
3125 	RETURN_STRINGL((const char *) key, sizeof key);
3126 }
3127 
PHP_FUNCTION(sodium_crypto_secretbox_keygen)3128 PHP_FUNCTION(sodium_crypto_secretbox_keygen)
3129 {
3130 	unsigned char key[crypto_secretbox_KEYBYTES];
3131 
3132 	if (zend_parse_parameters_none() == FAILURE) {
3133 		RETURN_THROWS();
3134 	}
3135 	randombytes_buf(key, sizeof key);
3136 	RETURN_STRINGL((const char *) key, sizeof key);
3137 }
3138 
PHP_FUNCTION(sodium_crypto_shorthash_keygen)3139 PHP_FUNCTION(sodium_crypto_shorthash_keygen)
3140 {
3141 	unsigned char key[crypto_shorthash_KEYBYTES];
3142 
3143 	if (zend_parse_parameters_none() == FAILURE) {
3144 		RETURN_THROWS();
3145 	}
3146 	randombytes_buf(key, sizeof key);
3147 	RETURN_STRINGL((const char *) key, sizeof key);
3148 }
3149 
PHP_FUNCTION(sodium_crypto_stream_keygen)3150 PHP_FUNCTION(sodium_crypto_stream_keygen)
3151 {
3152 	unsigned char key[crypto_stream_KEYBYTES];
3153 
3154 	if (zend_parse_parameters_none() == FAILURE) {
3155 		RETURN_THROWS();
3156 	}
3157 	randombytes_buf(key, sizeof key);
3158 	RETURN_STRINGL((const char *) key, sizeof key);
3159 }
3160 #ifdef crypto_stream_xchacha20_KEYBYTES
PHP_FUNCTION(sodium_crypto_stream_xchacha20_keygen)3161 PHP_FUNCTION(sodium_crypto_stream_xchacha20_keygen)
3162 {
3163 	unsigned char key[crypto_stream_xchacha20_KEYBYTES];
3164 
3165 	if (zend_parse_parameters_none() == FAILURE) {
3166 		return;
3167 	}
3168 	randombytes_buf(key, sizeof key);
3169 	RETURN_STRINGL((const char *) key, sizeof key);
3170 }
3171 #endif
3172 
PHP_FUNCTION(sodium_crypto_kdf_derive_from_key)3173 PHP_FUNCTION(sodium_crypto_kdf_derive_from_key)
3174 {
3175 	unsigned char  ctx_padded[crypto_generichash_blake2b_PERSONALBYTES];
3176 #ifndef crypto_kdf_PRIMITIVE
3177 	unsigned char  salt[crypto_generichash_blake2b_SALTBYTES];
3178 #endif
3179 	char          *ctx;
3180 	char          *key;
3181 	zend_string   *subkey;
3182 	zend_long      subkey_id;
3183 	zend_long      subkey_len;
3184 	size_t         ctx_len;
3185 	size_t         key_len;
3186 
3187 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "llss",
3188 									&subkey_len,
3189 									&subkey_id,
3190 									&ctx, &ctx_len,
3191 									&key, &key_len) == FAILURE) {
3192 		sodium_remove_param_values_from_backtrace(EG(exception));
3193 		RETURN_THROWS();
3194 	}
3195 	if (subkey_len < crypto_kdf_BYTES_MIN) {
3196 		zend_argument_error(sodium_exception_ce, 1, "must be greater than or equal to SODIUM_CRYPTO_KDF_BYTES_MIN");
3197 		RETURN_THROWS();
3198 	}
3199 	if (subkey_len > crypto_kdf_BYTES_MAX || subkey_len > SIZE_MAX) {
3200 		zend_argument_error(sodium_exception_ce, 1, "must be less than or equal to SODIUM_CRYPTO_KDF_BYTES_MAX");
3201 		RETURN_THROWS();
3202 	}
3203 	if (subkey_id < 0) {
3204 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to 0");
3205 		RETURN_THROWS();
3206 	}
3207 	if (ctx_len != crypto_kdf_CONTEXTBYTES) {
3208 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes long");
3209 		RETURN_THROWS();
3210 	}
3211 	if (key_len != crypto_kdf_KEYBYTES) {
3212 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_KDF_BYTES_MIN bytes long");
3213 		RETURN_THROWS();
3214 	}
3215 	memcpy(ctx_padded, ctx, crypto_kdf_CONTEXTBYTES);
3216 	memset(ctx_padded + crypto_kdf_CONTEXTBYTES, 0, sizeof ctx_padded - crypto_kdf_CONTEXTBYTES);
3217 	subkey = zend_string_alloc((size_t) subkey_len, 0);
3218 #ifdef crypto_kdf_PRIMITIVE
3219 	crypto_kdf_derive_from_key((unsigned char *) ZSTR_VAL(subkey),
3220 							   (size_t) subkey_len, (uint64_t) subkey_id,
3221 							   ctx, (const unsigned char *) key);
3222 #else
3223 	salt[0] = (unsigned char) (((uint64_t) subkey_id)      );
3224 	salt[1] = (unsigned char) (((uint64_t) subkey_id) >>  8);
3225 	salt[2] = (unsigned char) (((uint64_t) subkey_id) >> 16);
3226 	salt[3] = (unsigned char) (((uint64_t) subkey_id) >> 24);
3227 	salt[4] = (unsigned char) (((uint64_t) subkey_id) >> 32);
3228 	salt[5] = (unsigned char) (((uint64_t) subkey_id) >> 40);
3229 	salt[6] = (unsigned char) (((uint64_t) subkey_id) >> 48);
3230 	salt[7] = (unsigned char) (((uint64_t) subkey_id) >> 56);
3231 	memset(salt + 8, 0, (sizeof salt) - 8);
3232 	crypto_generichash_blake2b_salt_personal((unsigned char *) ZSTR_VAL(subkey),
3233 											 (size_t) subkey_len,
3234 											 NULL, 0,
3235 											 (const unsigned char *) key,
3236 											 crypto_kdf_KEYBYTES,
3237 											 salt, ctx_padded);
3238 #endif
3239 	ZSTR_VAL(subkey)[subkey_len] = 0;
3240 
3241 	RETURN_STR(subkey);
3242 }
3243 
PHP_FUNCTION(sodium_pad)3244 PHP_FUNCTION(sodium_pad)
3245 {
3246 	zend_string    *padded;
3247 	char           *unpadded;
3248 	zend_long       blocksize;
3249 	volatile size_t st;
3250 	size_t          i, j, k;
3251 	size_t          unpadded_len;
3252 	size_t          xpadlen;
3253 	size_t          xpadded_len;
3254 
3255 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
3256 									&unpadded, &unpadded_len, &blocksize) == FAILURE) {
3257 		sodium_remove_param_values_from_backtrace(EG(exception));
3258 		RETURN_THROWS();
3259 	}
3260 	if (blocksize <= 0) {
3261 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
3262 		RETURN_THROWS();
3263 	}
3264 	if (blocksize > SIZE_MAX) {
3265 		zend_argument_error(sodium_exception_ce, 2, "is too large");
3266 		RETURN_THROWS();
3267 	}
3268 	xpadlen = blocksize - 1U;
3269 	if ((blocksize & (blocksize - 1U)) == 0U) {
3270 		xpadlen -= unpadded_len & ((size_t) blocksize - 1U);
3271 	} else {
3272 		xpadlen -= unpadded_len % (size_t) blocksize;
3273 	}
3274 	if ((size_t) SIZE_MAX - unpadded_len <= xpadlen) {
3275 		zend_throw_exception(sodium_exception_ce, "input is too large", 0);
3276 		RETURN_THROWS();
3277 	}
3278 	xpadded_len = unpadded_len + xpadlen;
3279 	padded = zend_string_alloc(xpadded_len + 1U, 0);
3280 	if (unpadded_len > 0) {
3281 		st = 1U;
3282 		i = 0U;
3283 		k = unpadded_len;
3284 		for (j = 0U; j <= xpadded_len; j++) {
3285 			ZSTR_VAL(padded)[j] = unpadded[i];
3286 			k -= st;
3287 			st = (size_t) (~(((( (((uint64_t) k) >> 48) | (((uint64_t) k) >> 32) |
3288 								 (k >> 16) | k) & 0xffff) - 1U) >> 16)) & 1U;
3289 			i += st;
3290 		}
3291 	}
3292 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
3293 	if (sodium_pad(NULL, (unsigned char *) ZSTR_VAL(padded), unpadded_len,
3294 				   (size_t) blocksize, xpadded_len + 1U) != 0) {
3295 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3296 		RETURN_THROWS();
3297 	}
3298 #else
3299 	{
3300 		char                   *tail;
3301 		volatile unsigned char  mask;
3302 		unsigned char           barrier_mask;
3303 
3304 		tail = &ZSTR_VAL(padded)[xpadded_len];
3305 		mask = 0U;
3306 		for (i = 0; i < blocksize; i++) {
3307 			barrier_mask = (unsigned char)
3308 				(((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
3309 			tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
3310 			mask |= barrier_mask;
3311 		}
3312 	}
3313 #endif
3314 	ZSTR_VAL(padded)[xpadded_len + 1U] = 0;
3315 
3316 	RETURN_STR(padded);
3317 }
3318 
PHP_FUNCTION(sodium_unpad)3319 PHP_FUNCTION(sodium_unpad)
3320 {
3321 	zend_string *unpadded;
3322 	char        *padded;
3323 	size_t       padded_len;
3324 	size_t       unpadded_len;
3325 	zend_long    blocksize;
3326 	int          ret;
3327 
3328 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
3329 									&padded, &padded_len, &blocksize) == FAILURE) {
3330 		sodium_remove_param_values_from_backtrace(EG(exception));
3331 		RETURN_THROWS();
3332 	}
3333 	if (blocksize <= 0) {
3334 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
3335 		RETURN_THROWS();
3336 	}
3337 	if (blocksize > SIZE_MAX) {
3338 		zend_argument_error(sodium_exception_ce, 2, "is too large");
3339 		RETURN_THROWS();
3340 	}
3341 	if (padded_len < blocksize) {
3342 		zend_argument_error(sodium_exception_ce, 1, "must be at least as long as the block size");
3343 		RETURN_THROWS();
3344 	}
3345 
3346 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
3347 	ret = sodium_unpad(&unpadded_len, (const unsigned char *) padded,
3348 					   padded_len, (size_t) blocksize);
3349 #else
3350 	{
3351 		const char      *tail;
3352 		unsigned char    acc = 0U;
3353 		unsigned char    c;
3354 		unsigned char    valid = 0U;
3355 		volatile size_t  pad_len = 0U;
3356 		size_t           i;
3357 		size_t           is_barrier;
3358 
3359 		tail = &padded[padded_len - 1U];
3360 
3361 		for (i = 0U; i < (size_t) blocksize; i++) {
3362 			c = tail[-i];
3363 			is_barrier =
3364 				(( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
3365 			acc |= c;
3366 			pad_len |= i & (1U + ~is_barrier);
3367 			valid |= (unsigned char) is_barrier;
3368 		}
3369 		unpadded_len = padded_len - 1U - pad_len;
3370 		ret = (int) (valid - 1U);
3371 	}
3372 #endif
3373 	if (ret != 0 || unpadded_len > LONG_MAX) {
3374 		zend_throw_exception(sodium_exception_ce, "invalid padding", 0);
3375 		RETURN_THROWS();
3376 	}
3377 	unpadded = zend_string_init(padded, padded_len, 0);
3378 	PHP_SODIUM_ZSTR_TRUNCATE(unpadded, unpadded_len);
3379 	ZSTR_VAL(unpadded)[unpadded_len] = 0;
3380 	RETURN_STR(unpadded);
3381 }
3382 
3383 #ifdef crypto_secretstream_xchacha20poly1305_ABYTES
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen)3384 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen)
3385 {
3386 	unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES];
3387 
3388 	if (zend_parse_parameters_none() == FAILURE) {
3389 		RETURN_THROWS();
3390 	}
3391 	randombytes_buf(key, sizeof key);
3392 	RETURN_STRINGL((const char *) key, sizeof key);
3393 }
3394 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push)3395 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push)
3396 {
3397 	crypto_secretstream_xchacha20poly1305_state  state;
3398 	unsigned char                                header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
3399 	unsigned char                               *key;
3400 	size_t                                       key_len;
3401 
3402 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3403 									&key, &key_len) == FAILURE) {
3404 		sodium_remove_param_values_from_backtrace(EG(exception));
3405 		RETURN_THROWS();
3406 	}
3407 	if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
3408 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes long");
3409 		RETURN_THROWS();
3410 	}
3411 	if (crypto_secretstream_xchacha20poly1305_init_push(&state,
3412 														header, key) != 0) {
3413 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3414 		RETURN_THROWS();
3415 	}
3416 	array_init(return_value);
3417 	add_next_index_stringl(return_value, (const char *) &state, sizeof state);
3418 	add_next_index_stringl(return_value, (const char *) header, sizeof header);
3419 }
3420 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push)3421 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push)
3422 {
3423 	zval               *state_zv;
3424 	zend_string        *c;
3425 	unsigned char      *ad = NULL;
3426 	unsigned char      *msg;
3427 	unsigned char      *state;
3428 	unsigned long long  c_real_len;
3429 	zend_long           tag = crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
3430 	size_t              ad_len = (size_t) 0U;
3431 	size_t              c_len;
3432 	size_t              msg_len;
3433 	size_t              state_len;
3434 
3435 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|sl",
3436 									&state_zv,
3437 									&msg, &msg_len, &ad, &ad_len, &tag) == FAILURE) {
3438 		sodium_remove_param_values_from_backtrace(EG(exception));
3439 		RETURN_THROWS();
3440 	}
3441 	ZVAL_DEREF(state_zv);
3442 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3443 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3444 		RETURN_THROWS();
3445 	}
3446 	sodium_separate_string(state_zv);
3447 	state = (unsigned char *) Z_STRVAL(*state_zv);
3448 	state_len = Z_STRLEN(*state_zv);
3449 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3450 		zend_argument_error(sodium_exception_ce, 1, "must have a correct length");
3451 		RETURN_THROWS();
3452 	}
3453 	if (msg_len > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX ||
3454 		msg_len > SIZE_MAX - crypto_secretstream_xchacha20poly1305_ABYTES) {
3455 		zend_argument_error(sodium_exception_ce, 2, "must be at most SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes long");
3456 		RETURN_THROWS();
3457 	}
3458 	if (tag < 0 || tag > 255) {
3459 		zend_argument_error(sodium_exception_ce, 4, "must be in the range of 0-255");
3460 		RETURN_THROWS();
3461 	}
3462 	c_len = msg_len + crypto_secretstream_xchacha20poly1305_ABYTES;
3463 	c = zend_string_alloc((size_t) c_len, 0);
3464 	if (crypto_secretstream_xchacha20poly1305_push
3465 		((void *) state, (unsigned char *) ZSTR_VAL(c), &c_real_len,
3466 		 msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len,
3467 		 (unsigned char) tag) != 0) {
3468 		zend_string_efree(c);
3469 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3470 		RETURN_THROWS();
3471 	}
3472 	if (c_real_len <= 0U || c_real_len >= SIZE_MAX || c_real_len > c_len) {
3473 		zend_string_efree(c);
3474 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
3475 		RETURN_THROWS();
3476 	}
3477 	PHP_SODIUM_ZSTR_TRUNCATE(c, (size_t) c_real_len);
3478 	ZSTR_VAL(c)[c_real_len] = 0;
3479 
3480 	RETURN_NEW_STR(c);
3481 }
3482 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull)3483 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull)
3484 {
3485 	crypto_secretstream_xchacha20poly1305_state  state;
3486 	unsigned char                               *header;
3487 	unsigned char                               *key;
3488 	size_t                                       header_len;
3489 	size_t                                       key_len;
3490 
3491 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3492 									&header, &header_len,
3493 									&key, &key_len) == FAILURE) {
3494 		sodium_remove_param_values_from_backtrace(EG(exception));
3495 		RETURN_THROWS();
3496 	}
3497 	if (header_len != crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
3498 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes long");
3499 		RETURN_THROWS();
3500 	}
3501 	if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
3502 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes long");
3503 		RETURN_THROWS();
3504 	}
3505 	if (crypto_secretstream_xchacha20poly1305_init_pull(&state,
3506 														header, key) != 0) {
3507 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3508 		RETURN_THROWS();
3509 	}
3510 	RETURN_STRINGL((const char *) &state, sizeof state);
3511 }
3512 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull)3513 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull)
3514 {
3515 	zval               *state_zv;
3516 	zend_string        *msg;
3517 	unsigned char      *ad = NULL;
3518 	unsigned char      *c;
3519 	unsigned char      *state;
3520 	unsigned long long  msg_real_len;
3521 	size_t              ad_len = (size_t) 0U;
3522 	size_t              msg_len;
3523 	size_t              c_len;
3524 	size_t              state_len;
3525 	unsigned char       tag;
3526 
3527 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|s",
3528 									&state_zv,
3529 									&c, &c_len, &ad, &ad_len) == FAILURE) {
3530 		sodium_remove_param_values_from_backtrace(EG(exception));
3531 		RETURN_THROWS();
3532 	}
3533 	ZVAL_DEREF(state_zv);
3534 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3535 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3536 		RETURN_THROWS();
3537 	}
3538 	sodium_separate_string(state_zv);
3539 	state = (unsigned char *) Z_STRVAL(*state_zv);
3540 	state_len = Z_STRLEN(*state_zv);
3541 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3542 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
3543 		RETURN_THROWS();
3544 	}
3545 	if (c_len < crypto_secretstream_xchacha20poly1305_ABYTES) {
3546 		RETURN_FALSE;
3547 	}
3548 	msg_len = c_len - crypto_secretstream_xchacha20poly1305_ABYTES;
3549 	msg = zend_string_alloc((size_t) msg_len, 0);
3550 	if (crypto_secretstream_xchacha20poly1305_pull
3551 		((void *) state, (unsigned char *) ZSTR_VAL(msg), &msg_real_len, &tag,
3552 		 c, (unsigned long long) c_len, ad, (unsigned long long) ad_len) != 0) {
3553 		zend_string_efree(msg);
3554 		RETURN_FALSE;
3555 	}
3556 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
3557 		zend_string_efree(msg);
3558 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
3559 		RETURN_THROWS();
3560 	}
3561 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
3562 	ZSTR_VAL(msg)[msg_real_len] = 0;
3563 	array_init(return_value);
3564 	add_next_index_str(return_value, msg);
3565 	add_next_index_long(return_value, (long) tag);
3566 }
3567 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey)3568 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey)
3569 {
3570 	zval          *state_zv;
3571 	unsigned char *state;
3572 	size_t         state_len;
3573 
3574 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &state_zv) == FAILURE) {
3575 		sodium_remove_param_values_from_backtrace(EG(exception));
3576 		RETURN_THROWS();
3577 	}
3578 	ZVAL_DEREF(state_zv);
3579 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3580 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3581 		RETURN_THROWS();
3582 	}
3583 	sodium_separate_string(state_zv);
3584 	state = (unsigned char *) Z_STRVAL(*state_zv);
3585 	state_len = Z_STRLEN(*state_zv);
3586 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3587 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
3588 		RETURN_THROWS();
3589 	}
3590 	crypto_secretstream_xchacha20poly1305_rekey((void *) state);
3591 }
3592 #endif
3593 
3594 #ifdef crypto_core_ristretto255_HASHBYTES
PHP_FUNCTION(sodium_crypto_core_ristretto255_add)3595 PHP_FUNCTION(sodium_crypto_core_ristretto255_add)
3596 {
3597 	zend_string   *r;
3598 	unsigned char *p;
3599 	unsigned char *q;
3600 	size_t         p_len;
3601 	size_t         q_len;
3602 
3603 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3604 									&p, &p_len, &q, &q_len) == FAILURE) {
3605 		sodium_remove_param_values_from_backtrace(EG(exception));
3606 		RETURN_THROWS();
3607 	}
3608 	if (p_len != crypto_core_ristretto255_BYTES) {
3609 		zend_argument_error(sodium_exception_ce, 1,
3610 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3611 		RETURN_THROWS();
3612 	}
3613 	if (q_len != crypto_core_ristretto255_BYTES) {
3614 		zend_argument_error(sodium_exception_ce, 2,
3615 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3616 		RETURN_THROWS();
3617 	}
3618 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3619 	if (crypto_core_ristretto255_add((unsigned char *) ZSTR_VAL(r), p, q) != 0) {
3620 		zend_string_efree(r);
3621 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3622 		RETURN_THROWS();
3623 	}
3624 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3625 	RETURN_NEW_STR(r);
3626 }
3627 
PHP_FUNCTION(sodium_crypto_core_ristretto255_from_hash)3628 PHP_FUNCTION(sodium_crypto_core_ristretto255_from_hash)
3629 {
3630 	zend_string   *r;
3631 	unsigned char *s;
3632 	size_t         s_len;
3633 
3634 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3635 							  &s, &s_len) == FAILURE) {
3636 		sodium_remove_param_values_from_backtrace(EG(exception));
3637 		RETURN_THROWS();
3638 	}
3639 	if (s_len != crypto_core_ristretto255_HASHBYTES) {
3640 		zend_argument_error(sodium_exception_ce, 1,
3641 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES bytes long");
3642 		RETURN_THROWS();
3643 	}
3644 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3645 	if (crypto_core_ristretto255_from_hash((unsigned char *) ZSTR_VAL(r), s) != 0) {
3646 		zend_string_efree(r);
3647 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3648 		RETURN_THROWS();
3649 	}
3650 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3651 	RETURN_NEW_STR(r);
3652 }
3653 
PHP_FUNCTION(sodium_crypto_core_ristretto255_is_valid_point)3654 PHP_FUNCTION(sodium_crypto_core_ristretto255_is_valid_point)
3655 {
3656 	unsigned char *s;
3657 	size_t         s_len;
3658 
3659 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3660 							  &s, &s_len) == FAILURE) {
3661 		sodium_remove_param_values_from_backtrace(EG(exception));
3662 		RETURN_THROWS();
3663 	}
3664 	if (s_len != crypto_core_ristretto255_BYTES) {
3665 		zend_argument_error(sodium_exception_ce, 1,
3666 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3667 		RETURN_THROWS();
3668 	}
3669 	RETURN_BOOL(crypto_core_ristretto255_is_valid_point(s));
3670 }
3671 
PHP_FUNCTION(sodium_crypto_core_ristretto255_random)3672 PHP_FUNCTION(sodium_crypto_core_ristretto255_random)
3673 {
3674 	zend_string   *r;
3675 
3676 	if (zend_parse_parameters_none() == FAILURE) {
3677 		RETURN_THROWS();
3678 	}
3679 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3680 	crypto_core_ristretto255_random((unsigned char *) ZSTR_VAL(r));
3681 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3682 	RETURN_NEW_STR(r);
3683 }
3684 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_add)3685 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_add)
3686 {
3687 	zend_string   *r;
3688 	unsigned char *p;
3689 	unsigned char *q;
3690 	size_t         p_len;
3691 	size_t         q_len;
3692 
3693 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3694 									&p, &p_len, &q, &q_len) == FAILURE) {
3695 		sodium_remove_param_values_from_backtrace(EG(exception));
3696 		RETURN_THROWS();
3697 	}
3698 	if (p_len != crypto_core_ristretto255_SCALARBYTES) {
3699 		zend_argument_error(sodium_exception_ce, 1,
3700 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3701 		RETURN_THROWS();
3702 	}
3703 	if (q_len != crypto_core_ristretto255_SCALARBYTES) {
3704 		zend_argument_error(sodium_exception_ce, 2,
3705 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3706 		RETURN_THROWS();
3707 	}
3708 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3709 	crypto_core_ristretto255_scalar_add((unsigned char *) ZSTR_VAL(r), p, q);
3710 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3711 	RETURN_NEW_STR(r);
3712 }
3713 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_complement)3714 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_complement)
3715 {
3716 	zend_string   *r;
3717 	unsigned char *s;
3718 	size_t         s_len;
3719 
3720 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3721 							  &s, &s_len) == FAILURE) {
3722 		sodium_remove_param_values_from_backtrace(EG(exception));
3723 		RETURN_THROWS();
3724 	}
3725 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3726 		zend_argument_error(sodium_exception_ce, 1,
3727 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3728 		RETURN_THROWS();
3729 	}
3730 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3731 	crypto_core_ristretto255_scalar_complement((unsigned char *) ZSTR_VAL(r), s);
3732 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3733 	RETURN_NEW_STR(r);
3734 }
3735 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_invert)3736 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_invert)
3737 {
3738 	zend_string   *r;
3739 	unsigned char *s;
3740 	size_t         s_len;
3741 
3742 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3743 							  &s, &s_len) == FAILURE) {
3744 		sodium_remove_param_values_from_backtrace(EG(exception));
3745 		RETURN_THROWS();
3746 	}
3747 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3748 		zend_argument_error(sodium_exception_ce, 1,
3749 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3750 		RETURN_THROWS();
3751 	}
3752 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3753 	if (crypto_core_ristretto255_scalar_invert((unsigned char *) ZSTR_VAL(r), s) != 0) {
3754 		zend_string_efree(r);
3755 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3756 		RETURN_THROWS();
3757 	}
3758 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3759 	RETURN_NEW_STR(r);
3760 }
3761 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_mul)3762 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_mul)
3763 {
3764 	zend_string   *r;
3765 	unsigned char *x;
3766 	unsigned char *y;
3767 	size_t         x_len;
3768 	size_t         y_len;
3769 
3770 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3771 									&x, &x_len, &y, &y_len) == FAILURE) {
3772 		sodium_remove_param_values_from_backtrace(EG(exception));
3773 		RETURN_THROWS();
3774 	}
3775 	if (x_len != crypto_core_ristretto255_SCALARBYTES) {
3776 		zend_argument_error(sodium_exception_ce, 1,
3777 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3778 		RETURN_THROWS();
3779 	}
3780 	if (y_len != crypto_core_ristretto255_SCALARBYTES) {
3781 		zend_argument_error(sodium_exception_ce, 2,
3782 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3783 		RETURN_THROWS();
3784 	}
3785 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3786 	crypto_core_ristretto255_scalar_mul((unsigned char *) ZSTR_VAL(r), x, y);
3787 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3788 	RETURN_NEW_STR(r);
3789 }
3790 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_negate)3791 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_negate)
3792 {
3793 	zend_string   *r;
3794 	unsigned char *s;
3795 	size_t         s_len;
3796 
3797 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3798 							  &s, &s_len) == FAILURE) {
3799 		sodium_remove_param_values_from_backtrace(EG(exception));
3800 		RETURN_THROWS();
3801 	}
3802 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3803 		zend_argument_error(sodium_exception_ce, 1,
3804 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3805 		RETURN_THROWS();
3806 	}
3807 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3808 	crypto_core_ristretto255_scalar_negate((unsigned char *) ZSTR_VAL(r), s);
3809 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3810 	RETURN_NEW_STR(r);
3811 }
3812 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_random)3813 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_random)
3814 {
3815 	zend_string   *r;
3816 
3817 	if (zend_parse_parameters_none() == FAILURE) {
3818 		RETURN_THROWS();
3819 	};
3820 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3821 	crypto_core_ristretto255_scalar_random((unsigned char *) ZSTR_VAL(r));
3822 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3823 	RETURN_NEW_STR(r);
3824 }
3825 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_reduce)3826 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_reduce)
3827 {
3828 	zend_string   *r;
3829 	unsigned char *s;
3830 	size_t         s_len;
3831 
3832 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3833 							  &s, &s_len) == FAILURE) {
3834 		sodium_remove_param_values_from_backtrace(EG(exception));
3835 		RETURN_THROWS();
3836 	}
3837 	if (s_len != crypto_core_ristretto255_NONREDUCEDSCALARBYTES) {
3838 		zend_argument_error(sodium_exception_ce, 1,
3839 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES bytes long");
3840 		RETURN_THROWS();
3841 	}
3842 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3843 	crypto_core_ristretto255_scalar_reduce((unsigned char *) ZSTR_VAL(r), s);
3844 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3845 	RETURN_NEW_STR(r);
3846 }
3847 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_sub)3848 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_sub)
3849 {
3850 	zend_string   *r;
3851 	unsigned char *p;
3852 	unsigned char *q;
3853 	size_t         p_len;
3854 	size_t         q_len;
3855 
3856 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3857 									&p, &p_len, &q, &q_len) == FAILURE) {
3858 		sodium_remove_param_values_from_backtrace(EG(exception));
3859 		RETURN_THROWS();
3860 	}
3861 	if (p_len != crypto_core_ristretto255_SCALARBYTES) {
3862 		zend_argument_error(sodium_exception_ce, 1,
3863 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3864 		RETURN_THROWS();
3865 	}
3866 	if (q_len != crypto_core_ristretto255_SCALARBYTES) {
3867 		zend_argument_error(sodium_exception_ce, 2,
3868 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3869 		RETURN_THROWS();
3870 	}
3871 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3872 	crypto_core_ristretto255_scalar_sub((unsigned char *) ZSTR_VAL(r), p, q);
3873 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3874 	RETURN_NEW_STR(r);
3875 }
3876 
PHP_FUNCTION(sodium_crypto_core_ristretto255_sub)3877 PHP_FUNCTION(sodium_crypto_core_ristretto255_sub)
3878 {
3879 	zend_string   *r;
3880 	unsigned char *p;
3881 	unsigned char *q;
3882 	size_t         p_len;
3883 	size_t         q_len;
3884 
3885 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3886 									&p, &p_len, &q, &q_len) == FAILURE) {
3887 		sodium_remove_param_values_from_backtrace(EG(exception));
3888 		RETURN_THROWS();
3889 	}
3890 	if (p_len != crypto_core_ristretto255_BYTES) {
3891 		zend_argument_error(sodium_exception_ce, 1,
3892 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3893 		RETURN_THROWS();
3894 	}
3895 	if (q_len != crypto_core_ristretto255_BYTES) {
3896 		zend_argument_error(sodium_exception_ce, 2,
3897 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3898 		RETURN_THROWS();
3899 	}
3900 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3901 	if (crypto_core_ristretto255_sub((unsigned char *) ZSTR_VAL(r), p, q) != 0) {
3902 		zend_string_efree(r);
3903 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3904 		RETURN_THROWS();
3905 	}
3906 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3907 	RETURN_NEW_STR(r);
3908 }
3909 #endif
3910