xref: /PHP-8.3/ext/sodium/libsodium.c (revision af444f97)
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))
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(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_string_efree(publickey);
996 		zend_throw_exception(sodium_exception_ce,
997 				   "internal error", 0);
998 		RETURN_THROWS();
999 	}
1000 	ZSTR_VAL(publickey)[crypto_sign_PUBLICKEYBYTES] = 0;
1001 
1002 	RETURN_STR(publickey);
1003 }
1004 
PHP_FUNCTION(sodium_crypto_sign_secretkey)1005 PHP_FUNCTION(sodium_crypto_sign_secretkey)
1006 {
1007 	zend_string   *secretkey;
1008 	unsigned char *keypair;
1009 	size_t         keypair_len;
1010 
1011 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1012 									&keypair, &keypair_len) == FAILURE) {
1013 		sodium_remove_param_values_from_backtrace(EG(exception));
1014 		RETURN_THROWS();
1015 	}
1016 	if (keypair_len !=
1017 		crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) {
1018 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_KEYPAIRBYTES bytes long");
1019 		RETURN_THROWS();
1020 	}
1021 	secretkey = zend_string_alloc(crypto_sign_SECRETKEYBYTES, 0);
1022 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_sign_SECRETKEYBYTES);
1023 	ZSTR_VAL(secretkey)[crypto_sign_SECRETKEYBYTES] = 0;
1024 
1025 	RETURN_STR(secretkey);
1026 }
1027 
PHP_FUNCTION(sodium_crypto_sign_publickey)1028 PHP_FUNCTION(sodium_crypto_sign_publickey)
1029 {
1030 	zend_string   *publickey;
1031 	unsigned char *keypair;
1032 	size_t         keypair_len;
1033 
1034 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1035 									&keypair, &keypair_len) == FAILURE) {
1036 		sodium_remove_param_values_from_backtrace(EG(exception));
1037 		RETURN_THROWS();
1038 	}
1039 	if (keypair_len !=
1040 		crypto_sign_SECRETKEYBYTES + crypto_sign_PUBLICKEYBYTES) {
1041 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_KEYPAIRBYTES bytes long");
1042 		RETURN_THROWS();
1043 	}
1044 	publickey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
1045 	memcpy(ZSTR_VAL(publickey), keypair + crypto_sign_SECRETKEYBYTES,
1046 		   crypto_sign_PUBLICKEYBYTES);
1047 	ZSTR_VAL(publickey)[crypto_sign_PUBLICKEYBYTES] = 0;
1048 
1049 	RETURN_STR(publickey);
1050 }
1051 
PHP_FUNCTION(sodium_crypto_sign)1052 PHP_FUNCTION(sodium_crypto_sign)
1053 {
1054 	zend_string        *msg_signed;
1055 	unsigned char      *msg;
1056 	unsigned char      *secretkey;
1057 	unsigned long long  msg_signed_real_len;
1058 	size_t              msg_len;
1059 	size_t              msg_signed_len;
1060 	size_t              secretkey_len;
1061 
1062 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1063 									&msg, &msg_len,
1064 									&secretkey, &secretkey_len) == FAILURE) {
1065 		sodium_remove_param_values_from_backtrace(EG(exception));
1066 		RETURN_THROWS();
1067 	}
1068 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
1069 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
1070 		RETURN_THROWS();
1071 	}
1072 	if (SIZE_MAX - msg_len <= crypto_sign_BYTES) {
1073 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1074 		RETURN_THROWS();
1075 	}
1076 	msg_signed_len = msg_len + crypto_sign_BYTES;
1077 	msg_signed = zend_string_alloc((size_t) msg_signed_len, 0);
1078 	if (crypto_sign((unsigned char *) ZSTR_VAL(msg_signed),
1079 					&msg_signed_real_len, msg,
1080 					(unsigned long long) msg_len, secretkey) != 0) {
1081 		zend_string_efree(msg_signed);
1082 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1083 		RETURN_THROWS();
1084 	}
1085 	if (msg_signed_real_len >= SIZE_MAX || msg_signed_real_len > msg_signed_len) {
1086 		zend_string_efree(msg_signed);
1087 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1088 		RETURN_THROWS();
1089 	}
1090 	PHP_SODIUM_ZSTR_TRUNCATE(msg_signed, (size_t) msg_signed_real_len);
1091 	ZSTR_VAL(msg_signed)[msg_signed_real_len] = 0;
1092 
1093 	RETURN_NEW_STR(msg_signed);
1094 }
1095 
PHP_FUNCTION(sodium_crypto_sign_open)1096 PHP_FUNCTION(sodium_crypto_sign_open)
1097 {
1098 	zend_string        *msg;
1099 	unsigned char      *msg_signed;
1100 	unsigned char      *publickey;
1101 	unsigned long long  msg_real_len;
1102 	size_t              msg_len;
1103 	size_t              msg_signed_len;
1104 	size_t              publickey_len;
1105 
1106 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1107 									&msg_signed, &msg_signed_len,
1108 									&publickey, &publickey_len) == FAILURE) {
1109 		sodium_remove_param_values_from_backtrace(EG(exception));
1110 		RETURN_THROWS();
1111 	}
1112 	if (publickey_len != crypto_sign_PUBLICKEYBYTES) {
1113 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
1114 		RETURN_THROWS();
1115 	}
1116 	msg_len = msg_signed_len;
1117 	if (msg_len >= SIZE_MAX) {
1118 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1119 		RETURN_THROWS();
1120 	}
1121 	msg = zend_string_alloc((size_t) msg_len, 0);
1122 	if (crypto_sign_open((unsigned char *) ZSTR_VAL(msg), &msg_real_len,
1123 						 msg_signed, (unsigned long long) msg_signed_len,
1124 						 publickey) != 0) {
1125 		zend_string_efree(msg);
1126 		RETURN_FALSE;
1127 	}
1128 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_signed_len) {
1129 		zend_string_efree(msg);
1130 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1131 		RETURN_THROWS();
1132 	}
1133 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
1134 	ZSTR_VAL(msg)[msg_real_len] = 0;
1135 
1136 	RETURN_NEW_STR(msg);
1137 }
1138 
PHP_FUNCTION(sodium_crypto_sign_detached)1139 PHP_FUNCTION(sodium_crypto_sign_detached)
1140 {
1141 	zend_string        *signature;
1142 	unsigned char      *msg;
1143 	unsigned char      *secretkey;
1144 	unsigned long long  signature_real_len;
1145 	size_t              msg_len;
1146 	size_t              secretkey_len;
1147 
1148 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1149 									&msg, &msg_len,
1150 									&secretkey, &secretkey_len) == FAILURE) {
1151 		sodium_remove_param_values_from_backtrace(EG(exception));
1152 		RETURN_THROWS();
1153 	}
1154 	if (secretkey_len != crypto_sign_SECRETKEYBYTES) {
1155 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
1156 		RETURN_THROWS();
1157 	}
1158 	signature = zend_string_alloc((size_t) crypto_sign_BYTES, 0);
1159 	memset(ZSTR_VAL(signature), 0, (size_t) crypto_sign_BYTES);
1160 	if (crypto_sign_detached((unsigned char *) ZSTR_VAL(signature),
1161 							 &signature_real_len, msg,
1162 							 (unsigned long long) msg_len, secretkey) != 0) {
1163 		zend_string_efree(signature);
1164 		zend_throw_exception(sodium_exception_ce, "signature creation failed", 0);
1165 		RETURN_THROWS();
1166 	}
1167 	if (signature_real_len <= 0U || signature_real_len > crypto_sign_BYTES) {
1168 		zend_string_efree(signature);
1169 		zend_throw_exception(sodium_exception_ce, "signature has a bogus size", 0);
1170 		RETURN_THROWS();
1171 	}
1172 	PHP_SODIUM_ZSTR_TRUNCATE(signature, (size_t) signature_real_len);
1173 	ZSTR_VAL(signature)[signature_real_len] = 0;
1174 
1175 	RETURN_NEW_STR(signature);
1176 }
1177 
PHP_FUNCTION(sodium_crypto_sign_verify_detached)1178 PHP_FUNCTION(sodium_crypto_sign_verify_detached)
1179 {
1180 	unsigned char *msg;
1181 	unsigned char *publickey;
1182 	unsigned char *signature;
1183 	size_t         msg_len;
1184 	size_t         publickey_len;
1185 	size_t         signature_len;
1186 
1187 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
1188 									&signature, &signature_len,
1189 									&msg, &msg_len,
1190 									&publickey, &publickey_len) == FAILURE) {
1191 		sodium_remove_param_values_from_backtrace(EG(exception));
1192 		RETURN_THROWS();
1193 	}
1194 	if (signature_len != crypto_sign_BYTES) {
1195 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_BYTES bytes long");
1196 		RETURN_THROWS();
1197 	}
1198 	if (publickey_len != crypto_sign_PUBLICKEYBYTES) {
1199 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
1200 		RETURN_THROWS();
1201 	}
1202 	if (crypto_sign_verify_detached(signature,
1203 									msg, (unsigned long long) msg_len,
1204 									publickey) != 0) {
1205 		RETURN_FALSE;
1206 	}
1207 	RETURN_TRUE;
1208 }
1209 
PHP_FUNCTION(sodium_crypto_stream)1210 PHP_FUNCTION(sodium_crypto_stream)
1211 {
1212 	zend_string   *ciphertext;
1213 	unsigned char *key;
1214 	unsigned char *nonce;
1215 	zend_long      ciphertext_len;
1216 	size_t         key_len;
1217 	size_t         nonce_len;
1218 
1219 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lss",
1220 									&ciphertext_len,
1221 									&nonce, &nonce_len,
1222 									&key, &key_len) == FAILURE) {
1223 		sodium_remove_param_values_from_backtrace(EG(exception));
1224 		RETURN_THROWS();
1225 	}
1226 	if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX) {
1227 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1228 		RETURN_THROWS();
1229 	}
1230 	if (nonce_len != crypto_stream_NONCEBYTES) {
1231 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_NONCEBYTES bytes long");
1232 		RETURN_THROWS();
1233 	}
1234 	if (key_len != crypto_stream_KEYBYTES) {
1235 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_KEYBYTES bytes long");
1236 		RETURN_THROWS();
1237 	}
1238 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1239 	if (crypto_stream((unsigned char *) ZSTR_VAL(ciphertext),
1240 					  (unsigned long long) ciphertext_len, nonce, key) != 0) {
1241 		zend_string_efree(ciphertext);
1242 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1243 		RETURN_THROWS();
1244 	}
1245 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1246 
1247 	RETURN_NEW_STR(ciphertext);
1248 }
1249 
PHP_FUNCTION(sodium_crypto_stream_xor)1250 PHP_FUNCTION(sodium_crypto_stream_xor)
1251 {
1252 	zend_string   *ciphertext;
1253 	unsigned char *key;
1254 	unsigned char *msg;
1255 	unsigned char *nonce;
1256 	size_t         ciphertext_len;
1257 	size_t         key_len;
1258 	size_t         msg_len;
1259 	size_t         nonce_len;
1260 
1261 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
1262 									&msg, &msg_len,
1263 									&nonce, &nonce_len,
1264 									&key, &key_len) == FAILURE) {
1265 		sodium_remove_param_values_from_backtrace(EG(exception));
1266 		RETURN_THROWS();
1267 	}
1268 	if (nonce_len != crypto_stream_NONCEBYTES) {
1269 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_NONCEBYTES bytes long");
1270 		RETURN_THROWS();
1271 	}
1272 	if (key_len != crypto_stream_KEYBYTES) {
1273 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_KEYBYTES bytes long");
1274 		RETURN_THROWS();
1275 	}
1276 	ciphertext_len = msg_len;
1277 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1278 	if (crypto_stream_xor((unsigned char *) ZSTR_VAL(ciphertext), msg,
1279 						  (unsigned long long) msg_len, nonce, key) != 0) {
1280 		zend_string_efree(ciphertext);
1281 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1282 		RETURN_THROWS();
1283 	}
1284 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1285 
1286 	RETURN_NEW_STR(ciphertext);
1287 }
1288 
1289 #ifdef crypto_stream_xchacha20_KEYBYTES
PHP_FUNCTION(sodium_crypto_stream_xchacha20)1290 PHP_FUNCTION(sodium_crypto_stream_xchacha20)
1291 {
1292 	zend_string   *ciphertext;
1293 	unsigned char *key;
1294 	unsigned char *nonce;
1295 	zend_long      ciphertext_len;
1296 	size_t         key_len;
1297 	size_t         nonce_len;
1298 
1299 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lss",
1300 									&ciphertext_len,
1301 									&nonce, &nonce_len,
1302 									&key, &key_len) == FAILURE) {
1303 		sodium_remove_param_values_from_backtrace(EG(exception));
1304 		RETURN_THROWS();
1305 	}
1306 	if (ciphertext_len <= 0 || ciphertext_len >= SIZE_MAX) {
1307 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1308 		RETURN_THROWS();
1309 	}
1310 	if (nonce_len != crypto_stream_xchacha20_NONCEBYTES) {
1311 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long");
1312 		RETURN_THROWS();
1313 	}
1314 	if (key_len != crypto_stream_xchacha20_KEYBYTES) {
1315 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long");
1316 		RETURN_THROWS();
1317 	}
1318 	ciphertext = zend_string_checked_alloc((size_t) ciphertext_len, 0);
1319 	if (crypto_stream_xchacha20((unsigned char *) ZSTR_VAL(ciphertext),
1320 								(unsigned long long) ciphertext_len, nonce, key) != 0) {
1321 		zend_string_free(ciphertext);
1322 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1323 		RETURN_THROWS();
1324 	}
1325 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1326 
1327 	RETURN_NEW_STR(ciphertext);
1328 }
1329 
PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor)1330 PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor)
1331 {
1332 	zend_string   *ciphertext;
1333 	unsigned char *key;
1334 	unsigned char *msg;
1335 	unsigned char *nonce;
1336 	size_t         ciphertext_len;
1337 	size_t         key_len;
1338 	size_t         msg_len;
1339 	size_t         nonce_len;
1340 
1341 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
1342 									&msg, &msg_len,
1343 									&nonce, &nonce_len,
1344 									&key, &key_len) == FAILURE) {
1345 		sodium_remove_param_values_from_backtrace(EG(exception));
1346 		RETURN_THROWS();
1347 	}
1348 	if (nonce_len != crypto_stream_xchacha20_NONCEBYTES) {
1349 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long");
1350 		RETURN_THROWS();
1351 	}
1352 	if (key_len != crypto_stream_xchacha20_KEYBYTES) {
1353 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long");
1354 		RETURN_THROWS();
1355 	}
1356 	ciphertext_len = msg_len;
1357 	ciphertext = zend_string_checked_alloc((size_t) ciphertext_len, 0);
1358 	if (crypto_stream_xchacha20_xor((unsigned char *) ZSTR_VAL(ciphertext), msg,
1359 									(unsigned long long) msg_len, nonce, key) != 0) {
1360 		zend_string_free(ciphertext);
1361 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1362 		RETURN_THROWS();
1363 	}
1364 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1365 
1366 	RETURN_NEW_STR(ciphertext);
1367 }
1368 
PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor_ic)1369 PHP_FUNCTION(sodium_crypto_stream_xchacha20_xor_ic)
1370 {
1371 	zend_string   *ciphertext;
1372 	unsigned char *key;
1373 	unsigned char *msg;
1374 	unsigned char *nonce;
1375 	zend_long      ic;
1376 
1377 	size_t         ciphertext_len;
1378 	size_t         key_len;
1379 	size_t         msg_len;
1380 	size_t         nonce_len;
1381 
1382 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssls",
1383 									&msg, &msg_len,
1384 									&nonce, &nonce_len,
1385 									&ic,
1386 									&key, &key_len) == FAILURE) {
1387 		sodium_remove_param_values_from_backtrace(EG(exception));
1388 		RETURN_THROWS();
1389 	}
1390 	if (nonce_len != crypto_stream_xchacha20_NONCEBYTES) {
1391 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES bytes long");
1392 		RETURN_THROWS();
1393 	}
1394 	if (key_len != crypto_stream_xchacha20_KEYBYTES) {
1395 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES bytes long");
1396 		RETURN_THROWS();
1397 	}
1398 	ciphertext_len = msg_len;
1399 	ciphertext = zend_string_checked_alloc((size_t) ciphertext_len, 0);
1400 	if (crypto_stream_xchacha20_xor_ic((unsigned char *) ZSTR_VAL(ciphertext), msg,
1401 									   (unsigned long long) msg_len, nonce,
1402 									   (uint64_t) ic, key) != 0) {
1403 		zend_string_free(ciphertext);
1404 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1405 		RETURN_THROWS();
1406 	}
1407 	ZSTR_VAL(ciphertext)[ciphertext_len] = 0;
1408 
1409 	RETURN_NEW_STR(ciphertext);
1410 }
1411 #endif
1412 
1413 #ifdef crypto_pwhash_SALTBYTES
PHP_FUNCTION(sodium_crypto_pwhash)1414 PHP_FUNCTION(sodium_crypto_pwhash)
1415 {
1416 	zend_string   *hash;
1417 	unsigned char *salt;
1418 	char          *passwd;
1419 	zend_long      hash_len;
1420 	zend_long      memlimit;
1421 	zend_long      opslimit;
1422 	zend_long      alg;
1423 	size_t         passwd_len;
1424 	size_t         salt_len;
1425 	int            ret;
1426 
1427 	alg = (zend_long) crypto_pwhash_ALG_DEFAULT;
1428 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lssll|l",
1429 									&hash_len,
1430 									&passwd, &passwd_len,
1431 									&salt, &salt_len,
1432 									&opslimit, &memlimit, &alg) == FAILURE) {
1433 		sodium_remove_param_values_from_backtrace(EG(exception));
1434 		RETURN_THROWS();
1435 	}
1436 	if (hash_len <= 0) {
1437 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1438 		RETURN_THROWS();
1439 	}
1440 	if (hash_len >= 0xffffffff) {
1441 		zend_argument_error(sodium_exception_ce, 1, "is too large");
1442 		RETURN_THROWS();
1443 	}
1444 	if (passwd_len >= 0xffffffff) {
1445 		zend_argument_error(sodium_exception_ce, 2, "is too long");
1446 		RETURN_THROWS();
1447 	}
1448 	if (opslimit <= 0) {
1449 		zend_argument_error(sodium_exception_ce, 4, "must be greater than 0");
1450 		RETURN_THROWS();
1451 	}
1452 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1453 		zend_argument_error(sodium_exception_ce, 5, "must be greater than 0");
1454 		RETURN_THROWS();
1455 	}
1456 	if (alg != crypto_pwhash_ALG_ARGON2I13
1457 # ifdef crypto_pwhash_ALG_ARGON2ID13
1458 		&& alg != crypto_pwhash_ALG_ARGON2ID13
1459 # endif
1460 		&& alg != crypto_pwhash_ALG_DEFAULT) {
1461 		zend_throw_exception(sodium_exception_ce, "unsupported password hashing algorithm", 0);
1462 		RETURN_THROWS();
1463 	}
1464 	if (passwd_len <= 0) {
1465 		zend_error(E_WARNING, "empty password");
1466 	}
1467 	if (salt_len != crypto_pwhash_SALTBYTES) {
1468 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_PWHASH_SALTBYTES bytes long");
1469 		RETURN_THROWS();
1470 	}
1471 	if (opslimit < crypto_pwhash_OPSLIMIT_MIN) {
1472 		zend_argument_error(sodium_exception_ce, 4, "must be greater than or equal to %d", crypto_pwhash_OPSLIMIT_MIN);
1473 		RETURN_THROWS();
1474 	}
1475 	if (memlimit < crypto_pwhash_MEMLIMIT_MIN) {
1476 		zend_argument_error(sodium_exception_ce, 5, "must be greater than or equal to %d", crypto_pwhash_MEMLIMIT_MIN);
1477 	}
1478 	hash = zend_string_alloc((size_t) hash_len, 0);
1479 	ret = -1;
1480 # ifdef crypto_pwhash_ALG_ARGON2ID13
1481 	if (alg == crypto_pwhash_ALG_ARGON2ID13) {
1482 		ret = crypto_pwhash_argon2id
1483 			((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len,
1484 			  passwd, (unsigned long long) passwd_len, salt,
1485 			  (unsigned long long) opslimit, (size_t) memlimit, (int) alg);
1486 	}
1487 # endif
1488 	if (ret == -1) {
1489 		ret = crypto_pwhash
1490 			((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len,
1491 			  passwd, (unsigned long long) passwd_len, salt,
1492 			  (unsigned long long) opslimit, (size_t) memlimit, (int) alg);
1493 	}
1494 	if (ret != 0) {
1495 		zend_string_efree(hash);
1496 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1497 		RETURN_THROWS();
1498 	}
1499 	ZSTR_VAL(hash)[hash_len] = 0;
1500 
1501 	RETURN_NEW_STR(hash);
1502 }
1503 
PHP_FUNCTION(sodium_crypto_pwhash_str)1504 PHP_FUNCTION(sodium_crypto_pwhash_str)
1505 {
1506 	zend_string *hash_str;
1507 	char        *passwd;
1508 	zend_long    memlimit;
1509 	zend_long    opslimit;
1510 	size_t       passwd_len;
1511 	size_t       len;
1512 
1513 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll",
1514 									&passwd, &passwd_len,
1515 									&opslimit, &memlimit) == FAILURE) {
1516 		sodium_remove_param_values_from_backtrace(EG(exception));
1517 		RETURN_THROWS();
1518 	}
1519 	if (opslimit <= 0) {
1520 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
1521 		RETURN_THROWS();
1522 	}
1523 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1524 		zend_argument_error(sodium_exception_ce, 3, "must be greater than 0");
1525 		RETURN_THROWS();
1526 	}
1527 	if (passwd_len >= 0xffffffff) {
1528 		zend_argument_error(sodium_exception_ce, 1, "is too long");
1529 		RETURN_THROWS();
1530 	}
1531 	if (passwd_len <= 0) {
1532 		zend_error(E_WARNING, "empty password");
1533 	}
1534 	if (opslimit < crypto_pwhash_OPSLIMIT_MIN) {
1535 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to %d", crypto_pwhash_OPSLIMIT_MIN);
1536 	}
1537 	if (memlimit < crypto_pwhash_MEMLIMIT_MIN) {
1538 		zend_argument_error(sodium_exception_ce, 3, "must be greater than or equal to %d", crypto_pwhash_MEMLIMIT_MIN);
1539 	}
1540 	hash_str = zend_string_alloc(crypto_pwhash_STRBYTES - 1, 0);
1541 	if (crypto_pwhash_str
1542 		(ZSTR_VAL(hash_str), passwd, (unsigned long long) passwd_len,
1543 		 (unsigned long long) opslimit, (size_t) memlimit) != 0) {
1544 		zend_string_efree(hash_str);
1545 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1546 		RETURN_THROWS();
1547 	}
1548 	ZSTR_VAL(hash_str)[crypto_pwhash_STRBYTES - 1] = 0;
1549 
1550 	len = strlen(ZSTR_VAL(hash_str));
1551 	PHP_SODIUM_ZSTR_TRUNCATE(hash_str, len);
1552 
1553 	RETURN_NEW_STR(hash_str);
1554 }
1555 
1556 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
PHP_FUNCTION(sodium_crypto_pwhash_str_needs_rehash)1557 PHP_FUNCTION(sodium_crypto_pwhash_str_needs_rehash)
1558 {
1559 	char      *hash_str;
1560 	zend_long  memlimit;
1561 	zend_long  opslimit;
1562 	size_t     hash_str_len;
1563 
1564 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll",
1565 									&hash_str, &hash_str_len, &opslimit, &memlimit) == FAILURE) {
1566 		RETURN_THROWS();
1567 	}
1568 	if (crypto_pwhash_str_needs_rehash(hash_str, opslimit, memlimit) == 0) {
1569 		RETURN_FALSE;
1570 	}
1571 	RETURN_TRUE;
1572 }
1573 #endif
1574 
PHP_FUNCTION(sodium_crypto_pwhash_str_verify)1575 PHP_FUNCTION(sodium_crypto_pwhash_str_verify)
1576 {
1577 	char      *hash_str;
1578 	char      *passwd;
1579 	size_t     hash_str_len;
1580 	size_t     passwd_len;
1581 
1582 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1583 									&hash_str, &hash_str_len,
1584 									&passwd, &passwd_len) == FAILURE) {
1585 		sodium_remove_param_values_from_backtrace(EG(exception));
1586 		RETURN_THROWS();
1587 	}
1588 	if (passwd_len >= 0xffffffff) {
1589 		zend_argument_error(sodium_exception_ce, 2, "is too long");
1590 		RETURN_THROWS();
1591 	}
1592 	if (passwd_len <= 0) {
1593 		zend_error(E_WARNING, "empty password");
1594 	}
1595 	if (crypto_pwhash_str_verify
1596 		(hash_str, passwd, (unsigned long long) passwd_len) == 0) {
1597 		RETURN_TRUE;
1598 	}
1599 	RETURN_FALSE;
1600 }
1601 #endif
1602 
1603 #ifdef crypto_pwhash_scryptsalsa208sha256_SALTBYTES
PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256)1604 PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256)
1605 {
1606 	zend_string   *hash;
1607 	unsigned char *salt;
1608 	char          *passwd;
1609 	zend_long      hash_len;
1610 	zend_long      memlimit;
1611 	zend_long      opslimit;
1612 	size_t         passwd_len;
1613 	size_t         salt_len;
1614 
1615 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lssll",
1616 									&hash_len,
1617 									&passwd, &passwd_len,
1618 									&salt, &salt_len,
1619 									&opslimit, &memlimit) == FAILURE) {
1620 		sodium_remove_param_values_from_backtrace(EG(exception));
1621 		RETURN_THROWS();
1622 	}
1623 	if (hash_len <= 0 || hash_len >= SIZE_MAX || hash_len > 0x1fffffffe0ULL) {
1624 		zend_argument_error(sodium_exception_ce, 1, "must be greater than 0");
1625 		RETURN_THROWS();
1626 	}
1627 	if (opslimit <= 0) {
1628 		zend_argument_error(sodium_exception_ce, 4, "must be greater than 0");
1629 		RETURN_THROWS();
1630 	}
1631 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1632 		zend_argument_error(sodium_exception_ce, 5, "must be greater than 0");
1633 		RETURN_THROWS();
1634 	}
1635 	if (passwd_len <= 0) {
1636 		zend_error(E_WARNING, "empty password");
1637 	}
1638 	if (salt_len != crypto_pwhash_scryptsalsa208sha256_SALTBYTES) {
1639 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES bytes long");
1640 		RETURN_THROWS();
1641 	}
1642 	if (opslimit < crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE) {
1643 		zend_argument_error(sodium_exception_ce, 4, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE);
1644 	}
1645 	if (memlimit < crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) {
1646 		zend_argument_error(sodium_exception_ce, 5, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);
1647 	}
1648 	hash = zend_string_alloc((size_t) hash_len, 0);
1649 	if (crypto_pwhash_scryptsalsa208sha256
1650 		((unsigned char *) ZSTR_VAL(hash), (unsigned long long) hash_len,
1651 		 passwd, (unsigned long long) passwd_len, salt,
1652 		 (unsigned long long) opslimit, (size_t) memlimit) != 0) {
1653 		zend_string_efree(hash);
1654 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1655 		RETURN_THROWS();
1656 	}
1657 	ZSTR_VAL(hash)[hash_len] = 0;
1658 
1659 	RETURN_NEW_STR(hash);
1660 }
1661 
PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str)1662 PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str)
1663 {
1664 	zend_string *hash_str;
1665 	char        *passwd;
1666 	zend_long    memlimit;
1667 	zend_long    opslimit;
1668 	size_t       passwd_len;
1669 
1670 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll",
1671 									&passwd, &passwd_len,
1672 									&opslimit, &memlimit) == FAILURE) {
1673 		sodium_remove_param_values_from_backtrace(EG(exception));
1674 		RETURN_THROWS();
1675 	}
1676 	if (opslimit <= 0) {
1677 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
1678 		RETURN_THROWS();
1679 	}
1680 	if (memlimit <= 0 || memlimit > SIZE_MAX) {
1681 		zend_argument_error(sodium_exception_ce, 3, "must be greater than 0");
1682 		RETURN_THROWS();
1683 	}
1684 	if (passwd_len <= 0) {
1685 		zend_error(E_WARNING, "empty password");
1686 	}
1687 	if (opslimit < crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE) {
1688 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE);
1689 	}
1690 	if (memlimit < crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) {
1691 		zend_argument_error(sodium_exception_ce, 3, "must be greater than or equal to %d", crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);
1692 	}
1693 	hash_str = zend_string_alloc
1694 		(crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1, 0);
1695 	if (crypto_pwhash_scryptsalsa208sha256_str
1696 		(ZSTR_VAL(hash_str), passwd, (unsigned long long) passwd_len,
1697 		 (unsigned long long) opslimit, (size_t) memlimit) != 0) {
1698 		zend_string_efree(hash_str);
1699 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1700 		RETURN_THROWS();
1701 	}
1702 	ZSTR_VAL(hash_str)[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1] = 0;
1703 
1704 	RETURN_NEW_STR(hash_str);
1705 }
1706 
PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify)1707 PHP_FUNCTION(sodium_crypto_pwhash_scryptsalsa208sha256_str_verify)
1708 {
1709 	char      *hash_str;
1710 	char      *passwd;
1711 	size_t     hash_str_len;
1712 	size_t     passwd_len;
1713 
1714 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
1715 									&hash_str, &hash_str_len,
1716 									&passwd, &passwd_len) == FAILURE) {
1717 		sodium_remove_param_values_from_backtrace(EG(exception));
1718 		RETURN_THROWS();
1719 	}
1720 	if (passwd_len <= 0) {
1721 		zend_error(E_WARNING, "empty password");
1722 	}
1723 	if (hash_str_len != crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1) {
1724 		zend_error(E_WARNING, "wrong size for the hashed password");
1725 		RETURN_FALSE;
1726 	}
1727 	if (crypto_pwhash_scryptsalsa208sha256_str_verify
1728 		(hash_str, passwd, (unsigned long long) passwd_len) == 0) {
1729 		RETURN_TRUE;
1730 	}
1731 	RETURN_FALSE;
1732 }
1733 #endif
1734 
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available)1735 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_is_available)
1736 {
1737 	if (zend_parse_parameters_none() == FAILURE) {
1738 		RETURN_THROWS();
1739 	}
1740 #ifdef HAVE_AESGCM
1741 	RETURN_BOOL(crypto_aead_aes256gcm_is_available());
1742 #else
1743 	RETURN_FALSE;
1744 #endif
1745 }
1746 
1747 #ifdef HAVE_AESGCM
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_encrypt)1748 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_encrypt)
1749 {
1750 	zend_string        *ciphertext;
1751 	unsigned char      *ad;
1752 	unsigned char      *msg;
1753 	unsigned char      *npub;
1754 	unsigned char      *secretkey;
1755 	unsigned long long  ciphertext_real_len;
1756 	size_t              ad_len;
1757 	size_t              ciphertext_len;
1758 	size_t              msg_len;
1759 	size_t              npub_len;
1760 	size_t              secretkey_len;
1761 
1762 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1763 									&msg, &msg_len,
1764 									&ad, &ad_len,
1765 									&npub, &npub_len,
1766 									&secretkey, &secretkey_len) == FAILURE) {
1767 		sodium_remove_param_values_from_backtrace(EG(exception));
1768 		RETURN_THROWS();
1769 	}
1770 	if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) {
1771 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes long");
1772 		RETURN_THROWS();
1773 	}
1774 	if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) {
1775 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES bytes long");
1776 		RETURN_THROWS();
1777 	}
1778 	if (SIZE_MAX - msg_len <= crypto_aead_aes256gcm_ABYTES) {
1779 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1780 		RETURN_THROWS();
1781 	}
1782 	if ((unsigned long long) msg_len > (16ULL * ((1ULL << 32) - 2ULL)) - crypto_aead_aes256gcm_ABYTES) {
1783 		zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0);
1784 		RETURN_THROWS();
1785 	}
1786 	ciphertext_len = msg_len + crypto_aead_aes256gcm_ABYTES;
1787 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1788 	if (crypto_aead_aes256gcm_encrypt
1789 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
1790 		 (unsigned long long) msg_len,
1791 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
1792 		zend_string_efree(ciphertext);
1793 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
1794 		RETURN_THROWS();
1795 	}
1796 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
1797 		ciphertext_real_len > ciphertext_len) {
1798 		zend_string_efree(ciphertext);
1799 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1800 		RETURN_THROWS();
1801 	}
1802 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
1803 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
1804 
1805 	RETURN_NEW_STR(ciphertext);
1806 }
1807 
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt)1808 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt)
1809 {
1810 	zend_string        *msg;
1811 	unsigned char      *ad;
1812 	unsigned char      *ciphertext;
1813 	unsigned char      *npub;
1814 	unsigned char      *secretkey;
1815 	unsigned long long  msg_real_len;
1816 	size_t              ad_len;
1817 	size_t              ciphertext_len;
1818 	size_t              msg_len;
1819 	size_t              npub_len;
1820 	size_t              secretkey_len;
1821 
1822 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1823 									&ciphertext, &ciphertext_len,
1824 									&ad, &ad_len,
1825 									&npub, &npub_len,
1826 									&secretkey, &secretkey_len) == FAILURE) {
1827 		sodium_remove_param_values_from_backtrace(EG(exception));
1828 		RETURN_THROWS();
1829 	}
1830 	if (npub_len != crypto_aead_aes256gcm_NPUBBYTES) {
1831 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES bytes long");
1832 		RETURN_THROWS();
1833 	}
1834 	if (secretkey_len != crypto_aead_aes256gcm_KEYBYTES) {
1835 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES bytes long");
1836 		RETURN_THROWS();
1837 	}
1838 	if (ciphertext_len < crypto_aead_aes256gcm_ABYTES) {
1839 		RETURN_FALSE;
1840 	}
1841 	if (ciphertext_len - crypto_aead_aes256gcm_ABYTES > 16ULL * ((1ULL << 32) - 2ULL)) {
1842 		zend_argument_error(sodium_exception_ce, 1, "is too long");
1843 		RETURN_THROWS();
1844 	}
1845 	msg_len = ciphertext_len;
1846 	if (msg_len >= SIZE_MAX) {
1847 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1848 		RETURN_THROWS();
1849 	}
1850 	msg = zend_string_alloc((size_t) msg_len, 0);
1851 	if (crypto_aead_aes256gcm_decrypt
1852 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
1853 		 ciphertext, (unsigned long long) ciphertext_len,
1854 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
1855 		zend_string_efree(msg);
1856 		RETURN_FALSE;
1857 	}
1858 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
1859 		zend_string_efree(msg);
1860 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1861 		RETURN_THROWS();
1862 	}
1863 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
1864 	ZSTR_VAL(msg)[msg_real_len] = 0;
1865 
1866 	RETURN_NEW_STR(msg);
1867 }
1868 #endif
1869 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_encrypt)1870 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_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_chacha20poly1305_NPUBBYTES) {
1893 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes long");
1894 		RETURN_THROWS();
1895 	}
1896 	if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) {
1897 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes long");
1898 		RETURN_THROWS();
1899 	}
1900 	if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_ABYTES) {
1901 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
1902 		RETURN_THROWS();
1903 	}
1904 	ciphertext_len = msg_len + crypto_aead_chacha20poly1305_ABYTES;
1905 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
1906 	if (crypto_aead_chacha20poly1305_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_chacha20poly1305_decrypt)1926 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_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_chacha20poly1305_NPUBBYTES) {
1949 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES bytes long");
1950 		RETURN_THROWS();
1951 	}
1952 	if (secretkey_len != crypto_aead_chacha20poly1305_KEYBYTES) {
1953 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES bytes long");
1954 		RETURN_THROWS();
1955 	}
1956 	if (ciphertext_len < crypto_aead_chacha20poly1305_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_chacha20poly1305_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 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_encrypt)1983 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_encrypt)
1984 {
1985 	zend_string        *ciphertext;
1986 	unsigned char      *ad;
1987 	unsigned char      *msg;
1988 	unsigned char      *npub;
1989 	unsigned char      *secretkey;
1990 	unsigned long long  ciphertext_real_len;
1991 	size_t              ad_len;
1992 	size_t              ciphertext_len;
1993 	size_t              msg_len;
1994 	size_t              npub_len;
1995 	size_t              secretkey_len;
1996 
1997 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
1998 									&msg, &msg_len,
1999 									&ad, &ad_len,
2000 									&npub, &npub_len,
2001 									&secretkey, &secretkey_len) == FAILURE) {
2002 		sodium_remove_param_values_from_backtrace(EG(exception));
2003 		RETURN_THROWS();
2004 	}
2005 	if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) {
2006 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2007 		RETURN_THROWS();
2008 	}
2009 	if (secretkey_len != crypto_aead_chacha20poly1305_IETF_KEYBYTES) {
2010 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes long");
2011 		RETURN_THROWS();
2012 	}
2013 	if (SIZE_MAX - msg_len <= crypto_aead_chacha20poly1305_IETF_ABYTES) {
2014 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2015 		RETURN_THROWS();
2016 	}
2017 	if ((unsigned long long) msg_len > 64ULL * (1ULL << 32) - 64ULL) {
2018 		zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0);
2019 		RETURN_THROWS();
2020 	}
2021 	ciphertext_len = msg_len + crypto_aead_chacha20poly1305_IETF_ABYTES;
2022 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
2023 	if (crypto_aead_chacha20poly1305_ietf_encrypt
2024 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
2025 		 (unsigned long long) msg_len,
2026 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
2027 		zend_string_efree(ciphertext);
2028 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2029 		RETURN_THROWS();
2030 	}
2031 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
2032 		ciphertext_real_len > ciphertext_len) {
2033 		zend_string_efree(ciphertext);
2034 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2035 		RETURN_THROWS();
2036 	}
2037 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
2038 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
2039 
2040 	RETURN_NEW_STR(ciphertext);
2041 }
2042 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_decrypt)2043 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_decrypt)
2044 {
2045 	zend_string        *msg;
2046 	unsigned char      *ad;
2047 	unsigned char      *ciphertext;
2048 	unsigned char      *npub;
2049 	unsigned char      *secretkey;
2050 	unsigned long long  msg_real_len;
2051 	size_t              ad_len;
2052 	size_t              ciphertext_len;
2053 	size_t              msg_len;
2054 	size_t              npub_len;
2055 	size_t              secretkey_len;
2056 
2057 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2058 									&ciphertext, &ciphertext_len,
2059 									&ad, &ad_len,
2060 									&npub, &npub_len,
2061 									&secretkey, &secretkey_len) == FAILURE) {
2062 		sodium_remove_param_values_from_backtrace(EG(exception));
2063 		RETURN_THROWS();
2064 	}
2065 	if (npub_len != crypto_aead_chacha20poly1305_IETF_NPUBBYTES) {
2066 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2067 		RETURN_THROWS();
2068 	}
2069 	if (secretkey_len != crypto_aead_chacha20poly1305_IETF_KEYBYTES) {
2070 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES bytes long");
2071 		RETURN_THROWS();
2072 	}
2073 	msg_len = ciphertext_len;
2074 	if (msg_len >= SIZE_MAX) {
2075 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2076 		RETURN_THROWS();
2077 	}
2078 	if (ciphertext_len < crypto_aead_chacha20poly1305_IETF_ABYTES) {
2079 		RETURN_FALSE;
2080 	}
2081 	if ((unsigned long long) ciphertext_len -
2082 		crypto_aead_chacha20poly1305_IETF_ABYTES > 64ULL * (1ULL << 32) - 64ULL) {
2083 		zend_throw_exception(sodium_exception_ce, "message too long for a single key", 0);
2084 		RETURN_THROWS();
2085 	}
2086 	msg = zend_string_alloc((size_t) msg_len, 0);
2087 	if (crypto_aead_chacha20poly1305_ietf_decrypt
2088 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
2089 		 ciphertext, (unsigned long long) ciphertext_len,
2090 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
2091 		zend_string_efree(msg);
2092 		RETURN_FALSE;
2093 	}
2094 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
2095 		zend_string_efree(msg);
2096 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2097 		RETURN_THROWS();
2098 	}
2099 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
2100 	ZSTR_VAL(msg)[msg_real_len] = 0;
2101 
2102 	RETURN_NEW_STR(msg);
2103 }
2104 
2105 #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt)2106 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_encrypt)
2107 {
2108 	zend_string        *ciphertext;
2109 	unsigned char      *ad;
2110 	unsigned char      *msg;
2111 	unsigned char      *npub;
2112 	unsigned char      *secretkey;
2113 	unsigned long long  ciphertext_real_len;
2114 	size_t              ad_len;
2115 	size_t              ciphertext_len;
2116 	size_t              msg_len;
2117 	size_t              npub_len;
2118 	size_t              secretkey_len;
2119 
2120 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2121 									&msg, &msg_len,
2122 									&ad, &ad_len,
2123 									&npub, &npub_len,
2124 									&secretkey, &secretkey_len) == FAILURE) {
2125 		sodium_remove_param_values_from_backtrace(EG(exception));
2126 		RETURN_THROWS();
2127 	}
2128 	if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) {
2129 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2130 		RETURN_THROWS();
2131 	}
2132 	if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) {
2133 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES bytes long");
2134 		RETURN_THROWS();
2135 	}
2136 	if (SIZE_MAX - msg_len <= crypto_aead_xchacha20poly1305_IETF_ABYTES) {
2137 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2138 		RETURN_THROWS();
2139 	}
2140 	ciphertext_len = msg_len + crypto_aead_xchacha20poly1305_IETF_ABYTES;
2141 	ciphertext = zend_string_alloc((size_t) ciphertext_len, 0);
2142 	if (crypto_aead_xchacha20poly1305_ietf_encrypt
2143 		((unsigned char *) ZSTR_VAL(ciphertext), &ciphertext_real_len, msg,
2144 		 (unsigned long long) msg_len,
2145 		 ad, (unsigned long long) ad_len, NULL, npub, secretkey) != 0) {
2146 		zend_string_efree(ciphertext);
2147 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2148 		RETURN_THROWS();
2149 	}
2150 	if (ciphertext_real_len <= 0U || ciphertext_real_len >= SIZE_MAX ||
2151 		ciphertext_real_len > ciphertext_len) {
2152 		zend_string_efree(ciphertext);
2153 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2154 		RETURN_THROWS();
2155 	}
2156 	PHP_SODIUM_ZSTR_TRUNCATE(ciphertext, (size_t) ciphertext_real_len);
2157 	ZSTR_VAL(ciphertext)[ciphertext_real_len] = 0;
2158 
2159 	RETURN_NEW_STR(ciphertext);
2160 }
2161 
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt)2162 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt)
2163 {
2164 	zend_string        *msg;
2165 	unsigned char      *ad;
2166 	unsigned char      *ciphertext;
2167 	unsigned char      *npub;
2168 	unsigned char      *secretkey;
2169 	unsigned long long  msg_real_len;
2170 	size_t              ad_len;
2171 	size_t              ciphertext_len;
2172 	size_t              msg_len;
2173 	size_t              npub_len;
2174 	size_t              secretkey_len;
2175 
2176 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss",
2177 									&ciphertext, &ciphertext_len,
2178 									&ad, &ad_len,
2179 									&npub, &npub_len,
2180 									&secretkey, &secretkey_len) == FAILURE) {
2181 		sodium_remove_param_values_from_backtrace(EG(exception));
2182 		RETURN_THROWS();
2183 	}
2184 	if (npub_len != crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) {
2185 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes long");
2186 		RETURN_THROWS();
2187 	}
2188 	if (secretkey_len != crypto_aead_xchacha20poly1305_IETF_KEYBYTES) {
2189 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES bytes long");
2190 		RETURN_THROWS();
2191 	}
2192 	if (ciphertext_len < crypto_aead_xchacha20poly1305_IETF_ABYTES) {
2193 		RETURN_FALSE;
2194 	}
2195 	msg_len = ciphertext_len;
2196 	if (msg_len - crypto_aead_xchacha20poly1305_IETF_ABYTES >= SIZE_MAX) {
2197 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2198 		RETURN_THROWS();
2199 	}
2200 	if ((unsigned long long) ciphertext_len -
2201 		crypto_aead_xchacha20poly1305_IETF_ABYTES > 64ULL * (1ULL << 32) - 64ULL) {
2202 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2203 		RETURN_THROWS();
2204 	}
2205 	msg = zend_string_alloc((size_t) msg_len, 0);
2206 	if (crypto_aead_xchacha20poly1305_ietf_decrypt
2207 		((unsigned char *) ZSTR_VAL(msg), &msg_real_len, NULL,
2208 		 ciphertext, (unsigned long long) ciphertext_len,
2209 		 ad, (unsigned long long) ad_len, npub, secretkey) != 0) {
2210 		zend_string_efree(msg);
2211 		RETURN_FALSE;
2212 	}
2213 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
2214 		zend_string_efree(msg);
2215 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2216 		RETURN_THROWS();
2217 	}
2218 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
2219 	ZSTR_VAL(msg)[msg_real_len] = 0;
2220 
2221 	RETURN_NEW_STR(msg);
2222 }
2223 #endif
2224 
PHP_FUNCTION(sodium_bin2hex)2225 PHP_FUNCTION(sodium_bin2hex)
2226 {
2227 	zend_string   *hex;
2228 	unsigned char *bin;
2229 	size_t         bin_len;
2230 	size_t         hex_len;
2231 
2232 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2233 									&bin, &bin_len) == FAILURE) {
2234 		sodium_remove_param_values_from_backtrace(EG(exception));
2235 		RETURN_THROWS();
2236 	}
2237 	if (bin_len >= SIZE_MAX / 2U) {
2238 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2239 		RETURN_THROWS();
2240 	}
2241 	hex_len = bin_len * 2U;
2242 	hex = zend_string_alloc((size_t) hex_len, 0);
2243 	sodium_bin2hex(ZSTR_VAL(hex), hex_len + 1U, bin, bin_len);
2244 	ZSTR_VAL(hex)[hex_len] = 0;
2245 
2246 	RETURN_STR(hex);
2247 }
2248 
PHP_FUNCTION(sodium_hex2bin)2249 PHP_FUNCTION(sodium_hex2bin)
2250 {
2251 	zend_string   *bin;
2252 	const char    *end;
2253 	char          *hex;
2254 	char          *ignore = NULL;
2255 	size_t         bin_real_len;
2256 	size_t         bin_len;
2257 	size_t         hex_len;
2258 	size_t         ignore_len = 0;
2259 
2260 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s",
2261 									&hex, &hex_len,
2262 									&ignore, &ignore_len) == FAILURE) {
2263 		sodium_remove_param_values_from_backtrace(EG(exception));
2264 		RETURN_THROWS();
2265 	}
2266 	bin_len = hex_len / 2;
2267 	bin = zend_string_alloc(bin_len, 0);
2268 	if (sodium_hex2bin((unsigned char *) ZSTR_VAL(bin), bin_len, hex, hex_len,
2269 					   ignore, &bin_real_len, &end) != 0 ||
2270 		end != hex + hex_len) {
2271 		zend_string_efree(bin);
2272 		zend_argument_error(sodium_exception_ce, 1, "must be a valid hexadecimal string");
2273 		RETURN_THROWS();
2274 	}
2275 	if (bin_real_len >= SIZE_MAX || bin_real_len > bin_len) {
2276 		zend_string_efree(bin);
2277 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2278 		RETURN_THROWS();
2279 	}
2280 	PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len);
2281 	ZSTR_VAL(bin)[bin_real_len] = 0;
2282 
2283 	RETURN_NEW_STR(bin);
2284 }
2285 
2286 #ifdef sodium_base64_VARIANT_ORIGINAL
PHP_FUNCTION(sodium_bin2base64)2287 PHP_FUNCTION(sodium_bin2base64)
2288 {
2289 	zend_string   *b64;
2290 	unsigned char *bin;
2291 	zend_long      variant;
2292 	size_t         bin_len;
2293 	size_t         b64_len;
2294 
2295 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
2296 									&bin, &bin_len, &variant) == FAILURE) {
2297 		sodium_remove_param_values_from_backtrace(EG(exception));
2298 		RETURN_THROWS();
2299 	}
2300 	if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) {
2301 		zend_argument_error(sodium_exception_ce, 2, "must be a valid base64 variant identifier");
2302 		RETURN_THROWS();
2303 	}
2304 	if (bin_len >= SIZE_MAX / 4U * 3U - 3U - 1U) {
2305 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2306 		RETURN_THROWS();
2307 	}
2308 	b64_len = sodium_base64_ENCODED_LEN(bin_len, variant);
2309 	b64 = zend_string_alloc((size_t) b64_len - 1U, 0);
2310 	sodium_bin2base64(ZSTR_VAL(b64), b64_len, bin, bin_len, (int) variant);
2311 
2312 	RETURN_STR(b64);
2313 }
2314 
PHP_FUNCTION(sodium_base642bin)2315 PHP_FUNCTION(sodium_base642bin)
2316 {
2317 	zend_string   *bin;
2318 	char          *b64;
2319 	const char    *end;
2320 	char          *ignore = NULL;
2321 	zend_long      variant;
2322 	size_t         bin_real_len;
2323 	size_t         bin_len;
2324 	size_t         b64_len;
2325 	size_t         ignore_len = 0;
2326 
2327 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s",
2328 									&b64, &b64_len, &variant,
2329 									&ignore, &ignore_len) == FAILURE) {
2330 		sodium_remove_param_values_from_backtrace(EG(exception));
2331 		RETURN_THROWS();
2332 	}
2333 	if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) {
2334 		zend_argument_error(sodium_exception_ce, 2, "must be a valid base64 variant identifier");
2335 		RETURN_THROWS();
2336 	}
2337 	bin_len = b64_len / 4U * 3U + 2U;
2338 	bin = zend_string_alloc(bin_len, 0);
2339 	if (sodium_base642bin((unsigned char *) ZSTR_VAL(bin), bin_len,
2340 						  b64, b64_len,
2341 						  ignore, &bin_real_len, &end, (int) variant) != 0 ||
2342 		end != b64 + b64_len) {
2343 		zend_string_efree(bin);
2344 		zend_argument_error(sodium_exception_ce, 1, "must be a valid base64 string");
2345 		RETURN_THROWS();
2346 	}
2347 	if (bin_real_len >= SIZE_MAX || bin_real_len > bin_len) {
2348 		zend_string_efree(bin);
2349 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
2350 		RETURN_THROWS();
2351 	}
2352 	PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len);
2353 	ZSTR_VAL(bin)[bin_real_len] = 0;
2354 
2355 	RETURN_NEW_STR(bin);
2356 }
2357 #endif
2358 
PHP_FUNCTION(sodium_crypto_scalarmult)2359 PHP_FUNCTION(sodium_crypto_scalarmult)
2360 {
2361 	zend_string   *q;
2362 	unsigned char *n;
2363 	unsigned char *p;
2364 	size_t         n_len;
2365 	size_t         p_len;
2366 
2367 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2368 									&n, &n_len, &p, &p_len) == FAILURE) {
2369 		sodium_remove_param_values_from_backtrace(EG(exception));
2370 		RETURN_THROWS();
2371 	}
2372 	if (n_len != crypto_scalarmult_SCALARBYTES) {
2373 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SCALARMULT_SCALARBYTES bytes long");
2374 		RETURN_THROWS();
2375 	}
2376 	if (p_len != crypto_scalarmult_BYTES) {
2377 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SCALARMULT_SCALARBYTES bytes long");
2378 		RETURN_THROWS();
2379 	}
2380 	q = zend_string_alloc(crypto_scalarmult_BYTES, 0);
2381 	if (crypto_scalarmult((unsigned char *) ZSTR_VAL(q), n, p) != 0) {
2382 		zend_string_efree(q);
2383 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2384 		RETURN_THROWS();
2385 	}
2386 	ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0;
2387 
2388 	RETURN_NEW_STR(q);
2389 }
2390 
2391 #ifdef crypto_core_ristretto255_HASHBYTES
PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255)2392 PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255)
2393 {
2394 	zend_string   *q;
2395 	unsigned char *n;
2396 	unsigned char *p;
2397 	size_t         n_len;
2398 	size_t         p_len;
2399 
2400 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2401 									&n, &n_len, &p, &p_len) == FAILURE) {
2402 		sodium_remove_param_values_from_backtrace(EG(exception));
2403 		RETURN_THROWS();
2404 	}
2405 	if (n_len != crypto_scalarmult_ristretto255_SCALARBYTES) {
2406 		zend_argument_error(sodium_exception_ce, 1,
2407 							"must be SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES bytes long");
2408 		RETURN_THROWS();
2409 	}
2410 	if (p_len != crypto_scalarmult_ristretto255_BYTES) {
2411 		zend_argument_error(sodium_exception_ce, 2,
2412 							"must be SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES bytes long");
2413 		RETURN_THROWS();
2414 	}
2415 	q = zend_string_alloc(crypto_scalarmult_ristretto255_BYTES, 0);
2416 	if (crypto_scalarmult_ristretto255((unsigned char *) ZSTR_VAL(q), n, p) != 0) {
2417 		zend_string_efree(q);
2418 		zend_throw_exception(sodium_exception_ce, "Result is identity element", 0);
2419 		RETURN_THROWS();
2420 	}
2421 	ZSTR_VAL(q)[crypto_scalarmult_ristretto255_BYTES] = 0;
2422 
2423 	RETURN_NEW_STR(q);
2424 }
2425 
PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255_base)2426 PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255_base)
2427 {
2428 	zend_string   *q;
2429 	unsigned char *n;
2430 	size_t         n_len;
2431 
2432 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2433 							  &n, &n_len) == FAILURE) {
2434 		sodium_remove_param_values_from_backtrace(EG(exception));
2435 		RETURN_THROWS();
2436 	}
2437 	if (n_len != crypto_scalarmult_ristretto255_SCALARBYTES) {
2438 		zend_argument_error(sodium_exception_ce, 1,
2439 							"must be SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES bytes long");
2440 		RETURN_THROWS();
2441 	}
2442 	q = zend_string_alloc(crypto_scalarmult_ristretto255_BYTES, 0);
2443 	if (crypto_scalarmult_ristretto255_base((unsigned char *) ZSTR_VAL(q), n) != 0) {
2444 		zend_string_efree(q);
2445 		zend_argument_error(sodium_exception_ce, 1, "must not be zero", 0);
2446 		RETURN_THROWS();
2447 	}
2448 	ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0;
2449 
2450 	RETURN_NEW_STR(q);
2451 }
2452 #endif
2453 
PHP_FUNCTION(sodium_crypto_kx_seed_keypair)2454 PHP_FUNCTION(sodium_crypto_kx_seed_keypair)
2455 {
2456 	unsigned char *sk;
2457 	unsigned char *pk;
2458 	unsigned char *seed;
2459 	size_t         seed_len;
2460 	zend_string   *keypair;
2461 
2462 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2463 									&seed, &seed_len) == FAILURE) {
2464 		sodium_remove_param_values_from_backtrace(EG(exception));
2465 		RETURN_THROWS();
2466 	}
2467 	if (seed_len != crypto_kx_SEEDBYTES) {
2468 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_SEEDBYTES bytes long");
2469 		RETURN_THROWS();
2470 	}
2471 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2472 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2473 	keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0);
2474 	sk = (unsigned char *) ZSTR_VAL(keypair);
2475 	pk = sk + crypto_kx_SECRETKEYBYTES;
2476 	crypto_generichash(sk, crypto_kx_SECRETKEYBYTES,
2477 					   seed, crypto_kx_SEEDBYTES, NULL, 0);
2478 	if (crypto_scalarmult_base(pk, sk) != 0) {
2479 		zend_string_efree(keypair);
2480 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2481 		RETURN_THROWS();
2482 	}
2483 	ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0;
2484 	RETURN_STR(keypair);
2485 }
2486 
PHP_FUNCTION(sodium_crypto_kx_keypair)2487 PHP_FUNCTION(sodium_crypto_kx_keypair)
2488 {
2489 	unsigned char *sk;
2490 	unsigned char *pk;
2491 	zend_string   *keypair;
2492 
2493 	if (zend_parse_parameters_none() == FAILURE) {
2494 		RETURN_THROWS();
2495 	}
2496 	keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0);
2497 	sk = (unsigned char *) ZSTR_VAL(keypair);
2498 	pk = sk + crypto_kx_SECRETKEYBYTES;
2499 	randombytes_buf(sk, crypto_kx_SECRETKEYBYTES);
2500 	if (crypto_scalarmult_base(pk, sk) != 0) {
2501 		zend_string_efree(keypair);
2502 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2503 		RETURN_THROWS();
2504 	}
2505 	ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0;
2506 	RETURN_STR(keypair);
2507 }
2508 
PHP_FUNCTION(sodium_crypto_kx_secretkey)2509 PHP_FUNCTION(sodium_crypto_kx_secretkey)
2510 {
2511 	zend_string   *secretkey;
2512 	unsigned char *keypair;
2513 	size_t         keypair_len;
2514 
2515 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2516 									&keypair, &keypair_len) == FAILURE) {
2517 		sodium_remove_param_values_from_backtrace(EG(exception));
2518 		RETURN_THROWS();
2519 	}
2520 	if (keypair_len !=
2521 		crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2522 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2523 		RETURN_THROWS();
2524 	}
2525 	secretkey = zend_string_alloc(crypto_kx_SECRETKEYBYTES, 0);
2526 	memcpy(ZSTR_VAL(secretkey), keypair, crypto_kx_SECRETKEYBYTES);
2527 	ZSTR_VAL(secretkey)[crypto_kx_SECRETKEYBYTES] = 0;
2528 
2529 	RETURN_STR(secretkey);
2530 }
2531 
PHP_FUNCTION(sodium_crypto_kx_publickey)2532 PHP_FUNCTION(sodium_crypto_kx_publickey)
2533 {
2534 	zend_string   *publickey;
2535 	unsigned char *keypair;
2536 	size_t         keypair_len;
2537 
2538 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2539 									&keypair, &keypair_len) == FAILURE) {
2540 		sodium_remove_param_values_from_backtrace(EG(exception));
2541 		RETURN_THROWS();
2542 	}
2543 	if (keypair_len !=
2544 		crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2545 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2546 		RETURN_THROWS();
2547 	}
2548 	publickey = zend_string_alloc(crypto_kx_PUBLICKEYBYTES, 0);
2549 	memcpy(ZSTR_VAL(publickey), keypair + crypto_kx_SECRETKEYBYTES,
2550 		   crypto_kx_PUBLICKEYBYTES);
2551 	ZSTR_VAL(publickey)[crypto_kx_PUBLICKEYBYTES] = 0;
2552 
2553 	RETURN_STR(publickey);
2554 }
2555 
PHP_FUNCTION(sodium_crypto_kx_client_session_keys)2556 PHP_FUNCTION(sodium_crypto_kx_client_session_keys)
2557 {
2558 	crypto_generichash_state h;
2559 	unsigned char  q[crypto_scalarmult_BYTES];
2560 	unsigned char *keypair;
2561 	unsigned char *client_sk;
2562 	unsigned char *client_pk;
2563 	unsigned char *server_pk;
2564 	unsigned char  session_keys[2 * crypto_kx_SESSIONKEYBYTES];
2565 	size_t         keypair_len;
2566 	size_t         server_pk_len;
2567 
2568 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2569 									&keypair, &keypair_len,
2570 									&server_pk, &server_pk_len) == FAILURE) {
2571 		sodium_remove_param_values_from_backtrace(EG(exception));
2572 		RETURN_THROWS();
2573 	}
2574 	if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2575 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2576 		RETURN_THROWS();
2577 	}
2578 	if (server_pk_len != crypto_kx_PUBLICKEYBYTES) {
2579 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes long");
2580 		RETURN_THROWS();
2581 	}
2582 	client_sk = &keypair[0];
2583 	client_pk = &keypair[crypto_kx_SECRETKEYBYTES];
2584 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2585 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2586 	if (crypto_scalarmult(q, client_sk, server_pk) != 0) {
2587 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2588 		RETURN_THROWS();
2589 	}
2590 	crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES);
2591 	crypto_generichash_update(&h, q, sizeof q);
2592 	sodium_memzero(q, sizeof q);
2593 	crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES);
2594 	crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES);
2595 	crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES);
2596 	sodium_memzero(&h, sizeof h);
2597 	array_init(return_value);
2598 	add_next_index_stringl(return_value,
2599 						   (const char *) session_keys,
2600 						   crypto_kx_SESSIONKEYBYTES);
2601 	add_next_index_stringl(return_value,
2602 						   (const char *) session_keys + crypto_kx_SESSIONKEYBYTES,
2603 						   crypto_kx_SESSIONKEYBYTES);
2604 }
2605 
PHP_FUNCTION(sodium_crypto_kx_server_session_keys)2606 PHP_FUNCTION(sodium_crypto_kx_server_session_keys)
2607 {
2608 	crypto_generichash_state h;
2609 	unsigned char  q[crypto_scalarmult_BYTES];
2610 	unsigned char *keypair;
2611 	unsigned char *server_sk;
2612 	unsigned char *server_pk;
2613 	unsigned char *client_pk;
2614 	unsigned char  session_keys[2 * crypto_kx_SESSIONKEYBYTES];
2615 	size_t         keypair_len;
2616 	size_t         client_pk_len;
2617 
2618 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2619 									&keypair, &keypair_len,
2620 									&client_pk, &client_pk_len) == FAILURE) {
2621 		sodium_remove_param_values_from_backtrace(EG(exception));
2622 		RETURN_THROWS();
2623 	}
2624 	if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) {
2625 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes long");
2626 		RETURN_THROWS();
2627 	}
2628 	if (client_pk_len != crypto_kx_PUBLICKEYBYTES) {
2629 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes long");
2630 		RETURN_THROWS();
2631 	}
2632 	server_sk = &keypair[0];
2633 	server_pk = &keypair[crypto_kx_SECRETKEYBYTES];
2634 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]);
2635 	(void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]);
2636 	if (crypto_scalarmult(q, server_sk, client_pk) != 0) {
2637 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2638 		RETURN_THROWS();
2639 	}
2640 	crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES);
2641 	crypto_generichash_update(&h, q, sizeof q);
2642 	sodium_memzero(q, sizeof q);
2643 	crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES);
2644 	crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES);
2645 	crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES);
2646 	sodium_memzero(&h, sizeof h);
2647 	array_init(return_value);
2648 	add_next_index_stringl(return_value,
2649 						   (const char *) session_keys + crypto_kx_SESSIONKEYBYTES,
2650 						   crypto_kx_SESSIONKEYBYTES);
2651 	add_next_index_stringl(return_value,
2652 						   (const char *) session_keys,
2653 						   crypto_kx_SESSIONKEYBYTES);
2654 }
2655 
PHP_FUNCTION(sodium_crypto_auth)2656 PHP_FUNCTION(sodium_crypto_auth)
2657 {
2658 	zend_string *mac;
2659 	char        *key;
2660 	char        *msg;
2661 	size_t       msg_len;
2662 	size_t       key_len;
2663 
2664 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2665 									&msg, &msg_len,
2666 									&key, &key_len) == FAILURE) {
2667 		sodium_remove_param_values_from_backtrace(EG(exception));
2668 		RETURN_THROWS();
2669 	}
2670 	if (key_len != crypto_auth_KEYBYTES) {
2671 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes long");
2672 		RETURN_THROWS();
2673 	}
2674 	mac = zend_string_alloc(crypto_auth_BYTES, 0);
2675 	if (crypto_auth((unsigned char *) ZSTR_VAL(mac),
2676 					(const unsigned char *) msg, msg_len,
2677 					(const unsigned char *) key) != 0) {
2678 		zend_string_efree(mac);
2679 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
2680 		RETURN_THROWS();
2681 	}
2682 	ZSTR_VAL(mac)[crypto_auth_BYTES] = 0;
2683 
2684 	RETURN_STR(mac);
2685 }
2686 
PHP_FUNCTION(sodium_crypto_auth_verify)2687 PHP_FUNCTION(sodium_crypto_auth_verify)
2688 {
2689 	char      *mac;
2690 	char      *key;
2691 	char      *msg;
2692 	size_t     mac_len;
2693 	size_t     msg_len;
2694 	size_t     key_len;
2695 
2696 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
2697 									&mac, &mac_len,
2698 									&msg, &msg_len,
2699 									&key, &key_len) == FAILURE) {
2700 		sodium_remove_param_values_from_backtrace(EG(exception));
2701 		RETURN_THROWS();
2702 	}
2703 	if (key_len != crypto_auth_KEYBYTES) {
2704 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_AUTH_KEYBYTES bytes long");
2705 		RETURN_THROWS();
2706 	}
2707 	if (mac_len != crypto_auth_BYTES) {
2708 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_AUTH_BYTES bytes long");
2709 		RETURN_THROWS();
2710 	}
2711 	if (crypto_auth_verify((const unsigned char *) mac,
2712 						   (const unsigned char *) msg, msg_len,
2713 						   (const unsigned char *) key) != 0) {
2714 		RETURN_FALSE;
2715 	}
2716 	RETURN_TRUE;
2717 }
2718 
PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)2719 PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)
2720 {
2721 	zend_string *ecdhkey;
2722 	char        *eddsakey;
2723 	size_t       eddsakey_len;
2724 
2725 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2726 									&eddsakey, &eddsakey_len) == FAILURE) {
2727 		sodium_remove_param_values_from_backtrace(EG(exception));
2728 		RETURN_THROWS();
2729 	}
2730 	if (eddsakey_len != crypto_sign_SECRETKEYBYTES) {
2731 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes long");
2732 		RETURN_THROWS();
2733 	}
2734 	ecdhkey = zend_string_alloc(crypto_box_SECRETKEYBYTES, 0);
2735 
2736 	if (crypto_sign_ed25519_sk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey),
2737 											 (const unsigned char *) eddsakey) != 0) {
2738 		zend_string_efree(ecdhkey);
2739 		zend_throw_exception(sodium_exception_ce, "conversion failed", 0);
2740 		RETURN_THROWS();
2741 	}
2742 	ZSTR_VAL(ecdhkey)[crypto_box_SECRETKEYBYTES] = 0;
2743 
2744 	RETURN_STR(ecdhkey);
2745 }
2746 
PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519)2747 PHP_FUNCTION(sodium_crypto_sign_ed25519_pk_to_curve25519)
2748 {
2749 	zend_string *ecdhkey;
2750 	char        *eddsakey;
2751 	size_t       eddsakey_len;
2752 
2753 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
2754 									&eddsakey, &eddsakey_len) == FAILURE) {
2755 		sodium_remove_param_values_from_backtrace(EG(exception));
2756 		RETURN_THROWS();
2757 	}
2758 	if (eddsakey_len != crypto_sign_PUBLICKEYBYTES) {
2759 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes long");
2760 		RETURN_THROWS();
2761 	}
2762 	ecdhkey = zend_string_alloc(crypto_sign_PUBLICKEYBYTES, 0);
2763 
2764 	if (crypto_sign_ed25519_pk_to_curve25519((unsigned char *) ZSTR_VAL(ecdhkey),
2765 											 (const unsigned char *) eddsakey) != 0) {
2766 		zend_string_efree(ecdhkey);
2767 		zend_throw_exception(sodium_exception_ce, "conversion failed", 0);
2768 		RETURN_THROWS();
2769 	}
2770 	ZSTR_VAL(ecdhkey)[crypto_box_PUBLICKEYBYTES] = 0;
2771 
2772 	RETURN_STR(ecdhkey);
2773 }
2774 
PHP_FUNCTION(sodium_compare)2775 PHP_FUNCTION(sodium_compare)
2776 {
2777 	char      *buf1;
2778 	char      *buf2;
2779 	size_t     len1;
2780 	size_t     len2;
2781 
2782 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2783 									&buf1, &len1,
2784 									&buf2, &len2) == FAILURE) {
2785 		sodium_remove_param_values_from_backtrace(EG(exception));
2786 		RETURN_THROWS();
2787 	}
2788 	if (len1 != len2) {
2789 		zend_argument_error(sodium_exception_ce, 1, "and argument #2 ($string_2) must have the same length");
2790 		RETURN_THROWS();
2791 	} else {
2792 		RETURN_LONG(sodium_compare((const unsigned char *) buf1,
2793 								   (const unsigned char *) buf2, (size_t) len1));
2794 	}
2795 }
2796 
2797 #ifdef HAVE_AESGCM
PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen)2798 PHP_FUNCTION(sodium_crypto_aead_aes256gcm_keygen)
2799 {
2800 	unsigned char key[crypto_aead_aes256gcm_KEYBYTES];
2801 
2802 	if (zend_parse_parameters_none() == FAILURE) {
2803 		RETURN_THROWS();
2804 	}
2805 	randombytes_buf(key, sizeof key);
2806 	RETURN_STRINGL((const char *) key, sizeof key);
2807 }
2808 #endif
2809 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen)2810 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_keygen)
2811 {
2812 	unsigned char key[crypto_aead_chacha20poly1305_KEYBYTES];
2813 
2814 	if (zend_parse_parameters_none() == FAILURE) {
2815 		RETURN_THROWS();
2816 	}
2817 	randombytes_buf(key, sizeof key);
2818 	RETURN_STRINGL((const char *) key, sizeof key);
2819 }
2820 
PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen)2821 PHP_FUNCTION(sodium_crypto_aead_chacha20poly1305_ietf_keygen)
2822 {
2823 	unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES];
2824 
2825 	if (zend_parse_parameters_none() == FAILURE) {
2826 		RETURN_THROWS();
2827 	}
2828 	randombytes_buf(key, sizeof key);
2829 	RETURN_STRINGL((const char *) key, sizeof key);
2830 }
2831 
2832 #ifdef crypto_aead_xchacha20poly1305_IETF_NPUBBYTES
PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen)2833 PHP_FUNCTION(sodium_crypto_aead_xchacha20poly1305_ietf_keygen)
2834 {
2835 	unsigned char key[crypto_aead_xchacha20poly1305_IETF_KEYBYTES];
2836 
2837 	if (zend_parse_parameters_none() == FAILURE) {
2838 		RETURN_THROWS();
2839 	}
2840 	randombytes_buf(key, sizeof key);
2841 	RETURN_STRINGL((const char *) key, sizeof key);
2842 }
2843 #endif
2844 
PHP_FUNCTION(sodium_crypto_auth_keygen)2845 PHP_FUNCTION(sodium_crypto_auth_keygen)
2846 {
2847 	unsigned char key[crypto_auth_KEYBYTES];
2848 
2849 	if (zend_parse_parameters_none() == FAILURE) {
2850 		RETURN_THROWS();
2851 	}
2852 	randombytes_buf(key, sizeof key);
2853 	RETURN_STRINGL((const char *) key, sizeof key);
2854 }
2855 
PHP_FUNCTION(sodium_crypto_generichash_keygen)2856 PHP_FUNCTION(sodium_crypto_generichash_keygen)
2857 {
2858 	unsigned char key[crypto_generichash_KEYBYTES];
2859 
2860 	if (zend_parse_parameters_none() == FAILURE) {
2861 		RETURN_THROWS();
2862 	}
2863 	randombytes_buf(key, sizeof key);
2864 	RETURN_STRINGL((const char *) key, sizeof key);
2865 }
2866 
PHP_FUNCTION(sodium_crypto_kdf_keygen)2867 PHP_FUNCTION(sodium_crypto_kdf_keygen)
2868 {
2869 	unsigned char key[crypto_kdf_KEYBYTES];
2870 
2871 	if (zend_parse_parameters_none() == FAILURE) {
2872 		RETURN_THROWS();
2873 	}
2874 	randombytes_buf(key, sizeof key);
2875 	RETURN_STRINGL((const char *) key, sizeof key);
2876 }
2877 
PHP_FUNCTION(sodium_crypto_secretbox_keygen)2878 PHP_FUNCTION(sodium_crypto_secretbox_keygen)
2879 {
2880 	unsigned char key[crypto_secretbox_KEYBYTES];
2881 
2882 	if (zend_parse_parameters_none() == FAILURE) {
2883 		RETURN_THROWS();
2884 	}
2885 	randombytes_buf(key, sizeof key);
2886 	RETURN_STRINGL((const char *) key, sizeof key);
2887 }
2888 
PHP_FUNCTION(sodium_crypto_shorthash_keygen)2889 PHP_FUNCTION(sodium_crypto_shorthash_keygen)
2890 {
2891 	unsigned char key[crypto_shorthash_KEYBYTES];
2892 
2893 	if (zend_parse_parameters_none() == FAILURE) {
2894 		RETURN_THROWS();
2895 	}
2896 	randombytes_buf(key, sizeof key);
2897 	RETURN_STRINGL((const char *) key, sizeof key);
2898 }
2899 
PHP_FUNCTION(sodium_crypto_stream_keygen)2900 PHP_FUNCTION(sodium_crypto_stream_keygen)
2901 {
2902 	unsigned char key[crypto_stream_KEYBYTES];
2903 
2904 	if (zend_parse_parameters_none() == FAILURE) {
2905 		RETURN_THROWS();
2906 	}
2907 	randombytes_buf(key, sizeof key);
2908 	RETURN_STRINGL((const char *) key, sizeof key);
2909 }
2910 #ifdef crypto_stream_xchacha20_KEYBYTES
PHP_FUNCTION(sodium_crypto_stream_xchacha20_keygen)2911 PHP_FUNCTION(sodium_crypto_stream_xchacha20_keygen)
2912 {
2913 	unsigned char key[crypto_stream_xchacha20_KEYBYTES];
2914 
2915 	if (zend_parse_parameters_none() == FAILURE) {
2916 		return;
2917 	}
2918 	randombytes_buf(key, sizeof key);
2919 	RETURN_STRINGL((const char *) key, sizeof key);
2920 }
2921 #endif
2922 
PHP_FUNCTION(sodium_crypto_kdf_derive_from_key)2923 PHP_FUNCTION(sodium_crypto_kdf_derive_from_key)
2924 {
2925 	unsigned char  ctx_padded[crypto_generichash_blake2b_PERSONALBYTES];
2926 #ifndef crypto_kdf_PRIMITIVE
2927 	unsigned char  salt[crypto_generichash_blake2b_SALTBYTES];
2928 #endif
2929 	char          *ctx;
2930 	char          *key;
2931 	zend_string   *subkey;
2932 	zend_long      subkey_id;
2933 	zend_long      subkey_len;
2934 	size_t         ctx_len;
2935 	size_t         key_len;
2936 
2937 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "llss",
2938 									&subkey_len,
2939 									&subkey_id,
2940 									&ctx, &ctx_len,
2941 									&key, &key_len) == FAILURE) {
2942 		sodium_remove_param_values_from_backtrace(EG(exception));
2943 		RETURN_THROWS();
2944 	}
2945 	if (subkey_len < crypto_kdf_BYTES_MIN) {
2946 		zend_argument_error(sodium_exception_ce, 1, "must be greater than or equal to SODIUM_CRYPTO_KDF_BYTES_MIN");
2947 		RETURN_THROWS();
2948 	}
2949 	if (subkey_len > crypto_kdf_BYTES_MAX || subkey_len > SIZE_MAX) {
2950 		zend_argument_error(sodium_exception_ce, 1, "must be less than or equal to SODIUM_CRYPTO_KDF_BYTES_MAX");
2951 		RETURN_THROWS();
2952 	}
2953 	if (subkey_id < 0) {
2954 		zend_argument_error(sodium_exception_ce, 2, "must be greater than or equal to 0");
2955 		RETURN_THROWS();
2956 	}
2957 	if (ctx_len != crypto_kdf_CONTEXTBYTES) {
2958 		zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes long");
2959 		RETURN_THROWS();
2960 	}
2961 	if (key_len != crypto_kdf_KEYBYTES) {
2962 		zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_KDF_BYTES_MIN bytes long");
2963 		RETURN_THROWS();
2964 	}
2965 	memcpy(ctx_padded, ctx, crypto_kdf_CONTEXTBYTES);
2966 	memset(ctx_padded + crypto_kdf_CONTEXTBYTES, 0, sizeof ctx_padded - crypto_kdf_CONTEXTBYTES);
2967 	subkey = zend_string_alloc((size_t) subkey_len, 0);
2968 #ifdef crypto_kdf_PRIMITIVE
2969 	crypto_kdf_derive_from_key((unsigned char *) ZSTR_VAL(subkey),
2970 							   (size_t) subkey_len, (uint64_t) subkey_id,
2971 							   ctx, (const unsigned char *) key);
2972 #else
2973 	salt[0] = (unsigned char) (((uint64_t) subkey_id)      );
2974 	salt[1] = (unsigned char) (((uint64_t) subkey_id) >>  8);
2975 	salt[2] = (unsigned char) (((uint64_t) subkey_id) >> 16);
2976 	salt[3] = (unsigned char) (((uint64_t) subkey_id) >> 24);
2977 	salt[4] = (unsigned char) (((uint64_t) subkey_id) >> 32);
2978 	salt[5] = (unsigned char) (((uint64_t) subkey_id) >> 40);
2979 	salt[6] = (unsigned char) (((uint64_t) subkey_id) >> 48);
2980 	salt[7] = (unsigned char) (((uint64_t) subkey_id) >> 56);
2981 	memset(salt + 8, 0, (sizeof salt) - 8);
2982 	crypto_generichash_blake2b_salt_personal((unsigned char *) ZSTR_VAL(subkey),
2983 											 (size_t) subkey_len,
2984 											 NULL, 0,
2985 											 (const unsigned char *) key,
2986 											 crypto_kdf_KEYBYTES,
2987 											 salt, ctx_padded);
2988 #endif
2989 	ZSTR_VAL(subkey)[subkey_len] = 0;
2990 
2991 	RETURN_STR(subkey);
2992 }
2993 
PHP_FUNCTION(sodium_pad)2994 PHP_FUNCTION(sodium_pad)
2995 {
2996 	zend_string    *padded;
2997 	char           *unpadded;
2998 	zend_long       blocksize;
2999 	volatile size_t st;
3000 	size_t          i, j, k;
3001 	size_t          unpadded_len;
3002 	size_t          xpadlen;
3003 	size_t          xpadded_len;
3004 
3005 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
3006 									&unpadded, &unpadded_len, &blocksize) == FAILURE) {
3007 		sodium_remove_param_values_from_backtrace(EG(exception));
3008 		RETURN_THROWS();
3009 	}
3010 	if (blocksize <= 0) {
3011 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
3012 		RETURN_THROWS();
3013 	}
3014 	if (blocksize > SIZE_MAX) {
3015 		zend_argument_error(sodium_exception_ce, 2, "is too large");
3016 		RETURN_THROWS();
3017 	}
3018 	xpadlen = blocksize - 1U;
3019 	if ((blocksize & (blocksize - 1U)) == 0U) {
3020 		xpadlen -= unpadded_len & ((size_t) blocksize - 1U);
3021 	} else {
3022 		xpadlen -= unpadded_len % (size_t) blocksize;
3023 	}
3024 	if ((size_t) SIZE_MAX - unpadded_len <= xpadlen) {
3025 		zend_throw_exception(sodium_exception_ce, "input is too large", 0);
3026 		RETURN_THROWS();
3027 	}
3028 	xpadded_len = unpadded_len + xpadlen;
3029 	padded = zend_string_alloc(xpadded_len + 1U, 0);
3030 	if (unpadded_len > 0) {
3031 		st = 1U;
3032 		i = 0U;
3033 		k = unpadded_len;
3034 		for (j = 0U; j <= xpadded_len; j++) {
3035 			ZSTR_VAL(padded)[j] = unpadded[i];
3036 			k -= st;
3037 			st = (size_t) (~(((( (((uint64_t) k) >> 48) | (((uint64_t) k) >> 32) |
3038 								 (k >> 16) | k) & 0xffff) - 1U) >> 16)) & 1U;
3039 			i += st;
3040 		}
3041 	}
3042 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
3043 	if (sodium_pad(NULL, (unsigned char *) ZSTR_VAL(padded), unpadded_len,
3044 				   (size_t) blocksize, xpadded_len + 1U) != 0) {
3045 		zend_string_efree(padded);
3046 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3047 		RETURN_THROWS();
3048 	}
3049 #else
3050 	{
3051 		char                   *tail;
3052 		volatile unsigned char  mask;
3053 		unsigned char           barrier_mask;
3054 
3055 		tail = &ZSTR_VAL(padded)[xpadded_len];
3056 		mask = 0U;
3057 		for (i = 0; i < blocksize; i++) {
3058 			barrier_mask = (unsigned char)
3059 				(((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
3060 			tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
3061 			mask |= barrier_mask;
3062 		}
3063 	}
3064 #endif
3065 	ZSTR_VAL(padded)[xpadded_len + 1U] = 0;
3066 
3067 	RETURN_STR(padded);
3068 }
3069 
PHP_FUNCTION(sodium_unpad)3070 PHP_FUNCTION(sodium_unpad)
3071 {
3072 	zend_string *unpadded;
3073 	char        *padded;
3074 	size_t       padded_len;
3075 	size_t       unpadded_len;
3076 	zend_long    blocksize;
3077 	int          ret;
3078 
3079 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
3080 									&padded, &padded_len, &blocksize) == FAILURE) {
3081 		sodium_remove_param_values_from_backtrace(EG(exception));
3082 		RETURN_THROWS();
3083 	}
3084 	if (blocksize <= 0) {
3085 		zend_argument_error(sodium_exception_ce, 2, "must be greater than 0");
3086 		RETURN_THROWS();
3087 	}
3088 	if (blocksize > SIZE_MAX) {
3089 		zend_argument_error(sodium_exception_ce, 2, "is too large");
3090 		RETURN_THROWS();
3091 	}
3092 	if (padded_len < blocksize) {
3093 		zend_argument_error(sodium_exception_ce, 1, "must be at least as long as the block size");
3094 		RETURN_THROWS();
3095 	}
3096 
3097 #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6)
3098 	ret = sodium_unpad(&unpadded_len, (const unsigned char *) padded,
3099 					   padded_len, (size_t) blocksize);
3100 #else
3101 	{
3102 		const char      *tail;
3103 		unsigned char    acc = 0U;
3104 		unsigned char    c;
3105 		unsigned char    valid = 0U;
3106 		volatile size_t  pad_len = 0U;
3107 		size_t           i;
3108 		size_t           is_barrier;
3109 
3110 		tail = &padded[padded_len - 1U];
3111 
3112 		for (i = 0U; i < (size_t) blocksize; i++) {
3113 			c = tail[-i];
3114 			is_barrier =
3115 				(( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
3116 			acc |= c;
3117 			pad_len |= i & (1U + ~is_barrier);
3118 			valid |= (unsigned char) is_barrier;
3119 		}
3120 		unpadded_len = padded_len - 1U - pad_len;
3121 		ret = (int) (valid - 1U);
3122 	}
3123 #endif
3124 	if (ret != 0 || unpadded_len > LONG_MAX) {
3125 		zend_throw_exception(sodium_exception_ce, "invalid padding", 0);
3126 		RETURN_THROWS();
3127 	}
3128 	unpadded = zend_string_init(padded, padded_len, 0);
3129 	PHP_SODIUM_ZSTR_TRUNCATE(unpadded, unpadded_len);
3130 	ZSTR_VAL(unpadded)[unpadded_len] = 0;
3131 	RETURN_STR(unpadded);
3132 }
3133 
3134 #ifdef crypto_secretstream_xchacha20poly1305_ABYTES
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen)3135 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_keygen)
3136 {
3137 	unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES];
3138 
3139 	if (zend_parse_parameters_none() == FAILURE) {
3140 		RETURN_THROWS();
3141 	}
3142 	randombytes_buf(key, sizeof key);
3143 	RETURN_STRINGL((const char *) key, sizeof key);
3144 }
3145 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push)3146 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_push)
3147 {
3148 	crypto_secretstream_xchacha20poly1305_state  state;
3149 	unsigned char                                header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
3150 	unsigned char                               *key;
3151 	size_t                                       key_len;
3152 
3153 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3154 									&key, &key_len) == FAILURE) {
3155 		sodium_remove_param_values_from_backtrace(EG(exception));
3156 		RETURN_THROWS();
3157 	}
3158 	if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
3159 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes long");
3160 		RETURN_THROWS();
3161 	}
3162 	if (crypto_secretstream_xchacha20poly1305_init_push(&state,
3163 														header, key) != 0) {
3164 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3165 		RETURN_THROWS();
3166 	}
3167 	array_init(return_value);
3168 	add_next_index_stringl(return_value, (const char *) &state, sizeof state);
3169 	add_next_index_stringl(return_value, (const char *) header, sizeof header);
3170 }
3171 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push)3172 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_push)
3173 {
3174 	zval               *state_zv;
3175 	zend_string        *c;
3176 	unsigned char      *ad = NULL;
3177 	unsigned char      *msg;
3178 	unsigned char      *state;
3179 	unsigned long long  c_real_len;
3180 	zend_long           tag = crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
3181 	size_t              ad_len = (size_t) 0U;
3182 	size_t              c_len;
3183 	size_t              msg_len;
3184 	size_t              state_len;
3185 
3186 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|sl",
3187 									&state_zv,
3188 									&msg, &msg_len, &ad, &ad_len, &tag) == FAILURE) {
3189 		sodium_remove_param_values_from_backtrace(EG(exception));
3190 		RETURN_THROWS();
3191 	}
3192 	ZVAL_DEREF(state_zv);
3193 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3194 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3195 		RETURN_THROWS();
3196 	}
3197 	sodium_separate_string(state_zv);
3198 	state = (unsigned char *) Z_STRVAL(*state_zv);
3199 	state_len = Z_STRLEN(*state_zv);
3200 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3201 		zend_argument_error(sodium_exception_ce, 1, "must have a correct length");
3202 		RETURN_THROWS();
3203 	}
3204 	if (msg_len > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX ||
3205 		msg_len > SIZE_MAX - crypto_secretstream_xchacha20poly1305_ABYTES) {
3206 		zend_argument_error(sodium_exception_ce, 2, "must be at most SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes long");
3207 		RETURN_THROWS();
3208 	}
3209 	if (tag < 0 || tag > 255) {
3210 		zend_argument_error(sodium_exception_ce, 4, "must be in the range of 0-255");
3211 		RETURN_THROWS();
3212 	}
3213 	c_len = msg_len + crypto_secretstream_xchacha20poly1305_ABYTES;
3214 	c = zend_string_alloc((size_t) c_len, 0);
3215 	if (crypto_secretstream_xchacha20poly1305_push
3216 		((void *) state, (unsigned char *) ZSTR_VAL(c), &c_real_len,
3217 		 msg, (unsigned long long) msg_len, ad, (unsigned long long) ad_len,
3218 		 (unsigned char) tag) != 0) {
3219 		zend_string_efree(c);
3220 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3221 		RETURN_THROWS();
3222 	}
3223 	if (c_real_len <= 0U || c_real_len >= SIZE_MAX || c_real_len > c_len) {
3224 		zend_string_efree(c);
3225 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
3226 		RETURN_THROWS();
3227 	}
3228 	PHP_SODIUM_ZSTR_TRUNCATE(c, (size_t) c_real_len);
3229 	ZSTR_VAL(c)[c_real_len] = 0;
3230 
3231 	RETURN_NEW_STR(c);
3232 }
3233 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull)3234 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_init_pull)
3235 {
3236 	crypto_secretstream_xchacha20poly1305_state  state;
3237 	unsigned char                               *header;
3238 	unsigned char                               *key;
3239 	size_t                                       header_len;
3240 	size_t                                       key_len;
3241 
3242 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3243 									&header, &header_len,
3244 									&key, &key_len) == FAILURE) {
3245 		sodium_remove_param_values_from_backtrace(EG(exception));
3246 		RETURN_THROWS();
3247 	}
3248 	if (header_len != crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
3249 		zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes long");
3250 		RETURN_THROWS();
3251 	}
3252 	if (key_len != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
3253 		zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES bytes long");
3254 		RETURN_THROWS();
3255 	}
3256 	if (crypto_secretstream_xchacha20poly1305_init_pull(&state,
3257 														header, key) != 0) {
3258 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3259 		RETURN_THROWS();
3260 	}
3261 	RETURN_STRINGL((const char *) &state, sizeof state);
3262 }
3263 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull)3264 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_pull)
3265 {
3266 	zval               *state_zv;
3267 	zend_string        *msg;
3268 	unsigned char      *ad = NULL;
3269 	unsigned char      *c;
3270 	unsigned char      *state;
3271 	unsigned long long  msg_real_len;
3272 	size_t              ad_len = (size_t) 0U;
3273 	size_t              msg_len;
3274 	size_t              c_len;
3275 	size_t              state_len;
3276 	unsigned char       tag;
3277 
3278 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|s",
3279 									&state_zv,
3280 									&c, &c_len, &ad, &ad_len) == FAILURE) {
3281 		sodium_remove_param_values_from_backtrace(EG(exception));
3282 		RETURN_THROWS();
3283 	}
3284 	ZVAL_DEREF(state_zv);
3285 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3286 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3287 		RETURN_THROWS();
3288 	}
3289 	sodium_separate_string(state_zv);
3290 	state = (unsigned char *) Z_STRVAL(*state_zv);
3291 	state_len = Z_STRLEN(*state_zv);
3292 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3293 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
3294 		RETURN_THROWS();
3295 	}
3296 	if (c_len < crypto_secretstream_xchacha20poly1305_ABYTES) {
3297 		RETURN_FALSE;
3298 	}
3299 	msg_len = c_len - crypto_secretstream_xchacha20poly1305_ABYTES;
3300 	msg = zend_string_alloc((size_t) msg_len, 0);
3301 	if (crypto_secretstream_xchacha20poly1305_pull
3302 		((void *) state, (unsigned char *) ZSTR_VAL(msg), &msg_real_len, &tag,
3303 		 c, (unsigned long long) c_len, ad, (unsigned long long) ad_len) != 0) {
3304 		zend_string_efree(msg);
3305 		RETURN_FALSE;
3306 	}
3307 	if (msg_real_len >= SIZE_MAX || msg_real_len > msg_len) {
3308 		zend_string_efree(msg);
3309 		zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0);
3310 		RETURN_THROWS();
3311 	}
3312 	PHP_SODIUM_ZSTR_TRUNCATE(msg, (size_t) msg_real_len);
3313 	ZSTR_VAL(msg)[msg_real_len] = 0;
3314 	array_init(return_value);
3315 	add_next_index_str(return_value, msg);
3316 	add_next_index_long(return_value, (long) tag);
3317 }
3318 
PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey)3319 PHP_FUNCTION(sodium_crypto_secretstream_xchacha20poly1305_rekey)
3320 {
3321 	zval          *state_zv;
3322 	unsigned char *state;
3323 	size_t         state_len;
3324 
3325 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &state_zv) == FAILURE) {
3326 		sodium_remove_param_values_from_backtrace(EG(exception));
3327 		RETURN_THROWS();
3328 	}
3329 	ZVAL_DEREF(state_zv);
3330 	if (Z_TYPE_P(state_zv) != IS_STRING) {
3331 		zend_argument_error(sodium_exception_ce, 1, "must be a reference to a state");
3332 		RETURN_THROWS();
3333 	}
3334 	sodium_separate_string(state_zv);
3335 	state = (unsigned char *) Z_STRVAL(*state_zv);
3336 	state_len = Z_STRLEN(*state_zv);
3337 	if (state_len != sizeof (crypto_secretstream_xchacha20poly1305_state)) {
3338 		zend_throw_exception(sodium_exception_ce, "incorrect state length", 0);
3339 		RETURN_THROWS();
3340 	}
3341 	crypto_secretstream_xchacha20poly1305_rekey((void *) state);
3342 }
3343 #endif
3344 
3345 #ifdef crypto_core_ristretto255_HASHBYTES
PHP_FUNCTION(sodium_crypto_core_ristretto255_add)3346 PHP_FUNCTION(sodium_crypto_core_ristretto255_add)
3347 {
3348 	zend_string   *r;
3349 	unsigned char *p;
3350 	unsigned char *q;
3351 	size_t         p_len;
3352 	size_t         q_len;
3353 
3354 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3355 									&p, &p_len, &q, &q_len) == FAILURE) {
3356 		sodium_remove_param_values_from_backtrace(EG(exception));
3357 		RETURN_THROWS();
3358 	}
3359 	if (p_len != crypto_core_ristretto255_BYTES) {
3360 		zend_argument_error(sodium_exception_ce, 1,
3361 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3362 		RETURN_THROWS();
3363 	}
3364 	if (q_len != crypto_core_ristretto255_BYTES) {
3365 		zend_argument_error(sodium_exception_ce, 2,
3366 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3367 		RETURN_THROWS();
3368 	}
3369 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3370 	if (crypto_core_ristretto255_add((unsigned char *) ZSTR_VAL(r), p, q) != 0) {
3371 		zend_string_efree(r);
3372 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3373 		RETURN_THROWS();
3374 	}
3375 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3376 	RETURN_NEW_STR(r);
3377 }
3378 
PHP_FUNCTION(sodium_crypto_core_ristretto255_from_hash)3379 PHP_FUNCTION(sodium_crypto_core_ristretto255_from_hash)
3380 {
3381 	zend_string   *r;
3382 	unsigned char *s;
3383 	size_t         s_len;
3384 
3385 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3386 							  &s, &s_len) == FAILURE) {
3387 		sodium_remove_param_values_from_backtrace(EG(exception));
3388 		RETURN_THROWS();
3389 	}
3390 	if (s_len != crypto_core_ristretto255_HASHBYTES) {
3391 		zend_argument_error(sodium_exception_ce, 1,
3392 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES bytes long");
3393 		RETURN_THROWS();
3394 	}
3395 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3396 	if (crypto_core_ristretto255_from_hash((unsigned char *) ZSTR_VAL(r), s) != 0) {
3397 		zend_string_efree(r);
3398 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3399 		RETURN_THROWS();
3400 	}
3401 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3402 	RETURN_NEW_STR(r);
3403 }
3404 
PHP_FUNCTION(sodium_crypto_core_ristretto255_is_valid_point)3405 PHP_FUNCTION(sodium_crypto_core_ristretto255_is_valid_point)
3406 {
3407 	unsigned char *s;
3408 	size_t         s_len;
3409 
3410 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3411 							  &s, &s_len) == FAILURE) {
3412 		sodium_remove_param_values_from_backtrace(EG(exception));
3413 		RETURN_THROWS();
3414 	}
3415 	if (s_len != crypto_core_ristretto255_BYTES) {
3416 		zend_argument_error(sodium_exception_ce, 1,
3417 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3418 		RETURN_THROWS();
3419 	}
3420 	RETURN_BOOL(crypto_core_ristretto255_is_valid_point(s));
3421 }
3422 
PHP_FUNCTION(sodium_crypto_core_ristretto255_random)3423 PHP_FUNCTION(sodium_crypto_core_ristretto255_random)
3424 {
3425 	zend_string   *r;
3426 
3427 	if (zend_parse_parameters_none() == FAILURE) {
3428 		RETURN_THROWS();
3429 	}
3430 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3431 	crypto_core_ristretto255_random((unsigned char *) ZSTR_VAL(r));
3432 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3433 	RETURN_NEW_STR(r);
3434 }
3435 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_add)3436 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_add)
3437 {
3438 	zend_string   *r;
3439 	unsigned char *p;
3440 	unsigned char *q;
3441 	size_t         p_len;
3442 	size_t         q_len;
3443 
3444 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3445 									&p, &p_len, &q, &q_len) == FAILURE) {
3446 		sodium_remove_param_values_from_backtrace(EG(exception));
3447 		RETURN_THROWS();
3448 	}
3449 	if (p_len != crypto_core_ristretto255_SCALARBYTES) {
3450 		zend_argument_error(sodium_exception_ce, 1,
3451 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3452 		RETURN_THROWS();
3453 	}
3454 	if (q_len != crypto_core_ristretto255_SCALARBYTES) {
3455 		zend_argument_error(sodium_exception_ce, 2,
3456 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3457 		RETURN_THROWS();
3458 	}
3459 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3460 	crypto_core_ristretto255_scalar_add((unsigned char *) ZSTR_VAL(r), p, q);
3461 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3462 	RETURN_NEW_STR(r);
3463 }
3464 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_complement)3465 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_complement)
3466 {
3467 	zend_string   *r;
3468 	unsigned char *s;
3469 	size_t         s_len;
3470 
3471 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3472 							  &s, &s_len) == FAILURE) {
3473 		sodium_remove_param_values_from_backtrace(EG(exception));
3474 		RETURN_THROWS();
3475 	}
3476 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3477 		zend_argument_error(sodium_exception_ce, 1,
3478 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3479 		RETURN_THROWS();
3480 	}
3481 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3482 	crypto_core_ristretto255_scalar_complement((unsigned char *) ZSTR_VAL(r), s);
3483 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3484 	RETURN_NEW_STR(r);
3485 }
3486 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_invert)3487 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_invert)
3488 {
3489 	zend_string   *r;
3490 	unsigned char *s;
3491 	size_t         s_len;
3492 
3493 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3494 							  &s, &s_len) == FAILURE) {
3495 		sodium_remove_param_values_from_backtrace(EG(exception));
3496 		RETURN_THROWS();
3497 	}
3498 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3499 		zend_argument_error(sodium_exception_ce, 1,
3500 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3501 		RETURN_THROWS();
3502 	}
3503 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3504 	if (crypto_core_ristretto255_scalar_invert((unsigned char *) ZSTR_VAL(r), s) != 0) {
3505 		zend_string_efree(r);
3506 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3507 		RETURN_THROWS();
3508 	}
3509 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3510 	RETURN_NEW_STR(r);
3511 }
3512 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_mul)3513 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_mul)
3514 {
3515 	zend_string   *r;
3516 	unsigned char *x;
3517 	unsigned char *y;
3518 	size_t         x_len;
3519 	size_t         y_len;
3520 
3521 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3522 									&x, &x_len, &y, &y_len) == FAILURE) {
3523 		sodium_remove_param_values_from_backtrace(EG(exception));
3524 		RETURN_THROWS();
3525 	}
3526 	if (x_len != crypto_core_ristretto255_SCALARBYTES) {
3527 		zend_argument_error(sodium_exception_ce, 1,
3528 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3529 		RETURN_THROWS();
3530 	}
3531 	if (y_len != crypto_core_ristretto255_SCALARBYTES) {
3532 		zend_argument_error(sodium_exception_ce, 2,
3533 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3534 		RETURN_THROWS();
3535 	}
3536 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3537 	crypto_core_ristretto255_scalar_mul((unsigned char *) ZSTR_VAL(r), x, y);
3538 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3539 	RETURN_NEW_STR(r);
3540 }
3541 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_negate)3542 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_negate)
3543 {
3544 	zend_string   *r;
3545 	unsigned char *s;
3546 	size_t         s_len;
3547 
3548 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3549 							  &s, &s_len) == FAILURE) {
3550 		sodium_remove_param_values_from_backtrace(EG(exception));
3551 		RETURN_THROWS();
3552 	}
3553 	if (s_len != crypto_core_ristretto255_SCALARBYTES) {
3554 		zend_argument_error(sodium_exception_ce, 1,
3555 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3556 		RETURN_THROWS();
3557 	}
3558 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3559 	crypto_core_ristretto255_scalar_negate((unsigned char *) ZSTR_VAL(r), s);
3560 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3561 	RETURN_NEW_STR(r);
3562 }
3563 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_random)3564 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_random)
3565 {
3566 	zend_string   *r;
3567 
3568 	if (zend_parse_parameters_none() == FAILURE) {
3569 		RETURN_THROWS();
3570 	};
3571 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3572 	crypto_core_ristretto255_scalar_random((unsigned char *) ZSTR_VAL(r));
3573 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3574 	RETURN_NEW_STR(r);
3575 }
3576 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_reduce)3577 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_reduce)
3578 {
3579 	zend_string   *r;
3580 	unsigned char *s;
3581 	size_t         s_len;
3582 
3583 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
3584 							  &s, &s_len) == FAILURE) {
3585 		sodium_remove_param_values_from_backtrace(EG(exception));
3586 		RETURN_THROWS();
3587 	}
3588 	if (s_len != crypto_core_ristretto255_NONREDUCEDSCALARBYTES) {
3589 		zend_argument_error(sodium_exception_ce, 1,
3590 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES bytes long");
3591 		RETURN_THROWS();
3592 	}
3593 	r = zend_string_alloc(crypto_core_ristretto255_SCALARBYTES, 0);
3594 	crypto_core_ristretto255_scalar_reduce((unsigned char *) ZSTR_VAL(r), s);
3595 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3596 	RETURN_NEW_STR(r);
3597 }
3598 
PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_sub)3599 PHP_FUNCTION(sodium_crypto_core_ristretto255_scalar_sub)
3600 {
3601 	zend_string   *r;
3602 	unsigned char *p;
3603 	unsigned char *q;
3604 	size_t         p_len;
3605 	size_t         q_len;
3606 
3607 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3608 									&p, &p_len, &q, &q_len) == FAILURE) {
3609 		sodium_remove_param_values_from_backtrace(EG(exception));
3610 		RETURN_THROWS();
3611 	}
3612 	if (p_len != crypto_core_ristretto255_SCALARBYTES) {
3613 		zend_argument_error(sodium_exception_ce, 1,
3614 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3615 		RETURN_THROWS();
3616 	}
3617 	if (q_len != crypto_core_ristretto255_SCALARBYTES) {
3618 		zend_argument_error(sodium_exception_ce, 2,
3619 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES bytes long");
3620 		RETURN_THROWS();
3621 	}
3622 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3623 	crypto_core_ristretto255_scalar_sub((unsigned char *) ZSTR_VAL(r), p, q);
3624 	ZSTR_VAL(r)[crypto_core_ristretto255_SCALARBYTES] = 0;
3625 	RETURN_NEW_STR(r);
3626 }
3627 
PHP_FUNCTION(sodium_crypto_core_ristretto255_sub)3628 PHP_FUNCTION(sodium_crypto_core_ristretto255_sub)
3629 {
3630 	zend_string   *r;
3631 	unsigned char *p;
3632 	unsigned char *q;
3633 	size_t         p_len;
3634 	size_t         q_len;
3635 
3636 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
3637 									&p, &p_len, &q, &q_len) == FAILURE) {
3638 		sodium_remove_param_values_from_backtrace(EG(exception));
3639 		RETURN_THROWS();
3640 	}
3641 	if (p_len != crypto_core_ristretto255_BYTES) {
3642 		zend_argument_error(sodium_exception_ce, 1,
3643 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3644 		RETURN_THROWS();
3645 	}
3646 	if (q_len != crypto_core_ristretto255_BYTES) {
3647 		zend_argument_error(sodium_exception_ce, 2,
3648 							"must be SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES bytes long");
3649 		RETURN_THROWS();
3650 	}
3651 	r = zend_string_alloc(crypto_core_ristretto255_BYTES, 0);
3652 	if (crypto_core_ristretto255_sub((unsigned char *) ZSTR_VAL(r), p, q) != 0) {
3653 		zend_string_efree(r);
3654 		zend_throw_exception(sodium_exception_ce, "internal error", 0);
3655 		RETURN_THROWS();
3656 	}
3657 	ZSTR_VAL(r)[crypto_core_ristretto255_BYTES] = 0;
3658 	RETURN_NEW_STR(r);
3659 }
3660 #endif
3661