Skip to content

Commit e9c9279

Browse files
npmccallumsimo5
authored andcommitted
Use aes-256-gcm rather than aes-128-cbc
Also, remove all the manual HMAC code since it is no longer needed. The end result should be faster and stronger authenticated encryption. Closes #12 Reviewed-by: Simo Sorce <simo@redhat.com>
1 parent 1fc4999 commit e9c9279

File tree

2 files changed

+70
-130
lines changed

2 files changed

+70
-130
lines changed

src/crypto.c

Lines changed: 64 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
#include <stdbool.h>
77
#include "crypto.h"
88

9+
#define TAGSIZE 16
10+
911
struct seal_key {
1012
const EVP_CIPHER *cipher;
11-
const EVP_MD *md;
1213
unsigned char *ekey;
13-
unsigned char *hkey;
1414
};
1515

1616
apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
17-
struct databuf *keys)
17+
struct databuf *key)
1818
{
1919
struct seal_key *n;
2020
int keylen;
@@ -23,58 +23,38 @@ apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
2323
n = apr_pcalloc(p, sizeof(*n));
2424
if (!n) return ENOMEM;
2525

26-
n->cipher = EVP_aes_128_cbc();
26+
n->cipher = EVP_aes_256_gcm();
2727
if (!n->cipher) {
2828
ret = EFAULT;
2929
goto done;
3030
}
3131

3232
keylen = n->cipher->key_len;
3333

34-
n->md = EVP_sha256();
35-
if (!n->md) {
36-
ret = EFAULT;
37-
goto done;
38-
}
39-
4034
n->ekey = apr_palloc(p, keylen);
4135
if (!n->ekey) {
4236
ret = ENOMEM;
4337
goto done;
4438
}
4539

46-
n->hkey = apr_palloc(p, keylen);
47-
if (!n->hkey) {
48-
ret = ENOMEM;
49-
goto done;
50-
}
51-
52-
if (keys) {
53-
if (keys->length != (keylen * 2)) {
40+
if (key) {
41+
if (key->length < keylen) {
5442
ret = EINVAL;
5543
goto done;
5644
}
57-
memcpy(n->ekey, keys->value, keylen);
58-
memcpy(n->hkey, keys->value + keylen, keylen);
45+
memcpy(n->ekey, key->value, keylen);
5946
} else {
6047
ret = apr_generate_random_bytes(n->ekey, keylen);
6148
if (ret != 0) {
6249
ret = EFAULT;
6350
goto done;
6451
}
65-
66-
ret = apr_generate_random_bytes(n->hkey, keylen);
67-
if (ret != 0) {
68-
ret = EFAULT;
69-
goto done;
70-
}
7152
}
7253

7354
ret = 0;
7455
done:
7556
if (ret) {
7657
free(n->ekey);
77-
free(n->hkey);
7858
free(n);
7959
} else {
8060
*skey = n;
@@ -85,144 +65,104 @@ apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
8565
apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
8666
struct databuf *plain, struct databuf *cipher)
8767
{
88-
int blksz = skey->cipher->block_size;
8968
apr_status_t err = EFAULT;
90-
EVP_CIPHER_CTX ctx = { 0 };
91-
HMAC_CTX hmac_ctx = { 0 };
92-
uint8_t rbuf[blksz];
93-
unsigned int len;
94-
int outlen, totlen;
69+
EVP_CIPHER_CTX ctx = {};
70+
int minlen;
71+
int outlen;
9572
int ret;
9673

9774
EVP_CIPHER_CTX_init(&ctx);
9875

99-
/* confounder to avoid exposing random numbers directly to clients
100-
* as IVs */
101-
ret = apr_generate_random_bytes(rbuf, sizeof(rbuf));
102-
if (ret != 0) goto done;
103-
104-
if (cipher->length == 0) {
105-
/* add space for confounder and padding and MAC */
106-
cipher->length = (plain->length / blksz + 2) * blksz;
107-
cipher->value = apr_palloc(p, cipher->length + skey->md->md_size);
76+
/* Add space for padding, IV and tag. */
77+
minlen = plain->length / skey->cipher->block_size + 1;
78+
minlen *= skey->cipher->block_size;
79+
minlen += skey->cipher->iv_len + TAGSIZE;
80+
if (cipher->length < minlen) {
81+
cipher->length = minlen;
82+
cipher->value = apr_palloc(p, cipher->length);
10883
if (!cipher->value) {
10984
err = ENOMEM;
11085
goto done;
11186
}
11287
}
11388

114-
ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
115-
if (ret == 0) goto done;
116-
totlen = 0;
117-
118-
outlen = cipher->length;
119-
ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, sizeof(rbuf));
120-
if (ret == 0) goto done;
121-
totlen += outlen;
122-
123-
outlen = cipher->length - totlen;
124-
ret = EVP_EncryptUpdate(&ctx, &cipher->value[totlen], &outlen,
125-
plain->value, plain->length);
126-
if (ret == 0) goto done;
127-
totlen += outlen;
128-
129-
outlen = cipher->length - totlen;
130-
ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[totlen], &outlen);
131-
if (ret == 0) goto done;
132-
totlen += outlen;
133-
134-
/* now MAC the buffer */
135-
HMAC_CTX_init(&hmac_ctx);
136-
137-
ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
138-
skey->cipher->key_len, skey->md, NULL);
139-
if (ret == 0) goto done;
140-
141-
ret = HMAC_Update(&hmac_ctx, cipher->value, totlen);
142-
if (ret == 0) goto done;
143-
144-
ret = HMAC_Final(&hmac_ctx, &cipher->value[totlen], &len);
145-
if (ret == 0) goto done;
89+
/* Generate IV. */
90+
ret = apr_generate_random_bytes(cipher->value, skey->cipher->iv_len);
91+
if (ret != 0) goto done;
92+
cipher->length = skey->cipher->iv_len;
93+
94+
ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL,
95+
skey->ekey, cipher->value);
96+
if (ret != 1) goto done;
97+
98+
/* Encrypt the data. */
99+
outlen = 0;
100+
ret = EVP_EncryptUpdate(&ctx, &cipher->value[cipher->length],
101+
&outlen, plain->value, plain->length);
102+
if (ret != 1) goto done;
103+
cipher->length += outlen;
104+
105+
outlen = 0;
106+
ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[cipher->length], &outlen);
107+
if (ret != 1) goto done;
108+
cipher->length += outlen;
109+
110+
/* Get the tag */
111+
ret = EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, TAGSIZE,
112+
&cipher->value[cipher->length]);
113+
if (ret != 1) goto done;
114+
cipher->length += TAGSIZE;
146115

