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