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