147-
cipher->length = totlen + len;
148116
err = 0;
149117

150118
done:
151119
EVP_CIPHER_CTX_cleanup(&ctx);
152-
HMAC_CTX_cleanup(&hmac_ctx);
153120
return err;
154121
}
155122

156123
apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
157124
struct databuf *cipher, struct databuf *plain)
158125
{
159126
apr_status_t err = EFAULT;
160-
EVP_CIPHER_CTX ctx = { 0 };
161-
HMAC_CTX hmac_ctx = { 0 };
162-
unsigned char mac[skey->md->md_size];
163-
unsigned int len;
164-
int outlen, totlen;
165-
volatile bool equal = true;
166-
int ret, i;
167-
168-
/* check MAC first */
169-
HMAC_CTX_init(&hmac_ctx);
170-
171-
ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
172-
skey->cipher->key_len, skey->md, NULL);
173-
if (ret == 0) goto done;
174-
175-
cipher->length -= skey->md->md_size;
176-
177-
ret = HMAC_Update(&hmac_ctx, cipher->value, cipher->length);
178-
if (ret == 0) goto done;
179-
180-
ret = HMAC_Final(&hmac_ctx, mac, &len);
181-
if (ret == 0) goto done;
182-
183-
if (len != skey->md->md_size) goto done;
184-
for (i = 0; i < skey->md->md_size; i++) {
185-
if (cipher->value[cipher->length + i] != mac[i]) equal = false;
186-
/* not breaking intentionally,
187-
* or we would allow an oracle attack */
188-
}
189-
if (!equal) goto done;
127+
EVP_CIPHER_CTX ctx = {};
128+
int outlen;
129+
int ret;
190130

