]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/evp/bio_enc.c
Change functions to ANSI C.
[thirdparty/openssl.git] / crypto / evp / bio_enc.c
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 "buffer.h"
63 #include "evp.h"
64
65 #ifndef NOPROTO
66 static int enc_write(BIO *h,char *buf,int num);
67 static int enc_read(BIO *h,char *buf,int size);
68 /*static int enc_puts(BIO *h,char *str); */
69 /*static int enc_gets(BIO *h,char *str,int size); */
70 static long enc_ctrl(BIO *h,int cmd,long arg1,char *arg2);
71 static int enc_new(BIO *h);
72 static int enc_free(BIO *data);
73 #else
74 static int enc_write();
75 static int enc_read();
76 /*static int enc_puts(); */
77 /*static int enc_gets(); */
78 static long enc_ctrl();
79 static int enc_new();
80 static int enc_free();
81 #endif
82
83 #define ENC_BLOCK_SIZE (1024*4)
84
85 typedef struct enc_struct
86 {
87 int buf_len;
88 int buf_off;
89 int cont; /* <= 0 when finished */
90 int finished;
91 int ok; /* bad decrypt */
92 EVP_CIPHER_CTX cipher;
93 char buf[ENC_BLOCK_SIZE+10];
94 } BIO_ENC_CTX;
95
96 static BIO_METHOD methods_enc=
97 {
98 BIO_TYPE_CIPHER,"cipher",
99 enc_write,
100 enc_read,
101 NULL, /* enc_puts, */
102 NULL, /* enc_gets, */
103 enc_ctrl,
104 enc_new,
105 enc_free,
106 };
107
108 BIO_METHOD *BIO_f_cipher(void)
109 {
110 return(&methods_enc);
111 }
112
113 static int enc_new(BIO *bi)
114 {
115 BIO_ENC_CTX *ctx;
116
117 ctx=(BIO_ENC_CTX *)Malloc(sizeof(BIO_ENC_CTX));
118 EVP_CIPHER_CTX_init(&ctx->cipher);
119 if (ctx == NULL) return(0);
120
121 ctx->buf_len=0;
122 ctx->buf_off=0;
123 ctx->cont=1;
124 ctx->finished=0;
125 ctx->ok=1;
126
127 bi->init=0;
128 bi->ptr=(char *)ctx;
129 bi->flags=0;
130 return(1);
131 }
132
133 static int enc_free(BIO *a)
134 {
135 BIO_ENC_CTX *b;
136
137 if (a == NULL) return(0);
138 b=(BIO_ENC_CTX *)a->ptr;
139 EVP_CIPHER_CTX_cleanup(&(b->cipher));
140 memset(a->ptr,0,sizeof(BIO_ENC_CTX));
141 Free(a->ptr);
142 a->ptr=NULL;
143 a->init=0;
144 a->flags=0;
145 return(1);
146 }
147
148 static 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) return(0);
154 ctx=(BIO_ENC_CTX *)b->ptr;
155
156 if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
157
158 /* First check if there are bytes decoded/encoded */
159 if (ctx->buf_len > 0)
160 {
161 i=ctx->buf_len-ctx->buf_off;
162 if (i > outl) i=outl;
163 memcpy(out,&(ctx->buf[ctx->buf_off]),i);
164 ret=i;
165 out+=i;
166 outl-=i;
167 ctx->buf_off+=i;
168 if (ctx->buf_len == ctx->buf_off)
169 {
170 ctx->buf_len=0;
171 ctx->buf_off=0;
172 }
173 }
174
175 /* At this point, we have room of outl bytes and an empty
176 * buffer, so we should read in some more. */
177
178 while (outl > 0)
179 {
180 if (ctx->cont <= 0) break;
181
182 /* read in at offset 8, read the EVP_Cipher
183 * documentation about why */
184 i=BIO_read(b->next_bio,&(ctx->buf[8]),ENC_BLOCK_SIZE);
185
186 if (i <= 0)
187 {
188 /* Should be continue next time we are called? */
189 if (!BIO_should_retry(b->next_bio))
190 {
191 ctx->cont=i;
192 i=EVP_CipherFinal(&(ctx->cipher),
193 (unsigned char *)ctx->buf,
194 &(ctx->buf_len));
195 ctx->ok=i;
196 ctx->buf_off=0;
197 }
198 else
199 ret=(ret == 0)?i:ret;
200 break;
201 }
202 else
203 {
204 EVP_CipherUpdate(&(ctx->cipher),
205 (unsigned char *)ctx->buf,&ctx->buf_len,
206 (unsigned char *)&(ctx->buf[8]),i);
207 ctx->cont=1;
208 }
209
210 if (ctx->buf_len <= outl)
211 i=ctx->buf_len;
212 else
213 i=outl;
214
215 if (i <= 0) break;
216 memcpy(out,ctx->buf,i);
217 ret+=i;
218 ctx->buf_off=i;
219 outl-=i;
220 out+=i;
221 }
222
223 BIO_clear_retry_flags(b);
224 BIO_copy_next_retry(b);
225 return((ret == 0)?ctx->cont:ret);
226 }
227
228 static int enc_write(BIO *b, char *in, int inl)
229 {
230 int ret=0,n,i;
231 BIO_ENC_CTX *ctx;
232
233 ctx=(BIO_ENC_CTX *)b->ptr;
234 ret=inl;
235
236 BIO_clear_retry_flags(b);
237 n=ctx->buf_len-ctx->buf_off;
238 while (n > 0)
239 {
240 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
241 if (i <= 0)
242 {
243 BIO_copy_next_retry(b);
244 return(i);
245 }
246 ctx->buf_off+=i;
247 n-=i;
248 }
249 /* at this point all pending data has been written */
250
251 if ((in == NULL) || (inl <= 0)) return(0);
252
253 ctx->buf_off=0;
254 while (inl > 0)
255 {
256 n=(inl > ENC_BLOCK_SIZE)?ENC_BLOCK_SIZE:inl;
257 EVP_CipherUpdate(&(ctx->cipher),
258 (unsigned char *)ctx->buf,&ctx->buf_len,
259 (unsigned char *)in,n);
260 inl-=n;
261 in+=n;
262
263 ctx->buf_off=0;
264 n=ctx->buf_len;
265 while (n > 0)
266 {
267 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
268 if (i <= 0)
269 {
270 BIO_copy_next_retry(b);
271 return(i);
272 }
273 n-=i;
274 ctx->buf_off+=i;
275 }
276 ctx->buf_len=0;
277 ctx->buf_off=0;
278 }
279 BIO_copy_next_retry(b);
280 return(ret);
281 }
282
283 static long enc_ctrl(BIO *b, int cmd, long num, char *ptr)
284 {
285 BIO *dbio;
286 BIO_ENC_CTX *ctx,*dctx;
287 long ret=1;
288 int i;
289 EVP_CIPHER_CTX **c_ctx;
290
291 ctx=(BIO_ENC_CTX *)b->ptr;
292
293 switch (cmd)
294 {
295 case BIO_CTRL_RESET:
296 ctx->ok=1;
297 ctx->finished=0;
298 EVP_CipherInit(&(ctx->cipher),NULL,NULL,NULL,
299 ctx->cipher.encrypt);
300 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
301 break;
302 case BIO_CTRL_EOF: /* More to read */
303 if (ctx->cont <= 0)
304 ret=1;
305 else
306 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
307 break;
308 case BIO_CTRL_WPENDING:
309 ret=ctx->buf_len-ctx->buf_off;
310 if (ret <= 0)
311 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
312 break;
313 case BIO_CTRL_PENDING: /* More to read in buffer */
314 ret=ctx->buf_len-ctx->buf_off;
315 if (ret <= 0)
316 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
317 break;
318 case BIO_CTRL_FLUSH:
319 /* do a final write */
320 again:
321 while (ctx->buf_len != ctx->buf_off)
322 {
323 i=enc_write(b,NULL,0);
324 if (i < 0)
325 {
326 ret=i;
327 break;
328 }
329 }
330
331 if (!ctx->finished)
332 {
333 ctx->finished=1;
334 ctx->buf_off=0;
335 ret=EVP_CipherFinal(&(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 memcpy(&(dctx->cipher),&(ctx->cipher),sizeof(ctx->cipher));
365 dbio->init=1;
366 break;
367 default:
368 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
369 break;
370 }
371 return(ret);
372 }
373
374 /*
375 void BIO_set_cipher_ctx(b,c)
376 BIO *b;
377 EVP_CIPHER_ctx *c;
378 {
379 if (b == NULL) return;
380
381 if ((b->callback != NULL) &&
382 (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
383 return;
384
385 b->init=1;
386 ctx=(BIO_ENC_CTX *)b->ptr;
387 memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));
388
389 if (b->callback != NULL)
390 b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
391 }
392 */
393
394 void BIO_set_cipher(BIO *b, const EVP_CIPHER *c, unsigned char *k,
395 unsigned char *i, int e)
396 {
397 BIO_ENC_CTX *ctx;
398
399 if (b == NULL) return;
400
401 if ((b->callback != NULL) &&
402 (b->callback(b,BIO_CB_CTRL,(const char *)c,BIO_CTRL_SET,e,0L) <= 0))
403 return;
404
405 b->init=1;
406 ctx=(BIO_ENC_CTX *)b->ptr;
407 EVP_CipherInit(&(ctx->cipher),c,k,i,e);
408
409 if (b->callback != NULL)
410 b->callback(b,BIO_CB_CTRL,(const char *)c,BIO_CTRL_SET,e,1L);
411 }
412