summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/evp/e_chacha20poly1305.c
diff options
context:
space:
mode:
authorjsing <>2014-05-26 13:01:58 +0000
committerjsing <>2014-05-26 13:01:58 +0000
commit1e04f96479c885fa94175f42f348872cbdd3c9d4 (patch)
tree2d8c2f3b74e112db8f84b41231b2cde79d0be571 /src/lib/libcrypto/evp/e_chacha20poly1305.c
parent3ebf48c494177b3b775febf8302322375c80fe3b (diff)
downloadopenbsd-1e04f96479c885fa94175f42f348872cbdd3c9d4.tar.gz
openbsd-1e04f96479c885fa94175f42f348872cbdd3c9d4.tar.bz2
openbsd-1e04f96479c885fa94175f42f348872cbdd3c9d4.zip
Implement an improved version of the EVP AEAD API. The
EVP_AEAD_CTX_{open,seal} functions previously returned an ssize_t that was overloaded to indicate success/failure, along with the number of bytes written as output. This change adds an explicit *out_len argument which is used to return the number of output bytes and the return value is now an int that is purely used to identify success or failure. This change effectively rides the last libcrypto crank (although I do not expect there to be many users of the EVP AEAD API currently). Thanks to Adam Langley for providing the improved code that this diff is based on. ok miod@
Diffstat (limited to 'src/lib/libcrypto/evp/e_chacha20poly1305.c')
-rw-r--r--src/lib/libcrypto/evp/e_chacha20poly1305.c62
1 files changed, 33 insertions, 29 deletions
diff --git a/src/lib/libcrypto/evp/e_chacha20poly1305.c b/src/lib/libcrypto/evp/e_chacha20poly1305.c
index 7e32668b7f..7aeaf8775d 100644
--- a/src/lib/libcrypto/evp/e_chacha20poly1305.c
+++ b/src/lib/libcrypto/evp/e_chacha20poly1305.c
@@ -82,8 +82,9 @@ aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const unsigned char *key,
82 return 0; 82 return 0;
83 } 83 }
84 84
85 /* Internal error - EVP_AEAD_CTX_init should catch this. */
85 if (key_len != sizeof(c20_ctx->key)) 86 if (key_len != sizeof(c20_ctx->key))
86 return 0; /* internal error - EVP_AEAD_CTX_init should catch this. */ 87 return 0;
87 88
88 c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx)); 89 c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx));
89 if (c20_ctx == NULL) 90 if (c20_ctx == NULL)
@@ -100,6 +101,7 @@ static void
100aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) 101aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx)
101{ 102{
102 struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 103 struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
104
103 OPENSSL_cleanse(c20_ctx->key, sizeof(c20_ctx->key)); 105 OPENSSL_cleanse(c20_ctx->key, sizeof(c20_ctx->key));
104 free(c20_ctx); 106 free(c20_ctx);
105} 107}
@@ -121,11 +123,11 @@ poly1305_update_with_length(poly1305_state *poly1305,
121 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); 123 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
122} 124}
123 125
124static ssize_t 126static int
125aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 127aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
126 size_t max_out_len, const unsigned char *nonce, size_t nonce_len, 128 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
127 const unsigned char *in, size_t in_len, const unsigned char *ad, 129 size_t nonce_len, const unsigned char *in, size_t in_len,
128 size_t ad_len) 130 const unsigned char *ad, size_t ad_len)
129{ 131{
130 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 132 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
131 unsigned char poly1305_key[32]; 133 unsigned char poly1305_key[32];
@@ -139,20 +141,20 @@ aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
139 * 32-bits and this produces a warning because it's always false. 141 * 32-bits and this produces a warning because it's always false.
140 * Casting to uint64_t inside the conditional is not sufficient to stop 142 * Casting to uint64_t inside the conditional is not sufficient to stop
141 * the warning. */ 143 * the warning. */
142 if (in_len_64 >= (1ull << 32)*64 - 64) { 144 if (in_len_64 >= (1ULL << 32) * 64 - 64) {
143 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_TOO_LARGE); 145 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_TOO_LARGE);
144 return -1; 146 return 0;
145 } 147 }
146 148
147 if (max_out_len < in_len + c20_ctx->tag_len) { 149 if (max_out_len < in_len + c20_ctx->tag_len) {
148 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, 150 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL,
149 EVP_R_BUFFER_TOO_SMALL); 151 EVP_R_BUFFER_TOO_SMALL);
150 return -1; 152 return 0;
151 } 153 }
152 154
153 if (nonce_len != CHACHA20_NONCE_LEN) { 155 if (nonce_len != CHACHA20_NONCE_LEN) {
154 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE); 156 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE);
155 return -1; 157 return 0;
156 } 158 }
157 159
158 memset(poly1305_key, 0, sizeof(poly1305_key)); 160 memset(poly1305_key, 0, sizeof(poly1305_key));
@@ -168,29 +170,31 @@ aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
168 unsigned char tag[POLY1305_TAG_LEN]; 170 unsigned char tag[POLY1305_TAG_LEN];
169 CRYPTO_poly1305_finish(&poly1305, tag); 171 CRYPTO_poly1305_finish(&poly1305, tag);
170 memcpy(out + in_len, tag, c20_ctx->tag_len); 172 memcpy(out + in_len, tag, c20_ctx->tag_len);
171 return in_len + c20_ctx->tag_len; 173 *out_len = in_len + c20_ctx->tag_len;
174 return 1;
172 } 175 }
173 176
174 CRYPTO_poly1305_finish(&poly1305, out + in_len); 177 CRYPTO_poly1305_finish(&poly1305, out + in_len);
175 return in_len + POLY1305_TAG_LEN; 178 *out_len = in_len + POLY1305_TAG_LEN;
179 return 1;
176} 180}
177 181
178static ssize_t 182static int
179aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out, 183aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
180 size_t max_out_len, const unsigned char *nonce, size_t nonce_len, 184 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
181 const unsigned char *in, size_t in_len, const unsigned char *ad, 185 size_t nonce_len, const unsigned char *in, size_t in_len,
182 size_t ad_len) 186 const unsigned char *ad, size_t ad_len)
183{ 187{
184 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 188 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
185 unsigned char mac[POLY1305_TAG_LEN]; 189 unsigned char mac[POLY1305_TAG_LEN];
186 unsigned char poly1305_key[32]; 190 unsigned char poly1305_key[32];
187 size_t out_len;
188 poly1305_state poly1305; 191 poly1305_state poly1305;
189 const uint64_t in_len_64 = in_len; 192 const uint64_t in_len_64 = in_len;
193 size_t plaintext_len;
190 194
191 if (in_len < c20_ctx->tag_len) { 195 if (in_len < c20_ctx->tag_len) {
192 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT); 196 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
193 return -1; 197 return 0;
194 } 198 }
195 199
196 /* The underlying ChaCha implementation may not overflow the block 200 /* The underlying ChaCha implementation may not overflow the block
@@ -200,22 +204,22 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
200 * 32-bits and this produces a warning because it's always false. 204 * 32-bits and this produces a warning because it's always false.
201 * Casting to uint64_t inside the conditional is not sufficient to stop 205 * Casting to uint64_t inside the conditional is not sufficient to stop
202 * the warning. */ 206 * the warning. */
203 if (in_len_64 >= (1ull << 32)*64 - 64) { 207 if (in_len_64 >= (1ULL << 32) * 64 - 64) {
204 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_TOO_LARGE); 208 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_TOO_LARGE);
205 return -1; 209 return 0;
206 } 210 }
207 211
208 if (nonce_len != CHACHA20_NONCE_LEN) { 212 if (nonce_len != CHACHA20_NONCE_LEN) {
209 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE); 213 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE);
210 return -1; 214 return 0;
211 } 215 }
212 216
213 out_len = in_len - c20_ctx->tag_len; 217 plaintext_len = in_len - c20_ctx->tag_len;
214 218
215 if (max_out_len < out_len) { 219 if (max_out_len < plaintext_len) {
216 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, 220 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN,
217 EVP_R_BUFFER_TOO_SMALL); 221 EVP_R_BUFFER_TOO_SMALL);
218 return -1; 222 return 0;
219 } 223 }
220 224
221 memset(poly1305_key, 0, sizeof(poly1305_key)); 225 memset(poly1305_key, 0, sizeof(poly1305_key));
@@ -224,17 +228,17 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
224 228
225 CRYPTO_poly1305_init(&poly1305, poly1305_key); 229 CRYPTO_poly1305_init(&poly1305, poly1305_key);
226 poly1305_update_with_length(&poly1305, ad, ad_len); 230 poly1305_update_with_length(&poly1305, ad, ad_len);
227 poly1305_update_with_length(&poly1305, in, out_len); 231 poly1305_update_with_length(&poly1305, in, plaintext_len);
228 CRYPTO_poly1305_finish(&poly1305, mac); 232 CRYPTO_poly1305_finish(&poly1305, mac);
229 233
230 if (CRYPTO_memcmp(mac, in + out_len, c20_ctx->tag_len) != 0) { 234 if (CRYPTO_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
231 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT); 235 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
232 return -1; 236 return 0;
233 } 237 }
234 238
235 CRYPTO_chacha_20(out, in, out_len, c20_ctx->key, nonce, 1); 239 CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1);
236 240 *out_len = plaintext_len;
237 return out_len; 241 return 1;
238} 242}
239 243
240static const EVP_AEAD aead_chacha20_poly1305 = { 244static const EVP_AEAD aead_chacha20_poly1305 = {