1 /* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */
3 #include <openssl/evp.h>
4 #include <openssl/hmac.h>
5 #include <openssl/rand.h>
10 const EVP_CIPHER *cipher;
16 apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
23 n = apr_pcalloc(p, sizeof(*n));
24 if (!n) return ENOMEM;
26 n->cipher = EVP_aes_128_cbc();
32 keylen = n->cipher->key_len;
40 n->ekey = apr_palloc(p, keylen);
46 n->hkey = apr_palloc(p, keylen);
53 if (keys->length != (keylen * 2)) {
57 memcpy(n->ekey, keys->value, keylen);
58 memcpy(n->hkey, keys->value + keylen, keylen);
60 ret = RAND_bytes(n->ekey, keylen);
66 ret = RAND_bytes(n->hkey, keylen);
85 apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
86 struct databuf *plain, struct databuf *cipher)
88 apr_status_t err = EFAULT;
89 EVP_CIPHER_CTX ctx = { 0 };
90 HMAC_CTX hmac_ctx = { 0 };
96 EVP_CIPHER_CTX_init(&ctx);
98 /* confounder to avoid exposing random numbers directly to clients
100 ret = RAND_bytes(rbuf, 16);
101 if (ret == 0) goto done;
103 if (cipher->length == 0) {
104 /* add space for confounder and padding and MAC */
105 cipher->length = (plain->length / 16 + 2) * 16;
106 cipher->value = apr_palloc(p, cipher->length + skey->md->md_size);
107 if (!cipher->value) {
113 ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
114 if (ret == 0) goto done;
117 outlen = cipher->length;
118 ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, 16);
119 if (ret == 0) goto done;
122 outlen = cipher->length - totlen;
123 ret = EVP_EncryptUpdate(&ctx, &cipher->value[totlen], &outlen,
124 plain->value, plain->length);
125 if (ret == 0) goto done;
128 outlen = cipher->length - totlen;
129 ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[totlen], &outlen);
130 if (ret == 0) goto done;
133 /* now MAC the buffer */
134 HMAC_CTX_init(&hmac_ctx);
136 ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
137 skey->cipher->key_len, skey->md, NULL);
138 if (ret == 0) goto done;
140 ret = HMAC_Update(&hmac_ctx, cipher->value, totlen);
141 if (ret == 0) goto done;
143 ret = HMAC_Final(&hmac_ctx, &cipher->value[totlen], &len);
144 if (ret == 0) goto done;
146 cipher->length = totlen + len;
150 EVP_CIPHER_CTX_cleanup(&ctx);
151 HMAC_CTX_cleanup(&hmac_ctx);
155 apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
156 struct databuf *cipher, struct databuf *plain)
158 apr_status_t err = EFAULT;
159 EVP_CIPHER_CTX ctx = { 0 };
160 HMAC_CTX hmac_ctx = { 0 };
161 unsigned char mac[skey->md->md_size];
164 volatile bool equal = true;
167 /* check MAC first */
168 HMAC_CTX_init(&hmac_ctx);
170 ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
171 skey->cipher->key_len, skey->md, NULL);
172 if (ret == 0) goto done;
174 cipher->length -= skey->md->md_size;
176 ret = HMAC_Update(&hmac_ctx, cipher->value, cipher->length);
177 if (ret == 0) goto done;
179 ret = HMAC_Final(&hmac_ctx, mac, &len);
180 if (ret == 0) goto done;
182 if (len != skey->md->md_size) goto done;
183 for (i = 0; i < skey->md->md_size; i++) {
184 if (cipher->value[cipher->length + i] != mac[i]) equal = false;
185 /* not breaking intentionally,
186 * or we would allow an oracle attack */
188 if (!equal) goto done;
190 EVP_CIPHER_CTX_init(&ctx);
192 if (plain->length == 0) {
193 plain->length = cipher->length;
194 plain->value = apr_palloc(p, plain->length);
201 ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
202 if (ret == 0) goto done;
205 outlen = plain->length;
206 ret = EVP_DecryptUpdate(&ctx, plain->value, &outlen,
207 cipher->value, cipher->length);
208 if (ret == 0) goto done;
211 outlen = plain->length - totlen;
212 ret = EVP_DecryptFinal_ex(&ctx, plain->value, &outlen);
213 if (ret == 0) goto done;
216 /* now remove the confounder */
218 memmove(plain->value, plain->value + 16, totlen);
220 plain->length = totlen;
224 EVP_CIPHER_CTX_cleanup(&ctx);
225 HMAC_CTX_cleanup(&hmac_ctx);