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.
855714Skris *
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).
1555714Skris *
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.
2255714Skris *
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 :-).
3755714Skris * 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)"
4055714Skris *
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.
5255714Skris *
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);
6768651Skris/*static int enc_puts(BIO *h, const char *str); */
6868651Skris/*static int enc_gets(BIO *h, char *str, int size); */
6968651Skrisstatic long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
7055714Skrisstatic int enc_new(BIO *h);
7155714Skrisstatic int enc_free(BIO *data);
7268651Skrisstatic long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps);
7355714Skris#define ENC_BLOCK_SIZE	(1024*4)
74160814Ssimon#define BUF_OFFSET	(EVP_MAX_BLOCK_LENGTH*2)
7555714Skris
7655714Skristypedef struct enc_struct
7755714Skris	{
7855714Skris	int buf_len;
7955714Skris	int buf_off;
8055714Skris	int cont;		/* <= 0 when finished */
8155714Skris	int finished;
8255714Skris	int ok;			/* bad decrypt */
8355714Skris	EVP_CIPHER_CTX cipher;
84109998Smarkm	/* buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate
85109998Smarkm	 * can return up to a block more data than is presented to it
86109998Smarkm	 */
87109998Smarkm	char buf[ENC_BLOCK_SIZE+BUF_OFFSET+2];
8855714Skris	} BIO_ENC_CTX;
8955714Skris
9055714Skrisstatic BIO_METHOD methods_enc=
9155714Skris	{
9255714Skris	BIO_TYPE_CIPHER,"cipher",
9355714Skris	enc_write,
9455714Skris	enc_read,
9555714Skris	NULL, /* enc_puts, */
9655714Skris	NULL, /* enc_gets, */
9755714Skris	enc_ctrl,
9855714Skris	enc_new,
9955714Skris	enc_free,
10059191Skris	enc_callback_ctrl,
10155714Skris	};
10255714Skris
10355714SkrisBIO_METHOD *BIO_f_cipher(void)
10455714Skris	{
10555714Skris	return(&methods_enc);
10655714Skris	}
10755714Skris
10855714Skrisstatic int enc_new(BIO *bi)
10955714Skris	{
11055714Skris	BIO_ENC_CTX *ctx;
11155714Skris
11268651Skris	ctx=(BIO_ENC_CTX *)OPENSSL_malloc(sizeof(BIO_ENC_CTX));
113100936Snectar	if (ctx == NULL) return(0);
11455714Skris	EVP_CIPHER_CTX_init(&ctx->cipher);
11555714Skris
11655714Skris	ctx->buf_len=0;
11755714Skris	ctx->buf_off=0;
11855714Skris	ctx->cont=1;
11955714Skris	ctx->finished=0;
12055714Skris	ctx->ok=1;
12155714Skris
12255714Skris	bi->init=0;
12355714Skris	bi->ptr=(char *)ctx;
12455714Skris	bi->flags=0;
12555714Skris	return(1);
12655714Skris	}
12755714Skris
12855714Skrisstatic int enc_free(BIO *a)
12955714Skris	{
13055714Skris	BIO_ENC_CTX *b;
13155714Skris
13255714Skris	if (a == NULL) return(0);
13355714Skris	b=(BIO_ENC_CTX *)a->ptr;
13455714Skris	EVP_CIPHER_CTX_cleanup(&(b->cipher));
135109998Smarkm	OPENSSL_cleanse(a->ptr,sizeof(BIO_ENC_CTX));
13668651Skris	OPENSSL_free(a->ptr);
13755714Skris	a->ptr=NULL;
13855714Skris	a->init=0;
13955714Skris	a->flags=0;
14055714Skris	return(1);
14155714Skris	}
14255714Skris
14355714Skrisstatic int enc_read(BIO *b, char *out, int outl)
14455714Skris	{
14555714Skris	int ret=0,i;
14655714Skris	BIO_ENC_CTX *ctx;
14755714Skris
14855714Skris	if (out == NULL) return(0);
14955714Skris	ctx=(BIO_ENC_CTX *)b->ptr;
15055714Skris
15155714Skris	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
15255714Skris
15355714Skris	/* First check if there are bytes decoded/encoded */
15455714Skris	if (ctx->buf_len > 0)
15555714Skris		{
15655714Skris		i=ctx->buf_len-ctx->buf_off;
15755714Skris		if (i > outl) i=outl;
15855714Skris		memcpy(out,&(ctx->buf[ctx->buf_off]),i);
15955714Skris		ret=i;
16055714Skris		out+=i;
16155714Skris		outl-=i;
16255714Skris		ctx->buf_off+=i;
16355714Skris		if (ctx->buf_len == ctx->buf_off)
16455714Skris			{
16555714Skris			ctx->buf_len=0;
16655714Skris			ctx->buf_off=0;
16755714Skris			}
16855714Skris		}
16955714Skris
17055714Skris	/* At this point, we have room of outl bytes and an empty
17155714Skris	 * buffer, so we should read in some more. */
17255714Skris
17355714Skris	while (outl > 0)
17455714Skris		{
17555714Skris		if (ctx->cont <= 0) break;
17655714Skris
177109998Smarkm		/* read in at IV offset, read the EVP_Cipher
17855714Skris		 * documentation about why */
179109998Smarkm		i=BIO_read(b->next_bio,&(ctx->buf[BUF_OFFSET]),ENC_BLOCK_SIZE);
18055714Skris
18155714Skris		if (i <= 0)
18255714Skris			{
18355714Skris			/* Should be continue next time we are called? */
18455714Skris			if (!BIO_should_retry(b->next_bio))
18555714Skris				{
18655714Skris				ctx->cont=i;
187109998Smarkm				i=EVP_CipherFinal_ex(&(ctx->cipher),
18855714Skris					(unsigned char *)ctx->buf,
18955714Skris					&(ctx->buf_len));
19055714Skris				ctx->ok=i;
19155714Skris				ctx->buf_off=0;
19255714Skris				}
19359191Skris			else
19459191Skris				{
19555714Skris				ret=(ret == 0)?i:ret;
19659191Skris				break;
19759191Skris				}
19855714Skris			}
19955714Skris		else
20055714Skris			{
20155714Skris			EVP_CipherUpdate(&(ctx->cipher),
20255714Skris				(unsigned char *)ctx->buf,&ctx->buf_len,
203109998Smarkm				(unsigned char *)&(ctx->buf[BUF_OFFSET]),i);
20455714Skris			ctx->cont=1;
20559191Skris			/* Note: it is possible for EVP_CipherUpdate to
20659191Skris			 * decrypt zero bytes because this is or looks like
20759191Skris			 * the final block: if this happens we should retry
20859191Skris			 * and either read more data or decrypt the final
20959191Skris			 * block
21059191Skris			 */
21159191Skris			if(ctx->buf_len == 0) continue;
21255714Skris			}
21355714Skris
21455714Skris		if (ctx->buf_len <= outl)
21555714Skris			i=ctx->buf_len;
21655714Skris		else
21755714Skris			i=outl;
21855714Skris		if (i <= 0) break;
21955714Skris		memcpy(out,ctx->buf,i);
22055714Skris		ret+=i;
22155714Skris		ctx->buf_off=i;
22255714Skris		outl-=i;
22355714Skris		out+=i;
22455714Skris		}
22555714Skris
22655714Skris	BIO_clear_retry_flags(b);
22755714Skris	BIO_copy_next_retry(b);
22855714Skris	return((ret == 0)?ctx->cont:ret);
22955714Skris	}
23055714Skris
23168651Skrisstatic int enc_write(BIO *b, const char *in, int inl)
23255714Skris	{
23355714Skris	int ret=0,n,i;
23455714Skris	BIO_ENC_CTX *ctx;
23555714Skris
23655714Skris	ctx=(BIO_ENC_CTX *)b->ptr;
23755714Skris	ret=inl;
23855714Skris
23955714Skris	BIO_clear_retry_flags(b);
24055714Skris	n=ctx->buf_len-ctx->buf_off;
24155714Skris	while (n > 0)
24255714Skris		{
24355714Skris		i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
24455714Skris		if (i <= 0)
24555714Skris			{
24655714Skris			BIO_copy_next_retry(b);
24755714Skris			return(i);
24855714Skris			}
24955714Skris		ctx->buf_off+=i;
25055714Skris		n-=i;
25155714Skris		}
25255714Skris	/* at this point all pending data has been written */
25355714Skris
25455714Skris	if ((in == NULL) || (inl <= 0)) return(0);
25555714Skris
25655714Skris	ctx->buf_off=0;
25755714Skris	while (inl > 0)
25855714Skris		{
25955714Skris		n=(inl > ENC_BLOCK_SIZE)?ENC_BLOCK_SIZE:inl;
26055714Skris		EVP_CipherUpdate(&(ctx->cipher),
26155714Skris			(unsigned char *)ctx->buf,&ctx->buf_len,
26255714Skris			(unsigned char *)in,n);
26355714Skris		inl-=n;
26455714Skris		in+=n;
26555714Skris
26655714Skris		ctx->buf_off=0;
26755714Skris		n=ctx->buf_len;
26855714Skris		while (n > 0)
26955714Skris			{
27055714Skris			i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
27155714Skris			if (i <= 0)
27255714Skris				{
27355714Skris				BIO_copy_next_retry(b);
274120631Snectar				return (ret == inl) ? i : ret - inl;
27555714Skris				}
27655714Skris			n-=i;
27755714Skris			ctx->buf_off+=i;
27855714Skris			}
27955714Skris		ctx->buf_len=0;
28055714Skris		ctx->buf_off=0;
28155714Skris		}
28255714Skris	BIO_copy_next_retry(b);
28355714Skris	return(ret);
28455714Skris	}
28555714Skris
28668651Skrisstatic long enc_ctrl(BIO *b, int cmd, long num, void *ptr)
28755714Skris	{
28855714Skris	BIO *dbio;
28955714Skris	BIO_ENC_CTX *ctx,*dctx;
29055714Skris	long ret=1;
29155714Skris	int i;
29255714Skris	EVP_CIPHER_CTX **c_ctx;
29355714Skris
29455714Skris	ctx=(BIO_ENC_CTX *)b->ptr;
29555714Skris
29655714Skris	switch (cmd)
29755714Skris		{
29855714Skris	case BIO_CTRL_RESET:
29955714Skris		ctx->ok=1;
30055714Skris		ctx->finished=0;
301109998Smarkm		EVP_CipherInit_ex(&(ctx->cipher),NULL,NULL,NULL,NULL,
30255714Skris			ctx->cipher.encrypt);
30355714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
30455714Skris		break;
30555714Skris	case BIO_CTRL_EOF:	/* More to read */
30655714Skris		if (ctx->cont <= 0)
30755714Skris			ret=1;
30855714Skris		else
30955714Skris			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
31055714Skris		break;
31155714Skris	case BIO_CTRL_WPENDING:
31255714Skris		ret=ctx->buf_len-ctx->buf_off;
31355714Skris		if (ret <= 0)
31455714Skris			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
31555714Skris		break;
31655714Skris	case BIO_CTRL_PENDING: /* More to read in buffer */
31755714Skris		ret=ctx->buf_len-ctx->buf_off;
31855714Skris		if (ret <= 0)
31955714Skris			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
32055714Skris		break;
32155714Skris	case BIO_CTRL_FLUSH:
32255714Skris		/* do a final write */
32355714Skrisagain:
32455714Skris		while (ctx->buf_len != ctx->buf_off)
32555714Skris			{
32655714Skris			i=enc_write(b,NULL,0);
32755714Skris			if (i < 0)
328120631Snectar				return i;
32955714Skris			}
33055714Skris
33155714Skris		if (!ctx->finished)
33255714Skris			{
33355714Skris			ctx->finished=1;
33455714Skris			ctx->buf_off=0;
335109998Smarkm			ret=EVP_CipherFinal_ex(&(ctx->cipher),
33655714Skris				(unsigned char *)ctx->buf,
33755714Skris				&(ctx->buf_len));
33855714Skris			ctx->ok=(int)ret;
33955714Skris			if (ret <= 0) break;
34055714Skris
34155714Skris			/* push out the bytes */
34255714Skris			goto again;
34355714Skris			}
34455714Skris
34555714Skris		/* Finally flush the underlying BIO */
34655714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
34755714Skris		break;
34855714Skris	case BIO_C_GET_CIPHER_STATUS:
34955714Skris		ret=(long)ctx->ok;
35055714Skris		break;
35155714Skris	case BIO_C_DO_STATE_MACHINE:
35255714Skris		BIO_clear_retry_flags(b);
35355714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
35455714Skris		BIO_copy_next_retry(b);
35555714Skris		break;
35655714Skris	case BIO_C_GET_CIPHER_CTX:
35755714Skris		c_ctx=(EVP_CIPHER_CTX **)ptr;
35855714Skris		(*c_ctx)= &(ctx->cipher);
35955714Skris		b->init=1;
36055714Skris		break;
36155714Skris	case BIO_CTRL_DUP:
36255714Skris		dbio=(BIO *)ptr;
36355714Skris		dctx=(BIO_ENC_CTX *)dbio->ptr;
364238405Sjkim		EVP_CIPHER_CTX_init(&dctx->cipher);
365238405Sjkim		ret = EVP_CIPHER_CTX_copy(&dctx->cipher,&ctx->cipher);
366238405Sjkim		if (ret)
367238405Sjkim			dbio->init=1;
36855714Skris		break;
36955714Skris	default:
37055714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
37155714Skris		break;
37255714Skris		}
37355714Skris	return(ret);
37455714Skris	}
37555714Skris
37668651Skrisstatic long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
37759191Skris	{
37859191Skris	long ret=1;
37959191Skris
38059191Skris	if (b->next_bio == NULL) return(0);
38159191Skris	switch (cmd)
38259191Skris		{
38359191Skris	default:
38459191Skris		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
38559191Skris		break;
38659191Skris		}
38759191Skris	return(ret);
38859191Skris	}
38959191Skris
39055714Skris/*
39155714Skrisvoid BIO_set_cipher_ctx(b,c)
39255714SkrisBIO *b;
39355714SkrisEVP_CIPHER_ctx *c;
39455714Skris	{
39555714Skris	if (b == NULL) return;
39655714Skris
39755714Skris	if ((b->callback != NULL) &&
39855714Skris		(b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
39955714Skris		return;
40055714Skris
40155714Skris	b->init=1;
40255714Skris	ctx=(BIO_ENC_CTX *)b->ptr;
40355714Skris	memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));
40455714Skris
40555714Skris	if (b->callback != NULL)
40655714Skris		b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
40755714Skris	}
40855714Skris*/
40955714Skris
410160814Ssimonvoid BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
411160814Ssimon	     const unsigned char *i, int e)
41255714Skris	{
41355714Skris	BIO_ENC_CTX *ctx;
41455714Skris
41555714Skris	if (b == NULL) return;
41655714Skris
41755714Skris	if ((b->callback != NULL) &&
41855714Skris		(b->callback(b,BIO_CB_CTRL,(const char *)c,BIO_CTRL_SET,e,0L) <= 0))
41955714Skris		return;
42055714Skris
42155714Skris	b->init=1;
42255714Skris	ctx=(BIO_ENC_CTX *)b->ptr;
423109998Smarkm	EVP_CipherInit_ex(&(ctx->cipher),c,NULL, k,i,e);
42455714Skris
42555714Skris	if (b->callback != NULL)
42655714Skris		b->callback(b,BIO_CB_CTRL,(const char *)c,BIO_CTRL_SET,e,1L);
42755714Skris	}
42855714Skris
429