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