6
6
#include <stdbool.h>
7
7
#include "crypto.h"
8
8
9
+ #define TAGSIZE 16
10
+
9
11
struct seal_key {
10
12
const EVP_CIPHER * cipher ;
11
- const EVP_MD * md ;
12
13
unsigned char * ekey ;
13
- unsigned char * hkey ;
14
14
};
15
15
16
16
apr_status_t SEAL_KEY_CREATE (apr_pool_t * p , struct seal_key * * skey ,
17
- struct databuf * keys )
17
+ struct databuf * key )
18
18
{
19
19
struct seal_key * n ;
20
20
int keylen ;
@@ -23,58 +23,38 @@ apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
23
23
n = apr_pcalloc (p , sizeof (* n ));
24
24
if (!n ) return ENOMEM ;
25
25
26
- n -> cipher = EVP_aes_128_cbc ();
26
+ n -> cipher = EVP_aes_256_gcm ();
27
27
if (!n -> cipher ) {
28
28
ret = EFAULT ;
29
29
goto done ;
30
30
}
31
31
32
32
keylen = n -> cipher -> key_len ;
33
33
34
- n -> md = EVP_sha256 ();
35
- if (!n -> md ) {
36
- ret = EFAULT ;
37
- goto done ;
38
- }
39
-
40
34
n -> ekey = apr_palloc (p , keylen );
41
35
if (!n -> ekey ) {
42
36
ret = ENOMEM ;
43
37
goto done ;
44
38
}
45
39
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 ) {
54
42
ret = EINVAL ;
55
43
goto done ;
56
44
}
57
- memcpy (n -> ekey , keys -> value , keylen );
58
- memcpy (n -> hkey , keys -> value + keylen , keylen );
45
+ memcpy (n -> ekey , key -> value , keylen );
59
46
} else {
60
47
ret = apr_generate_random_bytes (n -> ekey , keylen );
61
48
if (ret != 0 ) {
62
49
ret = EFAULT ;
63
50
goto done ;
64
51
}
65
-
66
- ret = apr_generate_random_bytes (n -> hkey , keylen );
67
- if (ret != 0 ) {
68
- ret = EFAULT ;
69
- goto done ;
70
- }
71
52
}
72
53
73
54
ret = 0 ;
74
55
done :
75
56
if (ret ) {
76
57
free (n -> ekey );
77
- free (n -> hkey );
78
58
free (n );
79
59
} else {
80
60
* skey = n ;
@@ -85,144 +65,104 @@ apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
85
65
apr_status_t SEAL_BUFFER (apr_pool_t * p , struct seal_key * skey ,
86
66
struct databuf * plain , struct databuf * cipher )
87
67
{
88
- int blksz = skey -> cipher -> block_size ;
89
68
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 ;
95
72
int ret ;
96
73
97
74
EVP_CIPHER_CTX_init (& ctx );
98
75
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 );
108
83
if (!cipher -> value ) {
109
84
err = ENOMEM ;
110
85
goto done ;
111
86
}
112
87
}
113
88
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 ;
146
115
147
- cipher -> length = totlen + len ;
148
116
err = 0 ;
149
117
150
118
done :
151
119
EVP_CIPHER_CTX_cleanup (& ctx );
152
- HMAC_CTX_cleanup (& hmac_ctx );
153
120
return err ;
154
121
}
155
122
156
123
apr_status_t UNSEAL_BUFFER (apr_pool_t * p , struct seal_key * skey ,
157
124
struct databuf * cipher , struct databuf * plain )
158
125
{
159
126
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 ;
190
130
191
131
EVP_CIPHER_CTX_init (& ctx );
192
132
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 ;
195
135
plain -> value = apr_palloc (p , plain -> length );
196
136
if (!plain -> value ) {
197
137
err = ENOMEM ;
198
138
goto done ;
199
139
}
200
140
}
201
141
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 ;
204
146
205
- totlen = 0 ;
206
- outlen = plain -> length ;
147
+ outlen = 0 ;
207
148
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 ;
210
153
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 ;
215
157
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 ;
220
162
221
- plain -> length = totlen ;
222
163
err = 0 ;
223
164
224
165
done :
225
166
EVP_CIPHER_CTX_cleanup (& ctx );
226
- HMAC_CTX_cleanup (& hmac_ctx );
227
167
return err ;
228
168
}
0 commit comments