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