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 = apr_generate_random_bytes(n->ekey, keylen);
66 ret = apr_generate_random_bytes(n->hkey, keylen);
85 apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer,
86 struct databuf *result)
88 HMAC_CTX hmac_ctx = { 0 };
92 /* now MAC the buffer */
93 HMAC_CTX_init(&hmac_ctx);
95 ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
96 skey->cipher->key_len, skey->md, NULL);
97 if (ret == 0) goto done;
99 ret = HMAC_Update(&hmac_ctx, buffer->value, buffer->length);
100 if (ret == 0) goto done;
102 ret = HMAC_Final(&hmac_ctx, result->value, &len);
105 HMAC_CTX_cleanup(&hmac_ctx);
106 if (ret == 0) return EFAULT;
108 result->length = len;
112 apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
113 struct databuf *plain, struct databuf *cipher)
115 int blksz = skey->cipher->block_size;
116 apr_status_t err = EFAULT;
117 EVP_CIPHER_CTX ctx = { 0 };
119 struct databuf hmacbuf;
123 EVP_CIPHER_CTX_init(&ctx);
125 /* confounder to avoid exposing random numbers directly to clients
127 ret = apr_generate_random_bytes(rbuf, sizeof(rbuf));
128 if (ret != 0) goto done;
130 if (cipher->length == 0) {
131 /* add space for confounder and padding and MAC */
132 cipher->length = (plain->length / blksz + 2) * blksz;
133 cipher->value = apr_palloc(p, cipher->length + skey->md->md_size);
134 if (!cipher->value) {
140 ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
141 if (ret == 0) goto done;
144 outlen = cipher->length;
145 ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, sizeof(rbuf));
146 if (ret == 0) goto done;
149 outlen = cipher->length - totlen;
150 ret = EVP_EncryptUpdate(&ctx, &cipher->value[totlen], &outlen,
151 plain->value, plain->length);
152 if (ret == 0) goto done;
155 outlen = cipher->length - totlen;
156 ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[totlen], &outlen);
157 if (ret == 0) goto done;
160 /* now MAC the buffer */
161 cipher->length = totlen;
162 hmacbuf.value = &cipher->value[totlen];
163 ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
164 if (ret != 0) goto done;
166 cipher->length += hmacbuf.length;
170 EVP_CIPHER_CTX_cleanup(&ctx);
174 apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
175 struct databuf *cipher, struct databuf *plain)
177 apr_status_t err = EFAULT;
178 EVP_CIPHER_CTX ctx = { 0 };
179 unsigned char mac[skey->md->md_size];
180 struct databuf hmacbuf;
182 volatile bool equal = true;
185 /* check MAC first */
186 cipher->length -= skey->md->md_size;
188 ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
189 if (ret != 0) goto done;
191 if (hmacbuf.length != skey->md->md_size) goto done;
192 for (i = 0; i < skey->md->md_size; i++) {
193 if (cipher->value[cipher->length + i] != mac[i]) equal = false;
194 /* not breaking intentionally,
195 * or we would allow an oracle attack */
197 if (!equal) goto done;
199 EVP_CIPHER_CTX_init(&ctx);
201 if (plain->length == 0) {
202 plain->length = cipher->length;
203 plain->value = apr_palloc(p, plain->length);
210 ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
211 if (ret == 0) goto done;
214 outlen = plain->length;
215 ret = EVP_DecryptUpdate(&ctx, plain->value, &outlen,
216 cipher->value, cipher->length);
217 if (ret == 0) goto done;
220 outlen = plain->length - totlen;
221 ret = EVP_DecryptFinal_ex(&ctx, plain->value, &outlen);
222 if (ret == 0) goto done;
225 /* now remove the confounder */
226 totlen -= skey->cipher->block_size;
227 memmove(plain->value, plain->value + skey->cipher->block_size, totlen);
229 plain->length = totlen;
233 EVP_CIPHER_CTX_cleanup(&ctx);
237 int get_mac_size(struct seal_key *skey)
240 return skey->md->md_size;