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(struct seal_key **skey)
21 n = calloc(1, sizeof(*n));
22 if (!n) return ENOMEM;
24 n->cipher = EVP_aes_128_cbc();
36 n->ekey = malloc(n->cipher->key_len);
42 n->hkey = malloc(n->cipher->key_len);
48 ret = RAND_bytes(n->ekey, n->cipher->key_len);
56 ret = RAND_bytes(n->hkey, n->cipher->key_len);
68 apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
69 struct databuf *plain, struct databuf *cipher)
71 apr_status_t err = EFAULT;
72 EVP_CIPHER_CTX ctx = { 0 };
73 HMAC_CTX hmac_ctx = { 0 };
79 EVP_CIPHER_CTX_init(&ctx);
81 /* confounder to avoid exposing random numbers directly to clients
83 ret = RAND_bytes(rbuf, 16);
84 if (ret == 0) goto done;
86 if (cipher->length == 0) {
87 /* add space for confounder and padding and MAC */
88 cipher->length = (plain->length / 16 + 2) * 16;
89 cipher->value = apr_palloc(p, cipher->length + skey->md->md_size);
96 ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
97 if (ret == 0) goto done;
100 outlen = cipher->length;
101 ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, 16);
102 if (ret == 0) goto done;
105 outlen = cipher->length - totlen;
106 ret = EVP_EncryptUpdate(&ctx, &cipher->value[totlen], &outlen,
107 plain->value, plain->length);
108 if (ret == 0) goto done;
111 outlen = cipher->length - totlen;
112 ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[totlen], &outlen);
113 if (ret == 0) goto done;
116 /* now MAC the buffer */
117 HMAC_CTX_init(&hmac_ctx);
119 ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
120 skey->cipher->key_len, skey->md, NULL);
121 if (ret == 0) goto done;
123 ret = HMAC_Update(&hmac_ctx, cipher->value, totlen);
124 if (ret == 0) goto done;
126 ret = HMAC_Final(&hmac_ctx, &cipher->value[totlen], &len);
127 if (ret == 0) goto done;
129 cipher->length = totlen + len;
133 EVP_CIPHER_CTX_cleanup(&ctx);
134 HMAC_CTX_cleanup(&hmac_ctx);
138 apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
139 struct databuf *cipher, struct databuf *plain)
141 apr_status_t err = EFAULT;
142 EVP_CIPHER_CTX ctx = { 0 };
143 HMAC_CTX hmac_ctx = { 0 };
144 unsigned char mac[skey->md->md_size];
147 volatile bool equal = true;
150 /* check MAC first */
151 HMAC_CTX_init(&hmac_ctx);
153 ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
154 skey->cipher->key_len, skey->md, NULL);
155 if (ret == 0) goto done;
157 cipher->length -= skey->md->md_size;
159 ret = HMAC_Update(&hmac_ctx, cipher->value, cipher->length);
160 if (ret == 0) goto done;
162 ret = HMAC_Final(&hmac_ctx, mac, &len);
163 if (ret == 0) goto done;
165 if (len != skey->md->md_size) goto done;
166 for (i = 0; i < skey->md->md_size; i++) {
167 if (cipher->value[cipher->length + i] != mac[i]) equal = false;
168 /* not breaking intentionally,
169 * or we would allow an oracle attack */
171 if (!equal) goto done;
173 EVP_CIPHER_CTX_init(&ctx);
175 if (plain->length == 0) {
176 plain->length = cipher->length;
177 plain->value = apr_palloc(p, plain->length);
184 ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
185 if (ret == 0) goto done;
188 outlen = plain->length;
189 ret = EVP_DecryptUpdate(&ctx, plain->value, &outlen,
190 cipher->value, cipher->length);
191 if (ret == 0) goto done;
194 outlen = plain->length - totlen;
195 ret = EVP_DecryptFinal_ex(&ctx, plain->value, &outlen);
196 if (ret == 0) goto done;
199 /* now remove the confounder */
201 memmove(plain->value, plain->value + 16, totlen);
203 plain->length = totlen;
207 EVP_CIPHER_CTX_cleanup(&ctx);
208 HMAC_CTX_cleanup(&hmac_ctx);