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/*static int enc_puts(BIO *h, const char *str); */
68/*static int enc_gets(BIO *h, char *str, int size); */
69static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
70static int enc_new(BIO *h);
71static int enc_free(BIO *data);
72static long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps);
73#define ENC_BLOCK_SIZE	(1024*4)
74#define BUF_OFFSET	(EVP_MAX_BLOCK_LENGTH*2)
75
76typedef struct enc_struct
77	{
78	int buf_len;
79	int buf_off;
80	int cont;		/* <= 0 when finished */
81	int finished;
82	int ok;			/* bad decrypt */
83	EVP_CIPHER_CTX cipher;
84	/* buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate
85	 * can return up to a block more data than is presented to it
86	 */
87	char buf[ENC_BLOCK_SIZE+BUF_OFFSET+2];
88	} BIO_ENC_CTX;
89
90static BIO_METHOD methods_enc=
91	{
92	BIO_TYPE_CIPHER,"cipher",
93	enc_write,
94	enc_read,
95	NULL, /* enc_puts, */
96	NULL, /* enc_gets, */
97	enc_ctrl,
98	enc_new,
99	enc_free,
100	enc_callback_ctrl,
101	};
102
103BIO_METHOD *BIO_f_cipher(void)
104	{
105	return(&methods_enc);
106	}
107
108static int enc_new(BIO *bi)
109	{
110	BIO_ENC_CTX *ctx;
111
112	ctx=(BIO_ENC_CTX *)OPENSSL_malloc(sizeof(BIO_ENC_CTX));
113	if (ctx == NULL) return(0);
114	EVP_CIPHER_CTX_init(&ctx->cipher);
115
116	ctx->buf_len=0;
117	ctx->buf_off=0;
118	ctx->cont=1;
119	ctx->finished=0;
120	ctx->ok=1;
121
122	bi->init=0;
123	bi->ptr=(char *)ctx;
124	bi->flags=0;
125	return(1);
126	}
127
128static int enc_free(BIO *a)
129	{
130	BIO_ENC_CTX *b;
131
132	if (a == NULL) return(0);
133	b=(BIO_ENC_CTX *)a->ptr;
134	EVP_CIPHER_CTX_cleanup(&(b->cipher));
135	OPENSSL_cleanse(a->ptr,sizeof(BIO_ENC_CTX));
136	OPENSSL_free(a->ptr);
137	a->ptr=NULL;
138	a->init=0;
139	a->flags=0;
140	return(1);
141	}
142
143static int enc_read(BIO *b, char *out, int outl)
144	{
145	int ret=0,i;
146	BIO_ENC_CTX *ctx;
147
148	if (out == NULL) return(0);
149	ctx=(BIO_ENC_CTX *)b->ptr;
150
151	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
152
153	/* First check if there are bytes decoded/encoded */
154	if (ctx->buf_len > 0)
155		{
156		i=ctx->buf_len-ctx->buf_off;
157		if (i > outl) i=outl;
158		memcpy(out,&(ctx->buf[ctx->buf_off]),i);
159		ret=i;
160		out+=i;
161		outl-=i;
162		ctx->buf_off+=i;
163		if (ctx->buf_len == ctx->buf_off)
164			{
165			ctx->buf_len=0;
166			ctx->buf_off=0;
167			}
168		}
169
170	/* At this point, we have room of outl bytes and an empty
171	 * buffer, so we should read in some more. */
172
173	while (outl > 0)
174		{
175		if (ctx->cont <= 0) break;
176
177		/* read in at IV offset, read the EVP_Cipher
178		 * documentation about why */
179		i=BIO_read(b->next_bio,&(ctx->buf[BUF_OFFSET]),ENC_BLOCK_SIZE);
180
181		if (i <= 0)
182			{
183			/* Should be continue next time we are called? */
184			if (!BIO_should_retry(b->next_bio))
185				{
186				ctx->cont=i;
187				i=EVP_CipherFinal_ex(&(ctx->cipher),
188					(unsigned char *)ctx->buf,
189					&(ctx->buf_len));
190				ctx->ok=i;
191				ctx->buf_off=0;
192				}
193			else
194				{
195				ret=(ret == 0)?i:ret;
196				break;
197				}
198			}
199		else
200			{
201			EVP_CipherUpdate(&(ctx->cipher),
202				(unsigned char *)ctx->buf,&ctx->buf_len,
203				(unsigned char *)&(ctx->buf[BUF_OFFSET]),i);
204			ctx->cont=1;
205			/* Note: it is possible for EVP_CipherUpdate to
206			 * decrypt zero bytes because this is or looks like
207			 * the final block: if this happens we should retry
208			 * and either read more data or decrypt the final
209			 * block
210			 */
211			if(ctx->buf_len == 0) continue;
212			}
213
214		if (ctx->buf_len <= outl)
215			i=ctx->buf_len;
216		else
217			i=outl;
218		if (i <= 0) break;
219		memcpy(out,ctx->buf,i);
220		ret+=i;
221		ctx->buf_off=i;
222		outl-=i;
223		out+=i;
224		}
225
226	BIO_clear_retry_flags(b);
227	BIO_copy_next_retry(b);
228	return((ret == 0)?ctx->cont:ret);
229	}
230
231static int enc_write(BIO *b, const char *in, int inl)
232	{
233	int ret=0,n,i;
234	BIO_ENC_CTX *ctx;
235
236	ctx=(BIO_ENC_CTX *)b->ptr;
237	ret=inl;
238
239	BIO_clear_retry_flags(b);
240	n=ctx->buf_len-ctx->buf_off;
241	while (n > 0)
242		{
243		i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
244		if (i <= 0)
245			{
246			BIO_copy_next_retry(b);
247			return(i);
248			}
249		ctx->buf_off+=i;
250		n-=i;
251		}
252	/* at this point all pending data has been written */
253
254	if ((in == NULL) || (inl <= 0)) return(0);
255
256	ctx->buf_off=0;
257	while (inl > 0)
258		{
259		n=(inl > ENC_BLOCK_SIZE)?ENC_BLOCK_SIZE:inl;
260		EVP_CipherUpdate(&(ctx->cipher),
261			(unsigned char *)ctx->buf,&ctx->buf_len,
262			(unsigned char *)in,n);
263		inl-=n;
264		in+=n;
265
266		ctx->buf_off=0;
267		n=ctx->buf_len;
268		while (n > 0)
269			{
270			i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
271			if (i <= 0)
272				{
273				BIO_copy_next_retry(b);
274				return (ret == inl) ? i : ret - inl;
275				}
276			n-=i;
277			ctx->buf_off+=i;
278			}
279		ctx->buf_len=0;
280		ctx->buf_off=0;
281		}
282	BIO_copy_next_retry(b);
283	return(ret);
284	}
285
286static long enc_ctrl(BIO *b, int cmd, long num, void *ptr)
287	{
288	BIO *dbio;
289	BIO_ENC_CTX *ctx,*dctx;
290	long ret=1;
291	int i;
292	EVP_CIPHER_CTX **c_ctx;
293
294	ctx=(BIO_ENC_CTX *)b->ptr;
295
296	switch (cmd)
297		{
298	case BIO_CTRL_RESET:
299		ctx->ok=1;
300		ctx->finished=0;
301		EVP_CipherInit_ex(&(ctx->cipher),NULL,NULL,NULL,NULL,
302			ctx->cipher.encrypt);
303		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
304		break;
305	case BIO_CTRL_EOF:	/* More to read */
306		if (ctx->cont <= 0)
307			ret=1;
308		else
309			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
310		break;
311	case BIO_CTRL_WPENDING:
312		ret=ctx->buf_len-ctx->buf_off;
313		if (ret <= 0)
314			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
315		break;
316	case BIO_CTRL_PENDING: /* More to read in buffer */
317		ret=ctx->buf_len-ctx->buf_off;
318		if (ret <= 0)
319			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
320		break;
321	case BIO_CTRL_FLUSH:
322		/* do a final write */
323again:
324		while (ctx->buf_len != ctx->buf_off)
325			{
326			i=enc_write(b,NULL,0);
327			if (i < 0)
328				return i;
329			}
330
331		if (!ctx->finished)
332			{
333			ctx->finished=1;
334			ctx->buf_off=0;
335			ret=EVP_CipherFinal_ex(&(ctx->cipher),
336				(unsigned char *)ctx->buf,
337				&(ctx->buf_len));
338			ctx->ok=(int)ret;
339			if (ret <= 0) break;
340
341			/* push out the bytes */
342			goto again;
343			}
344
345		/* Finally flush the underlying BIO */
346		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
347		break;
348	case BIO_C_GET_CIPHER_STATUS:
349		ret=(long)ctx->ok;
350		break;
351	case BIO_C_DO_STATE_MACHINE:
352		BIO_clear_retry_flags(b);
353		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
354		BIO_copy_next_retry(b);
355		break;
356	case BIO_C_GET_CIPHER_CTX:
357		c_ctx=(EVP_CIPHER_CTX **)ptr;
358		(*c_ctx)= &(ctx->cipher);
359		b->init=1;
360		break;
361	case BIO_CTRL_DUP:
362		dbio=(BIO *)ptr;
363		dctx=(BIO_ENC_CTX *)dbio->ptr;
364		EVP_CIPHER_CTX_init(&dctx->cipher);
365		ret = EVP_CIPHER_CTX_copy(&dctx->cipher,&ctx->cipher);
366		if (ret)
367			dbio->init=1;
368		break;
369	default:
370		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
371		break;
372		}
373	return(ret);
374	}
375
376static long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
377	{
378	long ret=1;
379
380	if (b->next_bio == NULL) return(0);
381	switch (cmd)
382		{
383	default:
384		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
385		break;
386		}
387	return(ret);
388	}
389
390/*
391void BIO_set_cipher_ctx(b,c)
392BIO *b;
393EVP_CIPHER_ctx *c;
394	{
395	if (b == NULL) return;
396
397	if ((b->callback != NULL) &&
398		(b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
399		return;
400
401	b->init=1;
402	ctx=(BIO_ENC_CTX *)b->ptr;
403	memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));
404
405	if (b->callback != NULL)
406		b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
407	}
408*/
409
410void BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
411	     const unsigned char *i, int e)
412	{
413	BIO_ENC_CTX *ctx;
414
415	if (b == NULL) return;
416
417	if ((b->callback != NULL) &&
418		(b->callback(b,BIO_CB_CTRL,(const char *)c,BIO_CTRL_SET,e,0L) <= 0))
419		return;
420
421	b->init=1;
422	ctx=(BIO_ENC_CTX *)b->ptr;
423	EVP_CipherInit_ex(&(ctx->cipher),c,NULL, k,i,e);
424
425	if (b->callback != NULL)
426		b->callback(b,BIO_CB_CTRL,(const char *)c,BIO_CTRL_SET,e,1L);
427	}
428
429