191131
EVP_CIPHER_CTX_init(&ctx);
192132

193-
if (plain->length == 0) {
194-
plain->length = cipher->length;
133+
if (plain->length < cipher->length - skey->cipher->iv_len - TAGSIZE) {
134+
plain->length = cipher->length - skey->cipher->iv_len - TAGSIZE;
195135
plain->value = apr_palloc(p, plain->length);
196136
if (!plain->value) {
197137
err = ENOMEM;
198138
goto done;
199139
}
200140
}
201141

202-
ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
203-
if (ret == 0) goto done;
142+
ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL,
143+
skey->ekey, cipher->value);
144+
if (ret != 1) goto done;
145+
plain->length = 0;
204146

205-
totlen = 0;
206-
outlen = plain->length;
147+
outlen = 0;
207148
ret = EVP_DecryptUpdate(&ctx, plain->value, &outlen,
208-
cipher->value, cipher->length);
209-
if (ret == 0) goto done;
149+
&cipher->value[skey->cipher->iv_len],
150+
cipher->length - skey->cipher->iv_len - TAGSIZE);
151+
if (ret != 1) goto done;
152+
plain->length += outlen;
210153

211-
totlen += outlen;
212-
outlen = plain->length - totlen;
213-
ret = EVP_DecryptFinal_ex(&ctx, plain->value, &outlen);
214-
if (ret == 0) goto done;
154+
ret = EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, TAGSIZE,
155+
&cipher->value[cipher->length - TAGSIZE]);
156+
if (ret != 1) goto done;
215157

216-
totlen += outlen;
217-
/* now remove the confounder */
218-
totlen -= skey->cipher->block_size;
219-
memmove(plain->value, plain->value + skey->cipher->block_size, totlen);
158+
outlen = 0;
159+
ret = EVP_DecryptFinal_ex(&ctx, &plain->value[plain->length], &outlen);
160+
if (ret != 1) goto done;
161+
plain->length += outlen;
220162

221-
plain->length = totlen;
222163
err = 0;
223164

224165
done:
225166
EVP_CIPHER_CTX_cleanup(&ctx);
226-
HMAC_CTX_cleanup(&hmac_ctx);
227167
return err;
228168
}

src/mod_auth_gssapi.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on)
586586
static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
587587
{
588588
struct mag_config *cfg = (struct mag_config *)mconfig;
589-
struct databuf keys;
589+
struct databuf key;
590590
unsigned char *val;
591591
apr_status_t rc;
592592
const char *k;
@@ -607,16 +607,16 @@ static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
607607
return NULL;
608608
}
609609

610-
keys.length = (int)apr_base64_decode_binary(val, k);
611-
keys.value = (unsigned char *)val;
610+
key.length = (int)apr_base64_decode_binary(val, k);
611+
key.value = (unsigned char *)val;
612612

613-
if (keys.length != 32) {
613+
if (key.length < 32) {
614614
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
615-
"Invalid key lenght, expected 32 got %d", keys.length);
615+
"Invalid key length, expected >=32 got %d", key.length);
616616
return NULL;
617617
}
618618

619-
rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, &keys);
619+
rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, &key);
620620
if (rc != OK) {
621621
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
622622
"Failed to import sealing key!");

0 commit comments

Comments
 (0)