bio_enc.c revision 306195
1/* crypto/evp/bio_enc.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include <errno.h> 61#include "cryptlib.h" 62#include <openssl/buffer.h> 63#include <openssl/evp.h> 64 65static int enc_write(BIO *h, const char *buf, int num); 66static int enc_read(BIO *h, char *buf, int size); 67/* 68 * static int enc_puts(BIO *h, const char *str); 69 */ 70/* 71 * static int enc_gets(BIO *h, char *str, int size); 72 */ 73static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2); 74static int enc_new(BIO *h); 75static int enc_free(BIO *data); 76static long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps); 77#define ENC_BLOCK_SIZE (1024*4) 78#define BUF_OFFSET (EVP_MAX_BLOCK_LENGTH*2) 79 80typedef struct enc_struct { 81 int buf_len; 82 int buf_off; 83 int cont; /* <= 0 when finished */ 84 int finished; 85 int ok; /* bad decrypt */ 86 EVP_CIPHER_CTX cipher; 87 /* 88 * buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate can return 89 * up to a block more data than is presented to it 90 */ 91 char buf[ENC_BLOCK_SIZE + BUF_OFFSET + 2]; 92} BIO_ENC_CTX; 93 94static BIO_METHOD methods_enc = { 95 BIO_TYPE_CIPHER, "cipher", 96 enc_write, 97 enc_read, 98 NULL, /* enc_puts, */ 99 NULL, /* enc_gets, */ 100 enc_ctrl, 101 enc_new, 102 enc_free, 103 enc_callback_ctrl, 104}; 105 106BIO_METHOD *BIO_f_cipher(void) 107{ 108 return (&methods_enc); 109} 110 111static int enc_new(BIO *bi) 112{ 113 BIO_ENC_CTX *ctx; 114 115 ctx = (BIO_ENC_CTX *)OPENSSL_malloc(sizeof(BIO_ENC_CTX)); 116 if (ctx == NULL) 117 return (0); 118 EVP_CIPHER_CTX_init(&ctx->cipher); 119 120 ctx->buf_len = 0; 121 ctx->buf_off = 0; 122 ctx->cont = 1; 123 ctx->finished = 0; 124 ctx->ok = 1; 125 126 bi->init = 0; 127 bi->ptr = (char *)ctx; 128 bi->flags = 0; 129 return (1); 130} 131 132static int enc_free(BIO *a) 133{ 134 BIO_ENC_CTX *b; 135 136 if (a == NULL) 137 return (0); 138 b = (BIO_ENC_CTX *)a->ptr; 139 EVP_CIPHER_CTX_cleanup(&(b->cipher)); 140 OPENSSL_cleanse(a->ptr, sizeof(BIO_ENC_CTX)); 141 OPENSSL_free(a->ptr); 142 a->ptr = NULL; 143 a->init = 0; 144 a->flags = 0; 145 return (1); 146} 147 148static int enc_read(BIO *b, char *out, int outl) 149{ 150 int ret = 0, i; 151 BIO_ENC_CTX *ctx; 152 153 if (out == NULL) 154 return (0); 155 ctx = (BIO_ENC_CTX *)b->ptr; 156 157 if ((ctx == NULL) || (b->next_bio == NULL)) 158 return (0); 159 160 /* First check if there are bytes decoded/encoded */ 161 if (ctx->buf_len > 0) { 162 i = ctx->buf_len - ctx->buf_off; 163 if (i > outl) 164 i = outl; 165 memcpy(out, &(ctx->buf[ctx->buf_off]), i); 166 ret = i; 167 out += i; 168 outl -= i; 169 ctx->buf_off += i; 170 if (ctx->buf_len == ctx->buf_off) { 171 ctx->buf_len = 0; 172 ctx->buf_off = 0; 173 } 174 } 175 176 /* 177 * At this point, we have room of outl bytes and an empty buffer, so we 178 * should read in some more. 179 */ 180 181 while (outl > 0) { 182 if (ctx->cont <= 0) 183 break; 184 185 /* 186 * read in at IV offset, read the EVP_Cipher documentation about why 187 */ 188 i = BIO_read(b->next_bio, &(ctx->buf[BUF_OFFSET]), ENC_BLOCK_SIZE); 189 190 if (i <= 0) { 191 /* Should be continue next time we are called? */ 192 if (!BIO_should_retry(b->next_bio)) { 193 ctx->cont = i; 194 i = EVP_CipherFinal_ex(&(ctx->cipher), 195 (unsigned char *)ctx->buf, 196 &(ctx->buf_len)); 197 ctx->ok = i; 198 ctx->buf_off = 0; 199 } else { 200 ret = (ret == 0) ? i : ret; 201 break; 202 } 203 } else { 204 if (!EVP_CipherUpdate(&ctx->cipher, 205 (unsigned char *)ctx->buf, &ctx->buf_len, 206 (unsigned char *)&(ctx->buf[BUF_OFFSET]), 207 i)) { 208 BIO_clear_retry_flags(b); 209 ctx->ok = 0; 210 return 0; 211 } 212 ctx->cont = 1; 213 /* 214 * Note: it is possible for EVP_CipherUpdate to decrypt zero 215 * bytes because this is or looks like the final block: if this 216 * happens we should retry and either read more data or decrypt 217 * the final block 218 */ 219 if (ctx->buf_len == 0) 220 continue; 221 } 222 223 if (ctx->buf_len <= outl) 224 i = ctx->buf_len; 225 else 226 i = outl; 227 if (i <= 0) 228 break; 229 memcpy(out, ctx->buf, i); 230 ret += i; 231 ctx->buf_off = i; 232 outl -= i; 233 out += i; 234 } 235 236 BIO_clear_retry_flags(b); 237 BIO_copy_next_retry(b); 238 return ((ret == 0) ? ctx->cont : ret); 239} 240 241static int enc_write(BIO *b, const char *in, int inl) 242{ 243 int ret = 0, n, i; 244 BIO_ENC_CTX *ctx; 245 246 ctx = (BIO_ENC_CTX *)b->ptr; 247 ret = inl; 248 249 BIO_clear_retry_flags(b); 250 n = ctx->buf_len - ctx->buf_off; 251 while (n > 0) { 252 i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 253 if (i <= 0) { 254 BIO_copy_next_retry(b); 255 return (i); 256 } 257 ctx->buf_off += i; 258 n -= i; 259 } 260 /* at this point all pending data has been written */ 261 262 if ((in == NULL) || (inl <= 0)) 263 return (0); 264 265 ctx->buf_off = 0; 266 while (inl > 0) { 267 n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl; 268 if (!EVP_CipherUpdate(&ctx->cipher, 269 (unsigned char *)ctx->buf, &ctx->buf_len, 270 (unsigned char *)in, n)) { 271 BIO_clear_retry_flags(b); 272 ctx->ok = 0; 273 return 0; 274 } 275 inl -= n; 276 in += n; 277 278 ctx->buf_off = 0; 279 n = ctx->buf_len; 280 while (n > 0) { 281 i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 282 if (i <= 0) { 283 BIO_copy_next_retry(b); 284 return (ret == inl) ? i : ret - inl; 285 } 286 n -= i; 287 ctx->buf_off += i; 288 } 289 ctx->buf_len = 0; 290 ctx->buf_off = 0; 291 } 292 BIO_copy_next_retry(b); 293 return (ret); 294} 295 296static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) 297{ 298 BIO *dbio; 299 BIO_ENC_CTX *ctx, *dctx; 300 long ret = 1; 301 int i; 302 EVP_CIPHER_CTX **c_ctx; 303 304 ctx = (BIO_ENC_CTX *)b->ptr; 305 306 switch (cmd) { 307 case BIO_CTRL_RESET: 308 ctx->ok = 1; 309 ctx->finished = 0; 310 EVP_CipherInit_ex(&(ctx->cipher), NULL, NULL, NULL, NULL, 311 ctx->cipher.encrypt); 312 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 313 break; 314 case BIO_CTRL_EOF: /* More to read */ 315 if (ctx->cont <= 0) 316 ret = 1; 317 else 318 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 319 break; 320 case BIO_CTRL_WPENDING: 321 ret = ctx->buf_len - ctx->buf_off; 322 if (ret <= 0) 323 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 324 break; 325 case BIO_CTRL_PENDING: /* More to read in buffer */ 326 ret = ctx->buf_len - ctx->buf_off; 327 if (ret <= 0) 328 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 329 break; 330 case BIO_CTRL_FLUSH: 331 /* do a final write */ 332 again: 333 while (ctx->buf_len != ctx->buf_off) { 334 i = enc_write(b, NULL, 0); 335 if (i < 0) 336 return i; 337 } 338 339 if (!ctx->finished) { 340 ctx->finished = 1; 341 ctx->buf_off = 0; 342 ret = EVP_CipherFinal_ex(&(ctx->cipher), 343 (unsigned char *)ctx->buf, 344 &(ctx->buf_len)); 345 ctx->ok = (int)ret; 346 if (ret <= 0) 347 break; 348 349 /* push out the bytes */ 350 goto again; 351 } 352 353 /* Finally flush the underlying BIO */ 354 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 355 break; 356 case BIO_C_GET_CIPHER_STATUS: 357 ret = (long)ctx->ok; 358 break; 359 case BIO_C_DO_STATE_MACHINE: 360 BIO_clear_retry_flags(b); 361 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 362 BIO_copy_next_retry(b); 363 break; 364 case BIO_C_GET_CIPHER_CTX: 365 c_ctx = (EVP_CIPHER_CTX **)ptr; 366 (*c_ctx) = &(ctx->cipher); 367 b->init = 1; 368 break; 369 case BIO_CTRL_DUP: 370 dbio = (BIO *)ptr; 371 dctx = (BIO_ENC_CTX *)dbio->ptr; 372 EVP_CIPHER_CTX_init(&dctx->cipher); 373 ret = EVP_CIPHER_CTX_copy(&dctx->cipher, &ctx->cipher); 374 if (ret) 375 dbio->init = 1; 376 break; 377 default: 378 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 379 break; 380 } 381 return (ret); 382} 383 384static long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 385{ 386 long ret = 1; 387 388 if (b->next_bio == NULL) 389 return (0); 390 switch (cmd) { 391 default: 392 ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 393 break; 394 } 395 return (ret); 396} 397 398/*- 399void BIO_set_cipher_ctx(b,c) 400BIO *b; 401EVP_CIPHER_ctx *c; 402 { 403 if (b == NULL) return; 404 405 if ((b->callback != NULL) && 406 (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0)) 407 return; 408 409 b->init=1; 410 ctx=(BIO_ENC_CTX *)b->ptr; 411 memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX)); 412 413 if (b->callback != NULL) 414 b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L); 415 } 416*/ 417 418void BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k, 419 const unsigned char *i, int e) 420{ 421 BIO_ENC_CTX *ctx; 422 423 if (b == NULL) 424 return; 425 426 if ((b->callback != NULL) && 427 (b->callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 0L) <= 428 0)) 429 return; 430 431 b->init = 1; 432 ctx = (BIO_ENC_CTX *)b->ptr; 433 EVP_CipherInit_ex(&(ctx->cipher), c, NULL, k, i, e); 434 435 if (b->callback != NULL) 436 b->callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L); 437} 438