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