155714Skris/* crypto/evp/bio_enc.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8296465Sdelphij * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296465Sdelphij * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22296465Sdelphij * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296465Sdelphij * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52296465Sdelphij * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <errno.h> 6155714Skris#include "cryptlib.h" 6255714Skris#include <openssl/buffer.h> 6355714Skris#include <openssl/evp.h> 6455714Skris 6568651Skrisstatic int enc_write(BIO *h, const char *buf, int num); 6668651Skrisstatic int enc_read(BIO *h, char *buf, int size); 67296465Sdelphij/* 68296465Sdelphij * static int enc_puts(BIO *h, const char *str); 69296465Sdelphij */ 70296465Sdelphij/* 71296465Sdelphij * static int enc_gets(BIO *h, char *str, int size); 72296465Sdelphij */ 7368651Skrisstatic long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2); 7455714Skrisstatic int enc_new(BIO *h); 7555714Skrisstatic int enc_free(BIO *data); 7668651Skrisstatic long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps); 77296465Sdelphij#define ENC_BLOCK_SIZE (1024*4) 78296465Sdelphij#define BUF_OFFSET (EVP_MAX_BLOCK_LENGTH*2) 7955714Skris 80296465Sdelphijtypedef struct enc_struct { 81296465Sdelphij int buf_len; 82296465Sdelphij int buf_off; 83296465Sdelphij int cont; /* <= 0 when finished */ 84296465Sdelphij int finished; 85296465Sdelphij int ok; /* bad decrypt */ 86296465Sdelphij EVP_CIPHER_CTX cipher; 87296465Sdelphij /* 88296465Sdelphij * buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate can return 89296465Sdelphij * up to a block more data than is presented to it 90296465Sdelphij */ 91296465Sdelphij char buf[ENC_BLOCK_SIZE + BUF_OFFSET + 2]; 92296465Sdelphij} BIO_ENC_CTX; 9355714Skris 94296465Sdelphijstatic BIO_METHOD methods_enc = { 95296465Sdelphij BIO_TYPE_CIPHER, "cipher", 96296465Sdelphij enc_write, 97296465Sdelphij enc_read, 98296465Sdelphij NULL, /* enc_puts, */ 99296465Sdelphij NULL, /* enc_gets, */ 100296465Sdelphij enc_ctrl, 101296465Sdelphij enc_new, 102296465Sdelphij enc_free, 103296465Sdelphij enc_callback_ctrl, 104296465Sdelphij}; 10555714Skris 10655714SkrisBIO_METHOD *BIO_f_cipher(void) 107296465Sdelphij{ 108296465Sdelphij return (&methods_enc); 109296465Sdelphij} 11055714Skris 11155714Skrisstatic int enc_new(BIO *bi) 112296465Sdelphij{ 113296465Sdelphij BIO_ENC_CTX *ctx; 11455714Skris 115296465Sdelphij ctx = (BIO_ENC_CTX *)OPENSSL_malloc(sizeof(BIO_ENC_CTX)); 116296465Sdelphij if (ctx == NULL) 117296465Sdelphij return (0); 118296465Sdelphij EVP_CIPHER_CTX_init(&ctx->cipher); 11955714Skris 120296465Sdelphij ctx->buf_len = 0; 121296465Sdelphij ctx->buf_off = 0; 122296465Sdelphij ctx->cont = 1; 123296465Sdelphij ctx->finished = 0; 124296465Sdelphij ctx->ok = 1; 12555714Skris 126296465Sdelphij bi->init = 0; 127296465Sdelphij bi->ptr = (char *)ctx; 128296465Sdelphij bi->flags = 0; 129296465Sdelphij return (1); 130296465Sdelphij} 13155714Skris 13255714Skrisstatic int enc_free(BIO *a) 133296465Sdelphij{ 134296465Sdelphij BIO_ENC_CTX *b; 13555714Skris 136296465Sdelphij if (a == NULL) 137296465Sdelphij return (0); 138296465Sdelphij b = (BIO_ENC_CTX *)a->ptr; 139296465Sdelphij EVP_CIPHER_CTX_cleanup(&(b->cipher)); 140296465Sdelphij OPENSSL_cleanse(a->ptr, sizeof(BIO_ENC_CTX)); 141296465Sdelphij OPENSSL_free(a->ptr); 142296465Sdelphij a->ptr = NULL; 143296465Sdelphij a->init = 0; 144296465Sdelphij a->flags = 0; 145296465Sdelphij return (1); 146296465Sdelphij} 147296465Sdelphij 14855714Skrisstatic int enc_read(BIO *b, char *out, int outl) 149296465Sdelphij{ 150296465Sdelphij int ret = 0, i; 151296465Sdelphij BIO_ENC_CTX *ctx; 15255714Skris 153296465Sdelphij if (out == NULL) 154296465Sdelphij return (0); 155296465Sdelphij ctx = (BIO_ENC_CTX *)b->ptr; 15655714Skris 157296465Sdelphij if ((ctx == NULL) || (b->next_bio == NULL)) 158296465Sdelphij return (0); 15955714Skris 160296465Sdelphij /* First check if there are bytes decoded/encoded */ 161296465Sdelphij if (ctx->buf_len > 0) { 162296465Sdelphij i = ctx->buf_len - ctx->buf_off; 163296465Sdelphij if (i > outl) 164296465Sdelphij i = outl; 165296465Sdelphij memcpy(out, &(ctx->buf[ctx->buf_off]), i); 166296465Sdelphij ret = i; 167296465Sdelphij out += i; 168296465Sdelphij outl -= i; 169296465Sdelphij ctx->buf_off += i; 170296465Sdelphij if (ctx->buf_len == ctx->buf_off) { 171296465Sdelphij ctx->buf_len = 0; 172296465Sdelphij ctx->buf_off = 0; 173296465Sdelphij } 174296465Sdelphij } 17555714Skris 176296465Sdelphij /* 177296465Sdelphij * At this point, we have room of outl bytes and an empty buffer, so we 178296465Sdelphij * should read in some more. 179296465Sdelphij */ 18055714Skris 181296465Sdelphij while (outl > 0) { 182296465Sdelphij if (ctx->cont <= 0) 183296465Sdelphij break; 18455714Skris 185296465Sdelphij /* 186296465Sdelphij * read in at IV offset, read the EVP_Cipher documentation about why 187296465Sdelphij */ 188296465Sdelphij i = BIO_read(b->next_bio, &(ctx->buf[BUF_OFFSET]), ENC_BLOCK_SIZE); 18955714Skris 190296465Sdelphij if (i <= 0) { 191296465Sdelphij /* Should be continue next time we are called? */ 192296465Sdelphij if (!BIO_should_retry(b->next_bio)) { 193296465Sdelphij ctx->cont = i; 194296465Sdelphij i = EVP_CipherFinal_ex(&(ctx->cipher), 195296465Sdelphij (unsigned char *)ctx->buf, 196296465Sdelphij &(ctx->buf_len)); 197296465Sdelphij ctx->ok = i; 198296465Sdelphij ctx->buf_off = 0; 199296465Sdelphij } else { 200296465Sdelphij ret = (ret == 0) ? i : ret; 201296465Sdelphij break; 202296465Sdelphij } 203296465Sdelphij } else { 204296465Sdelphij EVP_CipherUpdate(&(ctx->cipher), 205296465Sdelphij (unsigned char *)ctx->buf, &ctx->buf_len, 206296465Sdelphij (unsigned char *)&(ctx->buf[BUF_OFFSET]), i); 207296465Sdelphij ctx->cont = 1; 208296465Sdelphij /* 209296465Sdelphij * Note: it is possible for EVP_CipherUpdate to decrypt zero 210296465Sdelphij * bytes because this is or looks like the final block: if this 211296465Sdelphij * happens we should retry and either read more data or decrypt 212296465Sdelphij * the final block 213296465Sdelphij */ 214296465Sdelphij if (ctx->buf_len == 0) 215296465Sdelphij continue; 216296465Sdelphij } 21755714Skris 218296465Sdelphij if (ctx->buf_len <= outl) 219296465Sdelphij i = ctx->buf_len; 220296465Sdelphij else 221296465Sdelphij i = outl; 222296465Sdelphij if (i <= 0) 223296465Sdelphij break; 224296465Sdelphij memcpy(out, ctx->buf, i); 225296465Sdelphij ret += i; 226296465Sdelphij ctx->buf_off = i; 227296465Sdelphij outl -= i; 228296465Sdelphij out += i; 229296465Sdelphij } 23055714Skris 231296465Sdelphij BIO_clear_retry_flags(b); 232296465Sdelphij BIO_copy_next_retry(b); 233296465Sdelphij return ((ret == 0) ? ctx->cont : ret); 234296465Sdelphij} 23555714Skris 23668651Skrisstatic int enc_write(BIO *b, const char *in, int inl) 237296465Sdelphij{ 238296465Sdelphij int ret = 0, n, i; 239296465Sdelphij BIO_ENC_CTX *ctx; 24055714Skris 241296465Sdelphij ctx = (BIO_ENC_CTX *)b->ptr; 242296465Sdelphij ret = inl; 24355714Skris 244296465Sdelphij BIO_clear_retry_flags(b); 245296465Sdelphij n = ctx->buf_len - ctx->buf_off; 246296465Sdelphij while (n > 0) { 247296465Sdelphij i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 248296465Sdelphij if (i <= 0) { 249296465Sdelphij BIO_copy_next_retry(b); 250296465Sdelphij return (i); 251296465Sdelphij } 252296465Sdelphij ctx->buf_off += i; 253296465Sdelphij n -= i; 254296465Sdelphij } 255296465Sdelphij /* at this point all pending data has been written */ 25655714Skris 257296465Sdelphij if ((in == NULL) || (inl <= 0)) 258296465Sdelphij return (0); 25955714Skris 260296465Sdelphij ctx->buf_off = 0; 261296465Sdelphij while (inl > 0) { 262296465Sdelphij n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl; 263296465Sdelphij EVP_CipherUpdate(&(ctx->cipher), 264296465Sdelphij (unsigned char *)ctx->buf, &ctx->buf_len, 265296465Sdelphij (unsigned char *)in, n); 266296465Sdelphij inl -= n; 267296465Sdelphij in += n; 26855714Skris 269296465Sdelphij ctx->buf_off = 0; 270296465Sdelphij n = ctx->buf_len; 271296465Sdelphij while (n > 0) { 272296465Sdelphij i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 273296465Sdelphij if (i <= 0) { 274296465Sdelphij BIO_copy_next_retry(b); 275296465Sdelphij return (ret == inl) ? i : ret - inl; 276296465Sdelphij } 277296465Sdelphij n -= i; 278296465Sdelphij ctx->buf_off += i; 279296465Sdelphij } 280296465Sdelphij ctx->buf_len = 0; 281296465Sdelphij ctx->buf_off = 0; 282296465Sdelphij } 283296465Sdelphij BIO_copy_next_retry(b); 284296465Sdelphij return (ret); 285296465Sdelphij} 28655714Skris 28768651Skrisstatic long enc_ctrl(BIO *b, int cmd, long num, void *ptr) 288296465Sdelphij{ 289296465Sdelphij BIO *dbio; 290296465Sdelphij BIO_ENC_CTX *ctx, *dctx; 291296465Sdelphij long ret = 1; 292296465Sdelphij int i; 293296465Sdelphij EVP_CIPHER_CTX **c_ctx; 29455714Skris 295296465Sdelphij ctx = (BIO_ENC_CTX *)b->ptr; 29655714Skris 297296465Sdelphij switch (cmd) { 298296465Sdelphij case BIO_CTRL_RESET: 299296465Sdelphij ctx->ok = 1; 300296465Sdelphij ctx->finished = 0; 301296465Sdelphij EVP_CipherInit_ex(&(ctx->cipher), NULL, NULL, NULL, NULL, 302296465Sdelphij ctx->cipher.encrypt); 303296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 304296465Sdelphij break; 305296465Sdelphij case BIO_CTRL_EOF: /* More to read */ 306296465Sdelphij if (ctx->cont <= 0) 307296465Sdelphij ret = 1; 308296465Sdelphij else 309296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 310296465Sdelphij break; 311296465Sdelphij case BIO_CTRL_WPENDING: 312296465Sdelphij ret = ctx->buf_len - ctx->buf_off; 313296465Sdelphij if (ret <= 0) 314296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 315296465Sdelphij break; 316296465Sdelphij case BIO_CTRL_PENDING: /* More to read in buffer */ 317296465Sdelphij ret = ctx->buf_len - ctx->buf_off; 318296465Sdelphij if (ret <= 0) 319296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 320296465Sdelphij break; 321296465Sdelphij case BIO_CTRL_FLUSH: 322296465Sdelphij /* do a final write */ 323296465Sdelphij again: 324296465Sdelphij while (ctx->buf_len != ctx->buf_off) { 325296465Sdelphij i = enc_write(b, NULL, 0); 326296465Sdelphij if (i < 0) 327296465Sdelphij return i; 328296465Sdelphij } 32955714Skris 330296465Sdelphij if (!ctx->finished) { 331296465Sdelphij ctx->finished = 1; 332296465Sdelphij ctx->buf_off = 0; 333296465Sdelphij ret = EVP_CipherFinal_ex(&(ctx->cipher), 334296465Sdelphij (unsigned char *)ctx->buf, 335296465Sdelphij &(ctx->buf_len)); 336296465Sdelphij ctx->ok = (int)ret; 337296465Sdelphij if (ret <= 0) 338296465Sdelphij break; 33955714Skris 340296465Sdelphij /* push out the bytes */ 341296465Sdelphij goto again; 342296465Sdelphij } 34355714Skris 344296465Sdelphij /* Finally flush the underlying BIO */ 345296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 346296465Sdelphij break; 347296465Sdelphij case BIO_C_GET_CIPHER_STATUS: 348296465Sdelphij ret = (long)ctx->ok; 349296465Sdelphij break; 350296465Sdelphij case BIO_C_DO_STATE_MACHINE: 351296465Sdelphij BIO_clear_retry_flags(b); 352296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 353296465Sdelphij BIO_copy_next_retry(b); 354296465Sdelphij break; 355296465Sdelphij case BIO_C_GET_CIPHER_CTX: 356296465Sdelphij c_ctx = (EVP_CIPHER_CTX **)ptr; 357296465Sdelphij (*c_ctx) = &(ctx->cipher); 358296465Sdelphij b->init = 1; 359296465Sdelphij break; 360296465Sdelphij case BIO_CTRL_DUP: 361296465Sdelphij dbio = (BIO *)ptr; 362296465Sdelphij dctx = (BIO_ENC_CTX *)dbio->ptr; 363296465Sdelphij memcpy(&(dctx->cipher), &(ctx->cipher), sizeof(ctx->cipher)); 364296465Sdelphij dbio->init = 1; 365296465Sdelphij break; 366296465Sdelphij default: 367296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 368296465Sdelphij break; 369296465Sdelphij } 370296465Sdelphij return (ret); 371296465Sdelphij} 372296465Sdelphij 37368651Skrisstatic long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 374296465Sdelphij{ 375296465Sdelphij long ret = 1; 37659191Skris 377296465Sdelphij if (b->next_bio == NULL) 378296465Sdelphij return (0); 379296465Sdelphij switch (cmd) { 380296465Sdelphij default: 381296465Sdelphij ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 382296465Sdelphij break; 383296465Sdelphij } 384296465Sdelphij return (ret); 385296465Sdelphij} 38659191Skris 387296465Sdelphij/*- 38855714Skrisvoid BIO_set_cipher_ctx(b,c) 38955714SkrisBIO *b; 39055714SkrisEVP_CIPHER_ctx *c; 391296465Sdelphij { 392296465Sdelphij if (b == NULL) return; 39355714Skris 394296465Sdelphij if ((b->callback != NULL) && 395296465Sdelphij (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0)) 396296465Sdelphij return; 39755714Skris 398296465Sdelphij b->init=1; 399296465Sdelphij ctx=(BIO_ENC_CTX *)b->ptr; 400296465Sdelphij memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX)); 401296465Sdelphij 402296465Sdelphij if (b->callback != NULL) 403296465Sdelphij b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L); 404296465Sdelphij } 40555714Skris*/ 40655714Skris 407160814Ssimonvoid BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k, 408296465Sdelphij const unsigned char *i, int e) 409296465Sdelphij{ 410296465Sdelphij BIO_ENC_CTX *ctx; 41155714Skris 412296465Sdelphij if (b == NULL) 413296465Sdelphij return; 41455714Skris 415296465Sdelphij if ((b->callback != NULL) && 416296465Sdelphij (b->callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 0L) <= 417296465Sdelphij 0)) 418296465Sdelphij return; 41955714Skris 420296465Sdelphij b->init = 1; 421296465Sdelphij ctx = (BIO_ENC_CTX *)b->ptr; 422296465Sdelphij EVP_CipherInit_ex(&(ctx->cipher), c, NULL, k, i, e); 42355714Skris 424296465Sdelphij if (b->callback != NULL) 425296465Sdelphij b->callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L); 426296465Sdelphij} 427