summaryrefslogtreecommitdiff
path: root/src/sp_crypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp_crypt.c')
-rw-r--r--src/sp_crypt.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/sp_crypt.c b/src/sp_crypt.c
new file mode 100644
index 0000000..0c40f1f
--- /dev/null
+++ b/src/sp_crypt.c
@@ -0,0 +1,136 @@
1#include "php_snuffleupagus.h"
2
3#include "ext/standard/url.h"
4
5ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
6
7static zend_long nonce_d = 0;
8
9static void generate_key(unsigned char *key) {
10 PHP_SHA256_CTX ctx;
11 const char *user_agent = getenv("HTTP_USER_AGENT");
12 const char *env_var =
13 getenv(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var);
14 const char *encryption_key =
15 SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key;
16
17 assert(32 == crypto_secretbox_KEYBYTES); // 32 is the size of a SHA256.
18 assert(encryption_key); // Encryption key can't be NULL
19
20 PHP_SHA256Init(&ctx);
21
22 if (user_agent) {
23 PHP_SHA256Update(&ctx, (unsigned char *)user_agent, strlen(user_agent));
24 }
25
26 if (env_var) {
27 PHP_SHA256Update(&ctx, (unsigned char *)env_var, strlen(env_var));
28 } else {
29 sp_log_err("cookie_encryption",
30 "The environment variable '%s'"
31 "is empty, cookies are weakly encrypted.",
32 SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var);
33 }
34
35 if (encryption_key) {
36 PHP_SHA256Update(&ctx, (const unsigned char *)encryption_key,
37 strlen(encryption_key));
38 }
39
40 PHP_SHA256Final((unsigned char *)key, &ctx);
41}
42
43// This function return 0 upon success , non-zero otherwise
44int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hash_key) {
45 unsigned char key[crypto_secretbox_KEYBYTES] = {0};
46 unsigned char *decrypted;
47 zend_string *debase64;
48 int ret = 0;
49
50 debase64 = php_base64_decode((unsigned char *)(Z_STRVAL_P(pDest)),
51 Z_STRLEN_P(pDest));
52
53 if (ZSTR_LEN(debase64) <
54 crypto_secretbox_NONCEBYTES + crypto_secretbox_ZEROBYTES) {
55 if (true == simulation) {
56 sp_log_msg(
57 "cookie_encryption", SP_LOG_SIMULATION,
58 "Buffer underflow tentative detected in cookie encryption handling "
59 "for %s. Using the cookie 'as it' instead of decrypting it.",
60 ZSTR_VAL(hash_key->key));
61 return ZEND_HASH_APPLY_KEEP;
62 } else {
63 sp_log_msg(
64 "cookie_encryption", SP_LOG_DROP,
65 "Buffer underflow tentative detected in cookie encryption handling.");
66 return ZEND_HASH_APPLY_REMOVE;
67 }
68 }
69
70 generate_key(key);
71
72 decrypted = ecalloc(ZSTR_LEN(debase64), 1);
73
74 ret = crypto_secretbox_open(
75 decrypted,
76 (unsigned char *)(ZSTR_VAL(debase64) + crypto_secretbox_NONCEBYTES),
77 ZSTR_LEN(debase64) - crypto_secretbox_NONCEBYTES,
78 (unsigned char *)ZSTR_VAL(debase64), key);
79
80 if (-1 == ret) {
81 if (true == simulation) {
82 sp_log_msg(
83 "cookie_encryption", SP_LOG_SIMULATION,
84 "Something went wrong with the decryption of %s. Using the cookie "
85 "'as it' instead of decrypting it",
86 ZSTR_VAL(hash_key->key));
87 return ZEND_HASH_APPLY_KEEP;
88 } else {
89 sp_log_msg("cookie_encryption", SP_LOG_DROP,
90 "Something went wrong with the decryption of %s.",
91 ZSTR_VAL(hash_key->key));
92 return ZEND_HASH_APPLY_REMOVE;
93 }
94 }
95
96 ZVAL_STRINGL(pDest, (char *)(decrypted + crypto_secretbox_ZEROBYTES),
97 ZSTR_LEN(debase64) - crypto_secretbox_NONCEBYTES - 1 -
98 crypto_secretbox_ZEROBYTES);
99
100 return ZEND_HASH_APPLY_KEEP;
101}
102
103zend_string *encrypt_zval(char *data, unsigned long long data_len) {
104 const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1;
105 const size_t emsg_and_nonce_len =
106 encrypted_msg_len + crypto_secretbox_NONCEBYTES;
107
108 unsigned char key[crypto_secretbox_KEYBYTES] = {0};
109 unsigned char nonce[crypto_secretbox_NONCEBYTES] = {0};
110 unsigned char *data_to_encrypt = ecalloc(encrypted_msg_len, 1);
111 unsigned char *encrypted_data = ecalloc(emsg_and_nonce_len, 1);
112
113 generate_key(key);
114
115 /* tweetnacl's API requires the message to be padded with
116 crypto_secretbox_ZEROBYTES zeroes. */
117 memcpy(data_to_encrypt + crypto_secretbox_ZEROBYTES, data, data_len);
118
119 assert(sizeof(zend_long) <= crypto_secretbox_NONCEBYTES);
120
121 if (0 == nonce_d) {
122 /* A zend_long should be enough to avoid collisions */
123 if (php_random_int_throw(0, ZEND_LONG_MAX, &nonce_d) == FAILURE) {
124 return NULL; // LCOV_EXCL_LINE
125 }
126 }
127 nonce_d++;
128 sscanf((char *)nonce, "%ld", &nonce_d);
129
130 memcpy(encrypted_data, nonce, crypto_secretbox_NONCEBYTES);
131 crypto_secretbox(encrypted_data + crypto_secretbox_NONCEBYTES,
132 data_to_encrypt, encrypted_msg_len, nonce, key);
133
134 zend_string *z = php_base64_encode(encrypted_data, emsg_and_nonce_len);
135 return z;
136} \ No newline at end of file