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