1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2013-2016 Jakub Zelenka |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Jakub Zelenka <bukka@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #define PHPC_SMART_CSTR_INCLUDE 1
20
21 #include "php.h"
22 #include "php_crypto.h"
23 #include "php_crypto_cipher.h"
24 #include "php_crypto_object.h"
25 #include "zend_exceptions.h"
26 #include "ext/standard/php_string.h"
27
28 #include <openssl/evp.h>
29
30 /* ERRORS */
31
32 PHP_CRYPTO_EXCEPTION_DEFINE(Cipher)
33 PHP_CRYPTO_ERROR_INFO_BEGIN(Cipher)
34 PHP_CRYPTO_ERROR_INFO_ENTRY(
35 ALGORITHM_NOT_FOUND,
36 "Cipher '%s' algorithm not found"
37 )
38 PHP_CRYPTO_ERROR_INFO_ENTRY(
39 STATIC_METHOD_NOT_FOUND,
40 "Cipher static method '%s' not found"
41 )
42 PHP_CRYPTO_ERROR_INFO_ENTRY(
43 STATIC_METHOD_TOO_MANY_ARGS,
44 "Cipher static method %s can accept max two arguments"
45 )
46 PHP_CRYPTO_ERROR_INFO_ENTRY(
47 MODE_NOT_FOUND,
48 "Cipher mode not found"
49 )
50 PHP_CRYPTO_ERROR_INFO_ENTRY(
51 MODE_NOT_AVAILABLE,
52 "Cipher mode %s is not available in installed OpenSSL library"
53 )
54 PHP_CRYPTO_ERROR_INFO_ENTRY(
55 AUTHENTICATION_NOT_SUPPORTED,
56 "The authentication is not supported for %s cipher mode"
57 )
58 PHP_CRYPTO_ERROR_INFO_ENTRY(
59 KEY_LENGTH_INVALID,
60 "Invalid length of key for cipher '%s' algorithm "
61 "(required length: %d)"
62 )
63 PHP_CRYPTO_ERROR_INFO_ENTRY(
64 IV_LENGTH_INVALID,
65 "Invalid length of initial vector for cipher '%s' algorithm "
66 "(required length: %d)"
67 )
68 PHP_CRYPTO_ERROR_INFO_ENTRY(
69 AAD_SETTER_FORBIDDEN,
70 "AAD setter has to be called before encryption or decryption"
71 )
72 PHP_CRYPTO_ERROR_INFO_ENTRY(
73 AAD_SETTER_FAILED,
74 "AAD setter failed"
75 )
76 PHP_CRYPTO_ERROR_INFO_ENTRY(
77 AAD_LENGTH_HIGH,
78 "AAD length can't exceed max integer length"
79 )
80 PHP_CRYPTO_ERROR_INFO_ENTRY(
81 TAG_GETTER_FORBIDDEN,
82 "Tag getter has to be called after encryption"
83 )
84 PHP_CRYPTO_ERROR_INFO_ENTRY(
85 TAG_SETTER_FORBIDDEN,
86 "Tag setter has to be called before decryption"
87 )
88 PHP_CRYPTO_ERROR_INFO_ENTRY(
89 TAG_GETTER_FAILED,
90 "Tag getter failed"
91 )
92 PHP_CRYPTO_ERROR_INFO_ENTRY(
93 TAG_SETTER_FAILED,
94 "Tag setter failed"
95 )
96 PHP_CRYPTO_ERROR_INFO_ENTRY(
97 TAG_LENGTH_SETTER_FORBIDDEN,
98 "Tag length setter has to be called before encryption"
99 )
100 PHP_CRYPTO_ERROR_INFO_ENTRY(
101 TAG_LENGTH_LOW,
102 "Tag length can't be lower than 32 bits (4 characters)"
103 )
104 PHP_CRYPTO_ERROR_INFO_ENTRY(
105 TAG_LENGTH_HIGH,
106 "Tag length can't exceed 128 bits (16 characters)"
107 )
108 PHP_CRYPTO_ERROR_INFO_ENTRY(
109 TAG_VERIFY_FAILED,
110 "Tag verifycation failed"
111 )
112 PHP_CRYPTO_ERROR_INFO_ENTRY(
113 INIT_ALG_FAILED,
114 "Initialization of cipher algorithm failed"
115 )
116 PHP_CRYPTO_ERROR_INFO_ENTRY(
117 INIT_CTX_FAILED,
118 "Initialization of cipher context failed"
119 )
120 PHP_CRYPTO_ERROR_INFO_ENTRY(
121 INIT_ENCRYPT_FORBIDDEN,
122 "Cipher object is already used for decryption"
123 )
124 PHP_CRYPTO_ERROR_INFO_ENTRY(
125 INIT_DECRYPT_FORBIDDEN,
126 "Cipher object is already used for encryption"
127 )
128 PHP_CRYPTO_ERROR_INFO_ENTRY(
129 UPDATE_FAILED,
130 "Updating of cipher failed"
131 )
132 PHP_CRYPTO_ERROR_INFO_ENTRY(
133 UPDATE_ENCRYPT_FORBIDDEN,
134 "Cipher object is not initialized for encryption"
135 )
136 PHP_CRYPTO_ERROR_INFO_ENTRY(
137 UPDATE_DECRYPT_FORBIDDEN,
138 "Cipher object is not initialized for decryption"
139 )
140 PHP_CRYPTO_ERROR_INFO_ENTRY(
141 FINISH_FAILED,
142 "Finalizing of cipher failed"
143 )
144 PHP_CRYPTO_ERROR_INFO_ENTRY(
145 FINISH_ENCRYPT_FORBIDDEN,
146 "Cipher object is not initialized for encryption"
147 )
148 PHP_CRYPTO_ERROR_INFO_ENTRY(
149 FINISH_DECRYPT_FORBIDDEN,
150 "Cipher object is not initialized for decryption"
151 )
152 PHP_CRYPTO_ERROR_INFO_ENTRY(
153 INPUT_DATA_LENGTH_HIGH,
154 "Input data length can't exceed max integer length"
155 )
156 PHP_CRYPTO_ERROR_INFO_END()
157
158
159 /* ARG INFOS */
160
161 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_algorithm, 0)
162 ZEND_ARG_INFO(0, algorithm)
163 ZEND_END_ARG_INFO()
164
165 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_data, 0)
166 ZEND_ARG_INFO(0, data)
167 ZEND_END_ARG_INFO()
168
169 ZEND_BEGIN_ARG_INFO_EX(arginfo_crypto_cipher_list, 0, 0, 0)
170 ZEND_ARG_INFO(0, aliases)
171 ZEND_ARG_INFO(0, prefix)
172 ZEND_END_ARG_INFO()
173
174 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_static, 0)
175 ZEND_ARG_INFO(0, name)
176 ZEND_ARG_INFO(0, arguments)
177 ZEND_END_ARG_INFO()
178
179 ZEND_BEGIN_ARG_INFO_EX(arginfo_crypto_cipher_construct, 0, 0, 1)
180 ZEND_ARG_INFO(0, algorithm)
181 ZEND_ARG_INFO(0, mode)
182 ZEND_ARG_INFO(0, key_size)
183 ZEND_END_ARG_INFO()
184
185 ZEND_BEGIN_ARG_INFO_EX(arginfo_crypto_cipher_init, 0, 0, 1)
186 ZEND_ARG_INFO(0, key)
187 ZEND_ARG_INFO(0, iv)
188 ZEND_END_ARG_INFO()
189
190 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_mode, 0)
191 ZEND_ARG_INFO(0, mode)
192 ZEND_END_ARG_INFO()
193
194 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_set_tag_len, 0)
195 ZEND_ARG_INFO(0, tag_length)
196 ZEND_END_ARG_INFO()
197
198 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_set_tag, 0)
199 ZEND_ARG_INFO(0, tag)
200 ZEND_END_ARG_INFO()
201
202 ZEND_BEGIN_ARG_INFO(arginfo_crypto_cipher_set_aad, 0)
203 ZEND_ARG_INFO(0, aad)
204 ZEND_END_ARG_INFO()
205
206 ZEND_BEGIN_ARG_INFO_EX(arginfo_crypto_cipher_crypt, 0, 0, 2)
207 ZEND_ARG_INFO(0, data)
208 ZEND_ARG_INFO(0, key)
209 ZEND_ARG_INFO(0, iv)
210 ZEND_END_ARG_INFO()
211
212
213 static const zend_function_entry php_crypto_cipher_object_methods[] = {
214 PHP_CRYPTO_ME(
215 Cipher, getAlgorithms,
216 arginfo_crypto_cipher_list,
217 ZEND_ACC_STATIC|ZEND_ACC_PUBLIC
218 )
219 PHP_CRYPTO_ME(
220 Cipher, hasAlgorithm,
221 arginfo_crypto_cipher_algorithm,
222 ZEND_ACC_STATIC|ZEND_ACC_PUBLIC
223 )
224 PHP_CRYPTO_ME(
225 Cipher, hasMode,
226 arginfo_crypto_cipher_mode,
227 ZEND_ACC_STATIC|ZEND_ACC_PUBLIC
228 )
229 PHP_CRYPTO_ME(
230 Cipher, __callStatic,
231 arginfo_crypto_cipher_static,
232 ZEND_ACC_STATIC|ZEND_ACC_PUBLIC
233 )
234 PHP_CRYPTO_ME(
235 Cipher, __construct,
236 arginfo_crypto_cipher_construct,
237 ZEND_ACC_CTOR|ZEND_ACC_PUBLIC
238 )
239 PHP_CRYPTO_ME(
240 Cipher, getAlgorithmName,
241 NULL,
242 ZEND_ACC_PUBLIC
243 )
244 PHP_CRYPTO_ME(
245 Cipher, encryptInit,
246 arginfo_crypto_cipher_init,
247 ZEND_ACC_PUBLIC
248 )
249 PHP_CRYPTO_ME(
250 Cipher, encryptUpdate,
251 arginfo_crypto_cipher_data,
252 ZEND_ACC_PUBLIC
253 )
254 PHP_CRYPTO_ME(
255 Cipher, encryptFinish,
256 NULL,
257 ZEND_ACC_PUBLIC
258 )
259 PHP_CRYPTO_ME(
260 Cipher, encrypt,
261 arginfo_crypto_cipher_crypt,
262 ZEND_ACC_PUBLIC
263 )
264 PHP_CRYPTO_ME(
265 Cipher, decryptInit,
266 arginfo_crypto_cipher_init,
267 ZEND_ACC_PUBLIC
268 )
269 PHP_CRYPTO_ME(
270 Cipher, decryptUpdate,
271 arginfo_crypto_cipher_data,
272 ZEND_ACC_PUBLIC
273 )
274 PHP_CRYPTO_ME(
275 Cipher, decryptFinish,
276 NULL,
277 ZEND_ACC_PUBLIC
278 )
279 PHP_CRYPTO_ME(
280 Cipher, decrypt,
281 arginfo_crypto_cipher_crypt,
282 ZEND_ACC_PUBLIC
283 )
284 PHP_CRYPTO_ME(
285 Cipher, getBlockSize,
286 NULL,
287 ZEND_ACC_PUBLIC
288 )
289 PHP_CRYPTO_ME(
290 Cipher, getKeyLength,
291 NULL,
292 ZEND_ACC_PUBLIC
293 )
294 PHP_CRYPTO_ME(
295 Cipher, getIVLength,
296 NULL,
297 ZEND_ACC_PUBLIC
298 )
299 PHP_CRYPTO_ME(
300 Cipher, getMode,
301 NULL,
302 ZEND_ACC_PUBLIC
303 )
304 PHP_CRYPTO_ME(
305 Cipher, getTag,
306 NULL,
307 ZEND_ACC_PUBLIC
308 )
309 PHP_CRYPTO_ME(
310 Cipher, setTag,
311 arginfo_crypto_cipher_set_tag,
312 ZEND_ACC_PUBLIC
313 )
314 PHP_CRYPTO_ME(
315 Cipher, setTagLength,
316 arginfo_crypto_cipher_set_tag_len,
317 ZEND_ACC_PUBLIC
318 )
319 PHP_CRYPTO_ME(
320 Cipher, setAAD,
321 arginfo_crypto_cipher_set_aad,
322 ZEND_ACC_PUBLIC
323 )
324 PHPC_FE_END
325 };
326
327 /* cipher modes lookup table */
328 static const php_crypto_cipher_mode php_crypto_cipher_modes[] = {
329 PHP_CRYPTO_CIPHER_MODE_ENTRY(ECB)
330 PHP_CRYPTO_CIPHER_MODE_ENTRY(CBC)
331 PHP_CRYPTO_CIPHER_MODE_ENTRY(CFB)
332 PHP_CRYPTO_CIPHER_MODE_ENTRY(OFB)
333 #ifdef EVP_CIPH_CTR_MODE
334 PHP_CRYPTO_CIPHER_MODE_ENTRY(CTR)
335 #else
336 PHP_CRYPTO_CIPHER_MODE_ENTRY_NOT_DEFINED(CTR)
337 #endif
338 #ifdef EVP_CIPH_GCM_MODE
339 PHP_CRYPTO_CIPHER_MODE_ENTRY_EX(GCM, 1, 0,
340 EVP_CTRL_GCM_SET_IVLEN,
341 EVP_CTRL_GCM_SET_TAG, EVP_CTRL_GCM_GET_TAG)
342 #else
343 PHP_CRYPTO_CIPHER_MODE_ENTRY_NOT_DEFINED(GCM)
344 #endif
345 #ifdef EVP_CIPH_CCM_MODE
346 PHP_CRYPTO_CIPHER_MODE_ENTRY_EX(CCM, 1, 1,
347 EVP_CTRL_CCM_SET_IVLEN,
348 EVP_CTRL_CCM_SET_TAG, EVP_CTRL_CCM_GET_TAG)
349 #else
350 PHP_CRYPTO_CIPHER_MODE_ENTRY_NOT_DEFINED(CCM)
351 #endif
352 #ifdef EVP_CIPH_XTS_MODE
353 PHP_CRYPTO_CIPHER_MODE_ENTRY(XTS)
354 #else
355 PHP_CRYPTO_CIPHER_MODE_ENTRY_NOT_DEFINED(XTS)
356 #endif
357 PHP_CRYPTO_CIPHER_MODE_ENTRY_END
358 };
359
360 /* class entry */
361 PHP_CRYPTO_API zend_class_entry *php_crypto_cipher_ce;
362
363 /* object handler */
364 PHPC_OBJ_DEFINE_HANDLER_VAR(crypto_cipher);
365
366 /* algorithm name getter macros */
367 #define PHP_CRYPTO_CIPHER_GET_ALGORITHM_NAME_EX(this_object) \
368 PHPC_READ_PROPERTY(php_crypto_cipher_ce, this_object, \
369 "algorithm", sizeof("algorithm")-1, 1)
370
371 #define PHP_CRYPTO_CIPHER_GET_ALGORITHM_NAME(this_object) \
372 Z_STRVAL_P(PHP_CRYPTO_CIPHER_GET_ALGORITHM_NAME_EX(this_object))
373
374
375 /* {{{ crypto_cipher free object handler */
PHPC_OBJ_HANDLER_FREE(crypto_cipher)376 PHPC_OBJ_HANDLER_FREE(crypto_cipher)
377 {
378 PHPC_OBJ_HANDLER_FREE_INIT(crypto_cipher);
379
380 EVP_CIPHER_CTX_free(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS));
381
382 if (PHP_CRYPTO_CIPHER_AAD(PHPC_THIS)) {
383 efree(PHP_CRYPTO_CIPHER_AAD(PHPC_THIS));
384 }
385 if (PHP_CRYPTO_CIPHER_TAG(PHPC_THIS)) {
386 efree(PHP_CRYPTO_CIPHER_TAG(PHPC_THIS));
387 }
388
389 PHPC_OBJ_HANDLER_FREE_DESTROY();
390 }
391 /* }}} */
392
393 /* {{{ crypto_cipher create_ex object helper */
PHPC_OBJ_HANDLER_CREATE_EX(crypto_cipher)394 PHPC_OBJ_HANDLER_CREATE_EX(crypto_cipher)
395 {
396 PHPC_OBJ_HANDLER_CREATE_EX_INIT(crypto_cipher);
397
398 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS) = EVP_CIPHER_CTX_new();
399 if (!PHP_CRYPTO_CIPHER_CTX(PHPC_THIS)) {
400 php_error(E_ERROR, "Creating Cipher object failed");
401 }
402
403 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS) = NULL;
404 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS) = 0;
405 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS) = NULL;
406 /* this is a default len for the tag */
407 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS) =
408 PHP_CRYPTO_CIPHER_AUTH_TAG_LENGTH_DEFAULT;
409
410 PHPC_OBJ_HANDLER_CREATE_EX_RETURN(crypto_cipher);
411 }
412 /* }}} */
413
414 /* {{{ crypto_cipher create object handler */
PHPC_OBJ_HANDLER_CREATE(crypto_cipher)415 PHPC_OBJ_HANDLER_CREATE(crypto_cipher)
416 {
417 PHPC_OBJ_HANDLER_CREATE_RETURN(crypto_cipher);
418 }
419 /* }}} */
420
421 /* {{{ crypto_cipher clone object handler */
PHPC_OBJ_HANDLER_CLONE(crypto_cipher)422 PHPC_OBJ_HANDLER_CLONE(crypto_cipher)
423 {
424 zend_bool copy_success;
425 PHPC_OBJ_HANDLER_CLONE_INIT(crypto_cipher);
426
427 PHPC_THAT->status = PHPC_THIS->status;
428 if (PHP_CRYPTO_CIPHER_TAG(PHPC_THIS)) {
429 PHP_CRYPTO_CIPHER_TAG(PHPC_THAT) = emalloc(
430 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS));
431 memcpy(PHP_CRYPTO_CIPHER_TAG(PHPC_THAT),
432 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS),
433 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS));
434 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THAT) =
435 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS);
436 }
437 if (PHP_CRYPTO_CIPHER_AAD(PHPC_THIS)) {
438 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS) = emalloc(
439 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS));
440 memcpy(PHP_CRYPTO_CIPHER_AAD(PHPC_THAT),
441 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS),
442 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS));
443 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THAT) =
444 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS);
445 }
446
447 #ifdef PHP_CRYPTO_HAS_CIPHER_CTX_COPY
448 copy_success = EVP_CIPHER_CTX_copy(
449 PHP_CRYPTO_CIPHER_CTX(PHPC_THAT),
450 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS));
451 #else
452 memcpy(PHP_CRYPTO_CIPHER_CTX(PHPC_THAT),
453 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
454 sizeof *(PHP_CRYPTO_CIPHER_CTX(PHPC_THAT)));
455
456 copy_success = 1;
457 if (PHP_CRYPTO_CIPHER_CTX(PHPC_THIS)->cipher_data &&
458 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS)->cipher->ctx_size) {
459 PHP_CRYPTO_CIPHER_CTX(PHPC_THAT)->cipher_data = OPENSSL_malloc(
460 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS)->cipher->ctx_size);
461 if (!PHP_CRYPTO_CIPHER_CTX(PHPC_THAT)->cipher_data) {
462 copy_success = 0;
463 }
464 memcpy(PHP_CRYPTO_CIPHER_CTX(PHPC_THAT)->cipher_data,
465 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS)->cipher_data,
466 PHP_CRYPTO_CIPHER_CTX(PHPC_THIS)->cipher->ctx_size);
467 }
468 #endif
469
470 PHP_CRYPTO_CIPHER_ALG(PHPC_THAT) = EVP_CIPHER_CTX_cipher(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS));
471
472 if (!copy_success) {
473 php_error(E_ERROR, "Cloning of Cipher object failed");
474 }
475
476 PHPC_OBJ_HANDLER_CLONE_RETURN();
477 }
478 /* }}} */
479
480 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(crypto_cipher)481 PHP_MINIT_FUNCTION(crypto_cipher)
482 {
483 zend_class_entry ce;
484 const php_crypto_cipher_mode *mode;
485
486 /* CipherException registration */
487 PHP_CRYPTO_EXCEPTION_REGISTER(ce, Cipher);
488 PHP_CRYPTO_ERROR_INFO_REGISTER(Cipher);
489
490 /* Cipher class */
491 INIT_CLASS_ENTRY(ce, PHP_CRYPTO_CLASS_NAME(Cipher), php_crypto_cipher_object_methods);
492 PHPC_CLASS_SET_HANDLER_CREATE(ce, crypto_cipher);
493 php_crypto_cipher_ce = PHPC_CLASS_REGISTER(ce);
494 PHPC_OBJ_INIT_HANDLERS(crypto_cipher);
495 PHPC_OBJ_SET_HANDLER_OFFSET(crypto_cipher);
496 PHPC_OBJ_SET_HANDLER_FREE(crypto_cipher);
497 PHPC_OBJ_SET_HANDLER_CLONE(crypto_cipher);
498 zend_declare_property_null(php_crypto_cipher_ce,
499 "algorithm", sizeof("algorithm")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
500
501 /* Cipher constants for modes */
502 for (mode = php_crypto_cipher_modes; mode->name[0]; mode++) {
503 zend_declare_class_constant_long(php_crypto_cipher_ce,
504 mode->constant, strlen(mode->constant), mode->value TSRMLS_CC);
505 }
506
507 return SUCCESS;
508 }
509 /* }}} */
510
511 /* METHODS */
512
513 /* {{{ php_crypto_get_algorithm_object_ex */
php_crypto_cipher_set_algorithm_name(zval * object,char * algorithm,phpc_str_size_t algorithm_len TSRMLS_DC)514 static inline void php_crypto_cipher_set_algorithm_name(zval *object,
515 char *algorithm, phpc_str_size_t algorithm_len TSRMLS_DC)
516 {
517 php_strtoupper(algorithm, algorithm_len);
518 zend_update_property_stringl(php_crypto_cipher_ce, object,
519 "algorithm", sizeof("algorithm")-1, algorithm, algorithm_len TSRMLS_CC);
520 }
521 /* }}} */
522
523 /* {{{ php_crypto_get_cipher_algorithm */
php_crypto_get_cipher_algorithm(char * algorithm,phpc_str_size_t algorithm_len)524 PHP_CRYPTO_API const EVP_CIPHER *php_crypto_get_cipher_algorithm(
525 char *algorithm, phpc_str_size_t algorithm_len)
526 {
527 const EVP_CIPHER *cipher;
528
529 if (algorithm_len > PHP_CRYPTO_CIPHER_ALGORITHM_LEN_MAX) {
530 return NULL;
531 }
532
533 php_strtoupper(algorithm, algorithm_len);
534 cipher = EVP_get_cipherbyname(algorithm);
535 if (!cipher) {
536 php_strtolower(algorithm, algorithm_len);
537 cipher = EVP_get_cipherbyname(algorithm);
538 }
539 return cipher;
540 }
541 /* }}} */
542
543 /* {{{ php_crypto_get_cipher_algorithm_from_params_ex */
php_crypto_get_cipher_algorithm_from_params_ex(zval * object,char * algorithm,phpc_str_size_t algorithm_len,zval * pz_mode,zval * pz_key_size,zend_bool is_static TSRMLS_DC)544 static const EVP_CIPHER *php_crypto_get_cipher_algorithm_from_params_ex(
545 zval *object, char *algorithm, phpc_str_size_t algorithm_len, zval *pz_mode,
546 zval *pz_key_size, zend_bool is_static TSRMLS_DC)
547 {
548 const EVP_CIPHER *cipher;
549 phpc_smart_cstr alg_buf = {0};
550
551 /* if mode is not set, then it is already contained in the algorithm string */
552 if (!pz_mode || Z_TYPE_P(pz_mode) == IS_NULL) {
553 cipher = php_crypto_get_cipher_algorithm(algorithm, algorithm_len);
554 if (!cipher) {
555 if (is_static) {
556 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, STATIC_METHOD_NOT_FOUND),
557 algorithm);
558 } else {
559 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, ALGORITHM_NOT_FOUND),
560 algorithm);
561 }
562 } else if (object) {
563 php_crypto_cipher_set_algorithm_name(object, algorithm, algorithm_len TSRMLS_CC);
564 }
565 return cipher;
566 }
567
568 phpc_smart_cstr_appendl(&alg_buf, algorithm, algorithm_len);
569 phpc_smart_cstr_appendc(&alg_buf, '-');
570
571 /* copy key size if available */
572 if (pz_key_size && Z_TYPE_P(pz_key_size) != IS_NULL) {
573 if (Z_TYPE_P(pz_key_size) == IS_STRING) {
574 phpc_smart_cstr_appendl(&alg_buf, Z_STRVAL_P(pz_key_size), Z_STRLEN_P(pz_key_size));
575 } else {
576 zval z_key_size = *pz_key_size;
577 zval_copy_ctor(&z_key_size);
578 convert_to_string(&z_key_size);
579 phpc_smart_cstr_appendl(&alg_buf, Z_STRVAL(z_key_size), Z_STRLEN(z_key_size));
580 phpc_smart_cstr_appendc(&alg_buf, '-');
581 zval_dtor(&z_key_size);
582 }
583 }
584
585 /* copy mode */
586 if (Z_TYPE_P(pz_mode) == IS_LONG) {
587 const php_crypto_cipher_mode *mode = php_crypto_get_cipher_mode_ex(Z_LVAL_P(pz_mode));
588 if (!mode) {
589 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, MODE_NOT_FOUND));
590 phpc_smart_cstr_free(&alg_buf);
591 return NULL;
592 }
593 if (mode->value == PHP_CRYPTO_CIPHER_MODE_NOT_DEFINED) {
594 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, MODE_NOT_AVAILABLE), mode->name);
595 phpc_smart_cstr_free(&alg_buf);
596 return NULL;
597 }
598 phpc_smart_cstr_appendl(&alg_buf, mode->name, PHP_CRYPTO_CIPHER_MODE_LEN);
599 } else if (Z_TYPE_P(pz_mode) == IS_STRING) {
600 phpc_smart_cstr_appendl(&alg_buf, Z_STRVAL_P(pz_mode), Z_STRLEN_P(pz_mode));
601 } else {
602 zval z_mode = *pz_mode;
603 zval_copy_ctor(&z_mode);
604 convert_to_string(&z_mode);
605 phpc_smart_cstr_appendl(&alg_buf, Z_STRVAL(z_mode), Z_STRLEN(z_mode));
606 zval_dtor(&z_mode);
607 }
608
609 phpc_smart_cstr_0(&alg_buf);
610 cipher = php_crypto_get_cipher_algorithm(alg_buf.c, alg_buf.len);
611 if (!cipher) {
612 if (is_static) {
613 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, STATIC_METHOD_NOT_FOUND), alg_buf.c);
614 } else {
615 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, ALGORITHM_NOT_FOUND), alg_buf.c);
616 }
617 } else if (object) {
618 php_crypto_cipher_set_algorithm_name(object, alg_buf.c, alg_buf.len TSRMLS_CC);
619 }
620 phpc_smart_cstr_free(&alg_buf);
621 return cipher;
622 }
623 /* }}} */
624
625 /* {{{ php_crypto_get_cipher_algorithm_from_params */
php_crypto_get_cipher_algorithm_from_params(char * algorithm,phpc_str_size_t algorithm_len,zval * pz_mode,zval * pz_key_size TSRMLS_DC)626 PHP_CRYPTO_API const EVP_CIPHER *php_crypto_get_cipher_algorithm_from_params(
627 char *algorithm, phpc_str_size_t algorithm_len, zval *pz_mode, zval *pz_key_size TSRMLS_DC)
628 {
629 return php_crypto_get_cipher_algorithm_from_params_ex(
630 NULL, algorithm, algorithm_len, pz_mode, pz_key_size, 0 TSRMLS_CC);
631 }
632 /* }}} */
633
634 /* {{{ php_crypto_set_cipher_algorithm_ex */
php_crypto_set_cipher_algorithm_ex(PHPC_THIS_DECLARE (crypto_cipher),char * algorithm,phpc_str_size_t algorithm_len TSRMLS_DC)635 static int php_crypto_set_cipher_algorithm_ex(PHPC_THIS_DECLARE(crypto_cipher),
636 char *algorithm, phpc_str_size_t algorithm_len TSRMLS_DC)
637 {
638 const EVP_CIPHER *cipher = php_crypto_get_cipher_algorithm(algorithm, algorithm_len);
639 if (!cipher) {
640 return FAILURE;
641 }
642 PHP_CRYPTO_CIPHER_ALG(PHPC_THIS) = cipher;
643 return SUCCESS;
644 }
645 /* }}} */
646
647 /* {{{ php_crypto_set_cipher_algorithm */
php_crypto_set_cipher_algorithm(zval * object,char * algorithm,phpc_str_size_t algorithm_len TSRMLS_DC)648 static int php_crypto_set_cipher_algorithm(zval *object,
649 char *algorithm, phpc_str_size_t algorithm_len TSRMLS_DC)
650 {
651 PHPC_THIS_DECLARE_AND_FETCH_FROM_ZVAL(crypto_cipher, object);
652 php_crypto_cipher_set_algorithm_name(object, algorithm, algorithm_len TSRMLS_CC);
653 return php_crypto_set_cipher_algorithm_ex(PHPC_THIS, algorithm, algorithm_len TSRMLS_CC);
654 }
655 /* }}} */
656
657 /* {{{ php_crypto_set_cipher_algorithm_from_params_ex */
php_crypto_set_cipher_algorithm_from_params_ex(zval * object,char * algorithm,phpc_str_size_t algorithm_len,zval * pz_mode,zval * pz_key_size,zend_bool is_static TSRMLS_DC)658 static int php_crypto_set_cipher_algorithm_from_params_ex(
659 zval *object, char *algorithm, phpc_str_size_t algorithm_len,
660 zval *pz_mode, zval *pz_key_size, zend_bool is_static TSRMLS_DC)
661 {
662 PHPC_THIS_DECLARE_AND_FETCH_FROM_ZVAL(crypto_cipher, object);
663 const EVP_CIPHER *cipher = php_crypto_get_cipher_algorithm_from_params_ex(
664 object, algorithm, algorithm_len, pz_mode, pz_key_size, is_static TSRMLS_CC);
665
666 if (!cipher) {
667 return FAILURE;
668 }
669
670 PHP_CRYPTO_CIPHER_ALG(PHPC_THIS) = cipher;
671 return SUCCESS;
672 }
673 /* }}} */
674
675 /* {{{ php_crypto_set_cipher_algorithm_from_params */
php_crypto_set_cipher_algorithm_from_params(zval * object,char * algorithm,phpc_str_size_t algorithm_len,zval * pz_mode,zval * pz_key_size TSRMLS_DC)676 static int php_crypto_set_cipher_algorithm_from_params(
677 zval *object, char *algorithm, phpc_str_size_t algorithm_len,
678 zval *pz_mode, zval *pz_key_size TSRMLS_DC)
679 {
680 return php_crypto_set_cipher_algorithm_from_params_ex(
681 object, algorithm, algorithm_len, pz_mode, pz_key_size, 0 TSRMLS_CC);
682 }
683 /* }}} */
684
685 /* {{{ php_crypto_get_cipher_mode_ex */
php_crypto_get_cipher_mode_ex(long mode_value)686 PHP_CRYPTO_API const php_crypto_cipher_mode *php_crypto_get_cipher_mode_ex(long mode_value)
687 {
688 const php_crypto_cipher_mode *mode;
689
690 for (mode = php_crypto_cipher_modes; mode->name[0]; mode++) {
691 if (mode_value == mode->value) {
692 return mode;
693 }
694 }
695 return NULL;
696 }
697 /* }}} */
698
699 /* {{{ php_crypto_get_cipher_mode_ex */
php_crypto_get_cipher_mode(const EVP_CIPHER * cipher)700 PHP_CRYPTO_API const php_crypto_cipher_mode *php_crypto_get_cipher_mode(const EVP_CIPHER *cipher)
701 {
702 return php_crypto_get_cipher_mode_ex(EVP_CIPHER_mode(cipher));
703 }
704 /* }}} */
705
706 /* {{{ php_crypto_cipher_is_mode_authenticated_ex */
php_crypto_cipher_is_mode_authenticated_ex(const php_crypto_cipher_mode * mode TSRMLS_DC)707 static int php_crypto_cipher_is_mode_authenticated_ex(const php_crypto_cipher_mode *mode TSRMLS_DC)
708 {
709 if (!mode) { /* this should never happen */
710 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, MODE_NOT_FOUND));
711 return FAILURE;
712 }
713 if (!mode->auth_enc) {
714 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, AUTHENTICATION_NOT_SUPPORTED),
715 mode->name);
716 return FAILURE;
717 }
718 return SUCCESS;
719 }
720
721 /* {{{ php_crypto_cipher_is_mode_authenticated */
php_crypto_cipher_is_mode_authenticated(PHPC_THIS_DECLARE (crypto_cipher)TSRMLS_DC)722 static int php_crypto_cipher_is_mode_authenticated(PHPC_THIS_DECLARE(crypto_cipher) TSRMLS_DC)
723 {
724 return php_crypto_cipher_is_mode_authenticated_ex(
725 php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS)) TSRMLS_CC);
726 }
727 /* }}} */
728
729 /* {{{ php_crypto_cipher_set_tag */
php_crypto_cipher_set_tag(EVP_CIPHER_CTX * cipher_ctx,const php_crypto_cipher_mode * mode,unsigned char * tag,int tag_len TSRMLS_DC)730 PHP_CRYPTO_API int php_crypto_cipher_set_tag(EVP_CIPHER_CTX *cipher_ctx,
731 const php_crypto_cipher_mode *mode, unsigned char *tag, int tag_len TSRMLS_DC)
732 {
733 if (!tag) {
734 return SUCCESS;
735 }
736 if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->auth_set_tag_flag, tag_len, tag)) {
737 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_SETTER_FAILED));
738 return FAILURE;
739 }
740 return SUCCESS;
741 }
742 /* }}} */
743
744 /* {{{ php_crypto_cipher_check_tag_len */
php_crypto_cipher_check_tag_len(int tag_len TSRMLS_DC)745 static int php_crypto_cipher_check_tag_len(int tag_len TSRMLS_DC)
746 {
747 if (tag_len < PHP_CRYPTO_CIPHER_AUTH_TAG_LENGTH_MIN) {
748 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_LENGTH_LOW));
749 return FAILURE;
750 }
751 if (tag_len > PHP_CRYPTO_CIPHER_AUTH_TAG_LENGTH_MAX) {
752 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_LENGTH_HIGH));
753 return FAILURE;
754 }
755 return SUCCESS;
756 }
757 /* }}} */
758
759 /* {{{ php_crypto_cipher_check_key_len */
php_crypto_cipher_check_key_len(zval * zobject,PHPC_THIS_DECLARE (crypto_cipher),phpc_str_size_t key_len TSRMLS_DC)760 static int php_crypto_cipher_check_key_len(zval *zobject, PHPC_THIS_DECLARE(crypto_cipher),
761 phpc_str_size_t key_len TSRMLS_DC)
762 {
763 int int_key_len, alg_key_len = EVP_CIPHER_key_length(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS));
764 PHPC_READ_PROPERTY_RV_DECLARE;
765
766 if (php_crypto_str_size_to_int(key_len, &int_key_len) == SUCCESS &&
767 int_key_len != alg_key_len &&
768 !EVP_CIPHER_CTX_set_key_length(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS), int_key_len)) {
769 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, KEY_LENGTH_INVALID),
770 PHP_CRYPTO_CIPHER_GET_ALGORITHM_NAME(zobject), alg_key_len);
771 return FAILURE;
772 }
773 return SUCCESS;
774 }
775 /* }}} */
776
777 /* {{{ php_crypto_cipher_check_iv_len */
php_crypto_cipher_check_iv_len(zval * zobject,PHPC_THIS_DECLARE (crypto_cipher),const php_crypto_cipher_mode * mode,phpc_str_size_t iv_len TSRMLS_DC)778 static int php_crypto_cipher_check_iv_len(zval *zobject, PHPC_THIS_DECLARE(crypto_cipher),
779 const php_crypto_cipher_mode *mode, phpc_str_size_t iv_len TSRMLS_DC)
780 {
781 int int_iv_len, alg_iv_len = EVP_CIPHER_iv_length(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS));
782 PHPC_READ_PROPERTY_RV_DECLARE;
783
784 if (php_crypto_str_size_to_int(iv_len, &int_iv_len) == FAILURE) {
785 return FAILURE;
786 }
787
788 if (int_iv_len == alg_iv_len) {
789 return SUCCESS;
790 }
791
792 if (!mode->auth_enc || int_iv_len == INT_MAX ||
793 !EVP_CIPHER_CTX_ctrl(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
794 mode->auth_ivlen_flag, int_iv_len, NULL)) {
795 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, IV_LENGTH_INVALID),
796 PHP_CRYPTO_CIPHER_GET_ALGORITHM_NAME(zobject), alg_iv_len);
797 return FAILURE;
798 }
799 return SUCCESS;
800 }
801 /* }}} */
802
803 /* {{{ php_crypto_cipher_init_ex */
PHPC_OBJ_STRUCT_NAME(crypto_cipher)804 static PHPC_OBJ_STRUCT_NAME(crypto_cipher) *php_crypto_cipher_init_ex(
805 zval *zobject, char *key, phpc_str_size_t key_len,
806 char *iv, phpc_str_size_t iv_len, int enc TSRMLS_DC)
807 {
808 const php_crypto_cipher_mode *mode;
809 PHPC_THIS_DECLARE_AND_FETCH_FROM_ZVAL(crypto_cipher, zobject);
810
811 /* check algorithm status */
812 if (enc && PHP_CRYPTO_CIPHER_IS_INITIALIZED_FOR_DECRYPTION(PHPC_THIS)) {
813 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, INIT_ENCRYPT_FORBIDDEN));
814 return NULL;
815 } else if (!enc && PHP_CRYPTO_CIPHER_IS_INITIALIZED_FOR_ENCRYPTION(PHPC_THIS)) {
816 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, INIT_DECRYPT_FORBIDDEN));
817 return NULL;
818 }
819
820 /* initialize encryption/decryption */
821 if (!EVP_CipherInit_ex(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS), PHP_CRYPTO_CIPHER_ALG(PHPC_THIS),
822 NULL, NULL, NULL, enc)) {
823 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, INIT_ALG_FAILED));
824 return NULL;
825 }
826
827 /* check key length */
828 if (php_crypto_cipher_check_key_len(zobject, PHPC_THIS, key_len TSRMLS_CC) == FAILURE) {
829 return NULL;
830 }
831
832 /* get mode */
833 mode = php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
834
835 /* mode with inlen init requires also pre-setting tag length */
836 if (mode->auth_inlen_init && enc) {
837 EVP_CIPHER_CTX_ctrl(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS), mode->auth_set_tag_flag,
838 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS), NULL);
839 }
840
841 /* check initialization vector length */
842 if (php_crypto_cipher_check_iv_len(zobject, PHPC_THIS, mode, iv_len TSRMLS_CC) == FAILURE) {
843 return NULL;
844 }
845
846 if (mode->auth_enc && !enc &&
847 php_crypto_cipher_set_tag(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS), mode,
848 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS),
849 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS) ? PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS) : 0
850 TSRMLS_CC) == FAILURE) {
851 return NULL;
852 }
853
854 /* initialize encryption */
855 if (!EVP_CipherInit_ex(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS), NULL, NULL,
856 (unsigned char *) key, (unsigned char *) iv, enc)) {
857 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, INIT_CTX_FAILED));
858 return NULL;
859 }
860 PHP_CRYPTO_CIPHER_SET_STATUS(PHPC_THIS, enc, INIT);
861
862
863 return PHPC_THIS;
864 }
865 /* }}} */
866
867 /* {{{ php_crypto_cipher_init */
php_crypto_cipher_init(INTERNAL_FUNCTION_PARAMETERS,int enc)868 static inline void php_crypto_cipher_init(INTERNAL_FUNCTION_PARAMETERS, int enc)
869 {
870 char *key, *iv = NULL;
871 phpc_str_size_t key_len, iv_len = 0;
872
873 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
874 &key, &key_len, &iv, &iv_len) == FAILURE) {
875 return;
876 }
877
878 if (php_crypto_cipher_init_ex(getThis(), key, key_len, iv, iv_len, enc TSRMLS_CC)) {
879 RETURN_TRUE;
880 } else {
881 RETURN_FALSE;
882 }
883 }
884 /* }}} */
885
886 /* {{{ php_crypto_cipher_write_aad */
php_crypto_cipher_write_aad(EVP_CIPHER_CTX * cipher_ctx,unsigned char * aad,int aad_len TSRMLS_DC)887 PHP_CRYPTO_API int php_crypto_cipher_write_aad(
888 EVP_CIPHER_CTX *cipher_ctx, unsigned char *aad, int aad_len TSRMLS_DC)
889 {
890 int outlen, ret;
891
892 if (aad) {
893 ret = EVP_CipherUpdate(cipher_ctx, NULL, &outlen, aad, aad_len);
894 } else {
895 unsigned char buf[4];
896 ret = EVP_CipherUpdate(cipher_ctx, NULL, &outlen, buf, 0);
897 }
898
899 if (!ret) {
900 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, AAD_SETTER_FAILED));
901 return FAILURE;
902 }
903 return SUCCESS;
904 }
905 /* }}} */
906
907 /* {{{ php_crypto_cipher_write_inlen */
php_crypto_cipher_write_inlen(EVP_CIPHER_CTX * cipher_ctx,int inlen TSRMLS_DC)908 static int php_crypto_cipher_write_inlen(
909 EVP_CIPHER_CTX *cipher_ctx, int inlen TSRMLS_DC)
910 {
911 int outlen;
912
913 if (!EVP_CipherUpdate(cipher_ctx, NULL, &outlen, NULL, inlen)) {
914 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, UPDATE_FAILED));
915 return FAILURE;
916 }
917 return SUCCESS;
918 }
919 /* }}} */
920
921 /* {{{ php_crypto_cipher_auth_init */
php_crypto_cipher_auth_init(PHPC_THIS_DECLARE (crypto_cipher),int inlen TSRMLS_DC)922 static int php_crypto_cipher_auth_init(
923 PHPC_THIS_DECLARE(crypto_cipher), int inlen TSRMLS_DC)
924 {
925 EVP_CIPHER_CTX *cipher_ctx = PHP_CRYPTO_CIPHER_CTX(PHPC_THIS);
926 const php_crypto_cipher_mode *mode = php_crypto_get_cipher_mode_ex(
927 PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
928
929 /* auth init is just for auth modes */
930 if (!mode->auth_enc) {
931 return SUCCESS;
932 }
933
934 /* check if plain text length needs to be initialized (CCM mode) */
935 if (mode->auth_inlen_init && php_crypto_cipher_write_inlen(
936 cipher_ctx, inlen TSRMLS_CC) == FAILURE) {
937 return FAILURE;
938 }
939
940 /* write additional authenticated data */
941 if (php_crypto_cipher_write_aad(
942 cipher_ctx,
943 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS),
944 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS) TSRMLS_CC) == FAILURE) {
945 return FAILURE;
946 }
947
948 return SUCCESS;
949 }
950 /* }}} */
951
952 /* {{{ php_crypto_cipher_update */
php_crypto_cipher_update(INTERNAL_FUNCTION_PARAMETERS,int enc)953 static inline void php_crypto_cipher_update(INTERNAL_FUNCTION_PARAMETERS, int enc)
954 {
955 PHPC_THIS_DECLARE(crypto_cipher);
956 PHPC_STR_DECLARE(out);
957 char *data;
958 phpc_str_size_t data_str_size;
959 int out_len, update_len, data_len;
960
961 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_str_size) == FAILURE) {
962 return;
963 }
964
965 if (php_crypto_str_size_to_int(data_str_size, &data_len)) {
966 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, INPUT_DATA_LENGTH_HIGH));
967 RETURN_FALSE;
968 }
969
970 PHPC_THIS_FETCH(crypto_cipher);
971
972 /* check algorithm status */
973 if (enc && !PHP_CRYPTO_CIPHER_IS_INITIALIZED_FOR_ENCRYPTION(PHPC_THIS)) {
974 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, UPDATE_ENCRYPT_FORBIDDEN));
975 RETURN_FALSE;
976 } else if (!enc && !PHP_CRYPTO_CIPHER_IS_INITIALIZED_FOR_DECRYPTION(PHPC_THIS)) {
977 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, UPDATE_DECRYPT_FORBIDDEN));
978 RETURN_FALSE;
979 }
980
981 /* if the crypto is in init state (first update), then do auth init */
982 if (PHP_CRYPTO_CIPHER_IS_IN_INIT_STATE(PHPC_THIS) &&
983 php_crypto_cipher_auth_init(PHPC_THIS, data_len TSRMLS_CC) == FAILURE) {
984 RETURN_FALSE;
985 }
986
987 out_len = data_len + EVP_CIPHER_block_size(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS));
988 update_len = out_len;
989 PHPC_STR_ALLOC(out, out_len);
990
991 /* update encryption context */
992 if (!EVP_CipherUpdate(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
993 (unsigned char *) PHPC_STR_VAL(out), &update_len,
994 (unsigned char *) data, data_len)) {
995 /* get mode info */
996 const php_crypto_cipher_mode *mode = php_crypto_get_cipher_mode_ex(
997 PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
998
999 if (!enc && mode->auth_inlen_init) {
1000 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_VERIFY_FAILED));
1001 } else {
1002 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, UPDATE_FAILED));
1003 }
1004 PHPC_STR_RELEASE(out);
1005 RETURN_FALSE;
1006 }
1007 PHP_CRYPTO_CIPHER_SET_STATUS(PHPC_THIS, enc, UPDATE);
1008 if (out_len > update_len) {
1009 PHPC_STR_REALLOC(out, update_len);
1010 }
1011 PHPC_STR_VAL(out)[update_len] = 0;
1012 PHPC_STR_RETURN(out);
1013 }
1014 /* }}} */
1015
1016 /* {{{ php_crypto_cipher_finish */
php_crypto_cipher_finish(INTERNAL_FUNCTION_PARAMETERS,int enc)1017 static inline void php_crypto_cipher_finish(INTERNAL_FUNCTION_PARAMETERS, int enc)
1018 {
1019 PHPC_THIS_DECLARE(crypto_cipher);
1020 PHPC_STR_DECLARE(out);
1021 const php_crypto_cipher_mode *mode;
1022 int out_len, final_len = 0;
1023
1024 if (zend_parse_parameters_none() == FAILURE) {
1025 return;
1026 }
1027
1028 PHPC_THIS_FETCH(crypto_cipher);
1029
1030 /* check algorithm status */
1031 if (enc && !PHP_CRYPTO_CIPHER_IS_INITIALIZED_FOR_ENCRYPTION(PHPC_THIS)) {
1032 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, FINISH_ENCRYPT_FORBIDDEN));
1033 RETURN_FALSE;
1034 } else if (!enc && !PHP_CRYPTO_CIPHER_IS_INITIALIZED_FOR_DECRYPTION(PHPC_THIS)) {
1035 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, FINISH_DECRYPT_FORBIDDEN));
1036 RETURN_FALSE;
1037 }
1038
1039 out_len = EVP_CIPHER_block_size(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS));
1040 PHPC_STR_ALLOC(out, out_len);
1041
1042 /* get mode info */
1043 mode = php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
1044
1045 /* finalize cipher context */
1046 if ((enc || !mode->auth_inlen_init) && !EVP_CipherFinal_ex(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
1047 (unsigned char *) PHPC_STR_VAL(out), &final_len)) {
1048 if (!enc && mode->auth_enc) {
1049 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_VERIFY_FAILED));
1050 } else {
1051 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, FINISH_FAILED));
1052 }
1053 PHPC_STR_RELEASE(out);
1054 RETURN_FALSE;
1055 }
1056 PHP_CRYPTO_CIPHER_SET_STATUS(PHPC_THIS, enc, FINAL);
1057 if (out_len > final_len) {
1058 PHPC_STR_REALLOC(out, final_len);
1059 }
1060 PHPC_STR_VAL(out)[final_len] = 0;
1061 PHPC_STR_RETURN(out);
1062 }
1063 /* }}} */
1064
1065 /* {{{ php_crypto_cipher_crypt */
php_crypto_cipher_crypt(INTERNAL_FUNCTION_PARAMETERS,int enc)1066 static inline void php_crypto_cipher_crypt(INTERNAL_FUNCTION_PARAMETERS, int enc)
1067 {
1068 PHPC_THIS_DECLARE(crypto_cipher);
1069 PHPC_STR_DECLARE(out);
1070 const php_crypto_cipher_mode *mode;
1071 char *data, *key, *iv = NULL;
1072 phpc_str_size_t data_str_size, key_len, iv_len = 0;
1073 int data_len, update_len, out_len, final_len = 0;
1074
1075 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s",
1076 &data, &data_str_size, &key, &key_len, &iv, &iv_len) == FAILURE) {
1077 return;
1078 }
1079
1080 if (php_crypto_str_size_to_int(data_str_size, &data_len)) {
1081 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, INPUT_DATA_LENGTH_HIGH));
1082 RETURN_FALSE;
1083 }
1084
1085 PHPC_THIS = php_crypto_cipher_init_ex(getThis(), key, key_len, iv, iv_len, enc TSRMLS_CC);
1086 if (PHPC_THIS == NULL) {
1087 RETURN_FALSE;
1088 }
1089
1090 /* do auth init */
1091 if (php_crypto_cipher_auth_init(PHPC_THIS, data_len TSRMLS_CC) == FAILURE) {
1092 RETURN_FALSE;
1093 }
1094
1095 out_len = data_len + EVP_CIPHER_block_size(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS));
1096 PHPC_STR_ALLOC(out, out_len);
1097
1098 /* get mode info */
1099 mode = php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
1100
1101 /* update encryption context */
1102 if (!EVP_CipherUpdate(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
1103 (unsigned char *) PHPC_STR_VAL(out), &update_len,
1104 (unsigned char *) data, data_len)) {
1105 if (!enc && mode->auth_inlen_init) {
1106 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_VERIFY_FAILED));
1107 } else {
1108 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, UPDATE_FAILED));
1109 }
1110 PHPC_STR_RELEASE(out);
1111 RETURN_FALSE;
1112 }
1113
1114 /* finalize cipher context */
1115 if ((enc || !mode->auth_inlen_init) && !EVP_CipherFinal_ex(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
1116 (unsigned char *) (PHPC_STR_VAL(out) + update_len), &final_len)) {
1117 if (!enc && mode->auth_enc) {
1118 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_VERIFY_FAILED));
1119 } else {
1120 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, FINISH_FAILED));
1121 }
1122 PHPC_STR_RELEASE(out);
1123 RETURN_FALSE;
1124 }
1125 PHP_CRYPTO_CIPHER_SET_STATUS(PHPC_THIS, enc, FINAL);
1126
1127 final_len += update_len;
1128 if (out_len > final_len) {
1129 PHPC_STR_REALLOC(out, final_len);
1130 }
1131 PHPC_STR_VAL(out)[final_len] = 0;
1132 PHPC_STR_RETURN(out);
1133 }
1134 /* }}} */
1135
1136 /* {{{ proto static string Crypto\Cipher::getAlgorithms(bool $aliases = false,
1137 string $prefix = null)
1138 Returns cipher algorithms */
PHP_CRYPTO_METHOD(Cipher,getAlgorithms)1139 PHP_CRYPTO_METHOD(Cipher, getAlgorithms)
1140 {
1141 php_crypto_object_fn_get_names(INTERNAL_FUNCTION_PARAM_PASSTHRU,
1142 OBJ_NAME_TYPE_CIPHER_METH);
1143 }
1144 /* }}} */
1145
1146 /* {{{ proto static bool Crypto\Cipher::hasAlgorithm(string $algorithm)
1147 Finds out whether algorithm exists */
PHP_CRYPTO_METHOD(Cipher,hasAlgorithm)1148 PHP_CRYPTO_METHOD(Cipher, hasAlgorithm)
1149 {
1150 char *algorithm;
1151 phpc_str_size_t algorithm_len;
1152
1153 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
1154 &algorithm, &algorithm_len) == FAILURE) {
1155 return;
1156 }
1157
1158 if (php_crypto_get_cipher_algorithm(algorithm, algorithm_len)) {
1159 RETURN_TRUE;
1160 } else {
1161 RETURN_FALSE;
1162 }
1163 }
1164 /* }}} */
1165
1166 /* {{{ proto static bool Crypto\Cipher::hasMode(int $mode)
1167 Finds out whether the cipher mode is defined in the used OpenSSL library */
PHP_CRYPTO_METHOD(Cipher,hasMode)1168 PHP_CRYPTO_METHOD(Cipher, hasMode)
1169 {
1170 phpc_long_t mode;
1171
1172 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
1173 return;
1174 }
1175
1176 RETURN_BOOL(mode != PHP_CRYPTO_CIPHER_MODE_NOT_DEFINED && (mode & EVP_CIPH_MODE));
1177 }
1178 /* }}} */
1179
1180 /* {{{ proto static Crypto\Cipher::__callStatic(string $name, array $arguments)
1181 Cipher magic method for calling static methods */
PHP_CRYPTO_METHOD(Cipher,__callStatic)1182 PHP_CRYPTO_METHOD(Cipher, __callStatic)
1183 {
1184 char *algorithm;
1185 int argc;
1186 phpc_str_size_t algorithm_len;
1187 phpc_val *ppv_mode;
1188 zval *pz_mode, *pz_key_size, *args;
1189
1190 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa",
1191 &algorithm, &algorithm_len, &args) == FAILURE) {
1192 return;
1193 }
1194
1195 argc = PHPC_HASH_NUM_ELEMENTS(Z_ARRVAL_P(args));
1196 if (argc > 2) {
1197 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, STATIC_METHOD_TOO_MANY_ARGS), algorithm);
1198 return;
1199 }
1200
1201 object_init_ex(return_value, php_crypto_cipher_ce);
1202
1203 if (argc == 0) {
1204 if (php_crypto_set_cipher_algorithm(
1205 return_value, algorithm, algorithm_len TSRMLS_CC) == FAILURE) {
1206 php_crypto_error_ex(PHP_CRYPTO_ERROR_ARGS(Cipher, STATIC_METHOD_NOT_FOUND), algorithm);
1207 }
1208 return;
1209 }
1210
1211 PHPC_HASH_INTERNAL_POINTER_RESET(Z_ARRVAL_P(args));
1212 PHPC_HASH_GET_CURRENT_DATA(Z_ARRVAL_P(args), ppv_mode);
1213 PHPC_PVAL_TO_PZVAL(ppv_mode, pz_mode);
1214 if (argc == 1) {
1215 pz_key_size = NULL;
1216 } else {
1217 phpc_val *ppv_key_size;
1218 PHPC_HASH_MOVE_FORWARD(Z_ARRVAL_P(args));
1219 PHPC_HASH_GET_CURRENT_DATA(Z_ARRVAL_P(args), ppv_key_size);
1220 PHPC_PVAL_TO_PZVAL(ppv_key_size, pz_key_size);
1221 }
1222 php_crypto_set_cipher_algorithm_from_params_ex(
1223 return_value, algorithm, algorithm_len, pz_mode, pz_key_size, 1 TSRMLS_CC);
1224 }
1225 /* }}} */
1226
1227 /* {{{ proto Crypto\Cipher::__construct(string $algorithm, int $mode = NULL, string $key_size = NULL)
1228 Cipher constructor */
PHP_CRYPTO_METHOD(Cipher,__construct)1229 PHP_CRYPTO_METHOD(Cipher, __construct)
1230 {
1231 char *algorithm, *algorithm_uc;
1232 phpc_str_size_t algorithm_len;
1233 zval *mode = NULL, *key_size = NULL;
1234
1235 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zz",
1236 &algorithm, &algorithm_len, &mode, &key_size) == FAILURE) {
1237 return;
1238 }
1239
1240 algorithm_uc = estrdup(algorithm);
1241 php_crypto_set_cipher_algorithm_from_params(
1242 getThis(), algorithm_uc, strlen(algorithm_uc), mode, key_size TSRMLS_CC);
1243 efree(algorithm_uc);
1244 }
1245 /* }}} */
1246
1247 /* {{{ proto string Crypto\Cipher::getAlgorithmName()
1248 Returns cipher algorithm string */
PHP_CRYPTO_METHOD(Cipher,getAlgorithmName)1249 PHP_CRYPTO_METHOD(Cipher, getAlgorithmName)
1250 {
1251 zval *algorithm;
1252 PHPC_READ_PROPERTY_RV_DECLARE;
1253
1254 algorithm = PHP_CRYPTO_CIPHER_GET_ALGORITHM_NAME_EX(getThis());
1255 RETURN_ZVAL(algorithm, 1, 0);
1256 }
1257 /* }}} */
1258
1259 /* {{{ proto bool Crypto\Cipher::encryptInit(string $key, string $iv = null)
1260 Initializes cipher encryption */
PHP_CRYPTO_METHOD(Cipher,encryptInit)1261 PHP_CRYPTO_METHOD(Cipher, encryptInit)
1262 {
1263 php_crypto_cipher_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1264 }
1265
1266 /* {{{ proto string Crypto\Cipher::encryptUpdate(string $data)
1267 Updates cipher encryption */
PHP_CRYPTO_METHOD(Cipher,encryptUpdate)1268 PHP_CRYPTO_METHOD(Cipher, encryptUpdate)
1269 {
1270 php_crypto_cipher_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1271 }
1272
1273 /* {{{ proto string Crypto\Cipher::encryptFinish()
1274 Finalizes cipher encryption */
PHP_CRYPTO_METHOD(Cipher,encryptFinish)1275 PHP_CRYPTO_METHOD(Cipher, encryptFinish)
1276 {
1277 php_crypto_cipher_finish(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1278 }
1279
1280 /* {{{ proto string Crypto\Cipher::encrypt(string $data, string $key, string $iv = null)
1281 Encrypts text to ciphertext */
PHP_CRYPTO_METHOD(Cipher,encrypt)1282 PHP_CRYPTO_METHOD(Cipher, encrypt)
1283 {
1284 php_crypto_cipher_crypt(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1285 }
1286
1287 /* {{{ proto void Crypto\Cipher::decryptInit(string $key, string $iv = null)
1288 Initializes cipher decryption */
PHP_CRYPTO_METHOD(Cipher,decryptInit)1289 PHP_CRYPTO_METHOD(Cipher, decryptInit)
1290 {
1291 php_crypto_cipher_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1292 }
1293
1294 /* {{{ proto string Crypto\Cipher::decryptUpdate(string $data)
1295 Updates cipher decryption */
PHP_CRYPTO_METHOD(Cipher,decryptUpdate)1296 PHP_CRYPTO_METHOD(Cipher, decryptUpdate)
1297 {
1298 php_crypto_cipher_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1299 }
1300
1301 /* {{{ proto string Crypto\Cipher::decryptFinish()
1302 Finalizes cipher decryption */
PHP_CRYPTO_METHOD(Cipher,decryptFinish)1303 PHP_CRYPTO_METHOD(Cipher, decryptFinish)
1304 {
1305 php_crypto_cipher_finish(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1306 }
1307
1308 /* {{{ proto string Crypto\Cipher::decrypt(string $data, string $key, string $iv = null)
1309 Decrypts ciphertext to decrypted text */
PHP_CRYPTO_METHOD(Cipher,decrypt)1310 PHP_CRYPTO_METHOD(Cipher, decrypt)
1311 {
1312 php_crypto_cipher_crypt(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1313 }
1314
1315 /* {{{ proto int Crypto\Cipher::getBlockSize()
1316 Returns cipher block size */
PHP_CRYPTO_METHOD(Cipher,getBlockSize)1317 PHP_CRYPTO_METHOD(Cipher, getBlockSize)
1318 {
1319 PHPC_THIS_DECLARE(crypto_cipher);
1320
1321 if (zend_parse_parameters_none() == FAILURE) {
1322 return;
1323 }
1324
1325 PHPC_THIS_FETCH(crypto_cipher);
1326 RETURN_LONG(EVP_CIPHER_block_size(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS)));
1327 }
1328
1329 /* {{{ proto int Crypto\Cipher::getKeyLength()
1330 Returns cipher key length */
PHP_CRYPTO_METHOD(Cipher,getKeyLength)1331 PHP_CRYPTO_METHOD(Cipher, getKeyLength)
1332 {
1333 PHPC_THIS_DECLARE(crypto_cipher);
1334
1335 if (zend_parse_parameters_none() == FAILURE) {
1336 return;
1337 }
1338
1339 PHPC_THIS_FETCH(crypto_cipher);
1340 RETURN_LONG(EVP_CIPHER_key_length(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS)));
1341 }
1342
1343 /* {{{ proto int Crypto\Cipher::getIVLength()
1344 Returns cipher IV length */
PHP_CRYPTO_METHOD(Cipher,getIVLength)1345 PHP_CRYPTO_METHOD(Cipher, getIVLength)
1346 {
1347 PHPC_THIS_DECLARE(crypto_cipher);
1348
1349 if (zend_parse_parameters_none() == FAILURE) {
1350 return;
1351 }
1352
1353 PHPC_THIS_FETCH(crypto_cipher);
1354 RETURN_LONG(EVP_CIPHER_iv_length(PHP_CRYPTO_CIPHER_ALG(PHPC_THIS)));
1355 }
1356
1357 /* {{{ proto int Crypto\Cipher::getMode()
1358 Returns cipher mode */
PHP_CRYPTO_METHOD(Cipher,getMode)1359 PHP_CRYPTO_METHOD(Cipher, getMode)
1360 {
1361 PHPC_THIS_DECLARE(crypto_cipher);
1362
1363 if (zend_parse_parameters_none() == FAILURE) {
1364 return;
1365 }
1366
1367 PHPC_THIS_FETCH(crypto_cipher);
1368 RETURN_LONG(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
1369 }
1370 /* }}} */
1371
1372 /* {{{ proto string Crypto\Cipher::getTag()
1373 Returns authentication tag */
PHP_CRYPTO_METHOD(Cipher,getTag)1374 PHP_CRYPTO_METHOD(Cipher, getTag)
1375 {
1376 PHPC_THIS_DECLARE(crypto_cipher);
1377 const php_crypto_cipher_mode *mode;
1378 PHPC_STR_DECLARE(tag);
1379 int tag_len;
1380
1381 if (zend_parse_parameters_none() == FAILURE) {
1382 return;
1383 }
1384
1385 PHPC_THIS_FETCH(crypto_cipher);
1386 mode = php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
1387 if (php_crypto_cipher_is_mode_authenticated_ex(mode TSRMLS_CC) == FAILURE) {
1388 RETURN_FALSE;
1389 }
1390
1391 if (PHPC_THIS->status != PHP_CRYPTO_CIPHER_STATUS_ENCRYPT_FINAL) {
1392 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_GETTER_FORBIDDEN));
1393 RETURN_FALSE;
1394 }
1395
1396 tag_len = PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS);
1397 PHPC_STR_ALLOC(tag, tag_len);
1398 PHPC_STR_VAL(tag)[tag_len] = 0;
1399
1400 if (!EVP_CIPHER_CTX_ctrl(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS),
1401 mode->auth_get_tag_flag, tag_len, PHPC_STR_VAL(tag))) {
1402 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_GETTER_FAILED));
1403 RETURN_FALSE;
1404 }
1405
1406 PHPC_STR_RETURN(tag);
1407 }
1408 /* }}} */
1409
1410 /* {{{ proto bool Crypto\Cipher::setTag(string $tag)
1411 Sets authentication tag */
PHP_CRYPTO_METHOD(Cipher,setTag)1412 PHP_CRYPTO_METHOD(Cipher, setTag)
1413 {
1414 PHPC_THIS_DECLARE(crypto_cipher);
1415 const php_crypto_cipher_mode *mode;
1416 char *tag;
1417 phpc_str_size_t tag_str_size;
1418 int tag_len;
1419
1420 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tag, &tag_str_size) == FAILURE) {
1421 return;
1422 }
1423
1424 PHPC_THIS_FETCH(crypto_cipher);
1425 mode = php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
1426 if (php_crypto_cipher_is_mode_authenticated_ex(mode TSRMLS_CC) == FAILURE ||
1427 php_crypto_str_size_to_int(tag_str_size, &tag_len) == FAILURE ||
1428 php_crypto_cipher_check_tag_len(tag_len TSRMLS_CC) == FAILURE) {
1429 RETURN_FALSE;
1430 }
1431
1432 if (PHPC_THIS->status == PHP_CRYPTO_CIPHER_STATUS_CLEAR) {
1433 if (!PHP_CRYPTO_CIPHER_TAG(PHPC_THIS)) {
1434 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS) = emalloc(tag_len + 1);
1435 } else if (PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS) < tag_len) {
1436 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS) = erealloc(
1437 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS), tag_len + 1);
1438 }
1439 memcpy(PHP_CRYPTO_CIPHER_TAG(PHPC_THIS), tag, tag_len + 1);
1440 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS) = tag_len;
1441 } else if (PHPC_THIS->status == PHP_CRYPTO_CIPHER_STATUS_DECRYPT_INIT) {
1442 php_crypto_cipher_set_tag(PHP_CRYPTO_CIPHER_CTX(PHPC_THIS), mode,
1443 (unsigned char *) tag, tag_len TSRMLS_CC);
1444 } else {
1445 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_SETTER_FORBIDDEN));
1446 RETURN_FALSE;
1447 }
1448 RETURN_TRUE;
1449 }
1450 /* }}} */
1451
1452 /* {{{ proto bool Crypto\Cipher::setTagLength(int $tag_length)
1453 Set authentication tag length */
PHP_CRYPTO_METHOD(Cipher,setTagLength)1454 PHP_CRYPTO_METHOD(Cipher, setTagLength)
1455 {
1456 PHPC_THIS_DECLARE(crypto_cipher);
1457 const php_crypto_cipher_mode *mode;
1458 phpc_long_t tag_len_long;
1459 int tag_len;
1460
1461 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag_len_long) == FAILURE) {
1462 return;
1463 }
1464
1465 PHPC_THIS_FETCH(crypto_cipher);
1466 mode = php_crypto_get_cipher_mode_ex(PHP_CRYPTO_CIPHER_MODE_VALUE(PHPC_THIS));
1467 if (php_crypto_cipher_is_mode_authenticated_ex(mode TSRMLS_CC) == FAILURE ||
1468 PHP_CRYPTO_CIPHER_TAG(PHPC_THIS) ||
1469 php_crypto_long_to_int(tag_len_long, &tag_len) == FAILURE ||
1470 php_crypto_cipher_check_tag_len(tag_len TSRMLS_CC) == FAILURE) {
1471 RETURN_FALSE;
1472 }
1473
1474 if (PHPC_THIS->status != PHP_CRYPTO_CIPHER_STATUS_ENCRYPT_INIT &&
1475 PHPC_THIS->status != PHP_CRYPTO_CIPHER_STATUS_CLEAR) {
1476 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, TAG_LENGTH_SETTER_FORBIDDEN));
1477 RETURN_FALSE;
1478 }
1479
1480 PHP_CRYPTO_CIPHER_TAG_LEN(PHPC_THIS) = tag_len;
1481
1482 RETURN_TRUE;
1483 }
1484 /* }}} */
1485
1486 /* {{{ proto bool Crypto\Cipher::setAAD(string $aad)
1487 Sets additional application data for authenticated encryption */
PHP_CRYPTO_METHOD(Cipher,setAAD)1488 PHP_CRYPTO_METHOD(Cipher, setAAD)
1489 {
1490 PHPC_THIS_DECLARE(crypto_cipher);
1491 char *aad;
1492 phpc_str_size_t aad_str_size;
1493 int aad_len;
1494
1495 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &aad, &aad_str_size) == FAILURE) {
1496 return;
1497 }
1498
1499 PHPC_THIS_FETCH(crypto_cipher);
1500 if (php_crypto_cipher_is_mode_authenticated(PHPC_THIS TSRMLS_CC) == FAILURE) {
1501 RETURN_FALSE;
1502 }
1503
1504 if (php_crypto_str_size_to_int(aad_str_size, &aad_len) == FAILURE) {
1505 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, AAD_LENGTH_HIGH));
1506 RETURN_FALSE;
1507 } else if (PHPC_THIS->status == PHP_CRYPTO_CIPHER_STATUS_CLEAR ||
1508 PHPC_THIS->status == PHP_CRYPTO_CIPHER_STATUS_ENCRYPT_INIT ||
1509 PHPC_THIS->status == PHP_CRYPTO_CIPHER_STATUS_DECRYPT_INIT) {
1510 if (!PHP_CRYPTO_CIPHER_AAD(PHPC_THIS)) {
1511 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS) = emalloc(aad_len + 1);
1512 } else if (PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS) < aad_len) {
1513 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS) = erealloc(
1514 PHP_CRYPTO_CIPHER_AAD(PHPC_THIS), aad_len + 1);
1515 }
1516 memcpy(PHP_CRYPTO_CIPHER_AAD(PHPC_THIS), aad, aad_len + 1);
1517 PHP_CRYPTO_CIPHER_AAD_LEN(PHPC_THIS) = aad_len;
1518 } else {
1519 php_crypto_error(PHP_CRYPTO_ERROR_ARGS(Cipher, AAD_SETTER_FORBIDDEN));
1520 RETURN_FALSE;
1521 }
1522 RETURN_TRUE;
1523 }
1524 /* }}} */
1525