bio_enc.c 13.1 KB
Newer Older
1
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 3 4 5 6
 * All rights reserved.
 *
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
7
 *
8 9 10 11 12 13
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14
 *
15 16 17 18 19 20
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
21
 *
22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
36
 * 4. If you include any Windows specific code (or a derivative thereof) from
37 38
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39
 *
40 41 42 43 44 45 46 47 48 49 50
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
51
 *
52 53 54 55 56 57 58 59
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

#include <stdio.h>
#include <errno.h>
60
#include "internal/cryptlib.h"
61 62
#include <openssl/buffer.h>
#include <openssl/evp.h>
M
Matt Caswell 已提交
63
#include "internal/bio.h"
64

65 66
static int enc_write(BIO *h, const char *buf, int num);
static int enc_read(BIO *h, char *buf, int size);
67 68 69 70 71 72
/*
 * static int enc_puts(BIO *h, const char *str);
 */
/*
 * static int enc_gets(BIO *h, char *str, int size);
 */
73
static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
74 75
static int enc_new(BIO *h);
static int enc_free(BIO *data);
D
 
Dr. Stephen Henson 已提交
76
static long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps);
77 78 79 80 81 82 83 84 85
#define ENC_BLOCK_SIZE  (1024*4)
#define BUF_OFFSET      (EVP_MAX_BLOCK_LENGTH*2)

typedef struct enc_struct {
    int buf_len;
    int buf_off;
    int cont;                   /* <= 0 when finished */
    int finished;
    int ok;                     /* bad decrypt */
86
    EVP_CIPHER_CTX *cipher;
87 88 89 90 91 92 93
    /*
     * buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate can return
     * up to a block more data than is presented to it
     */
    char buf[ENC_BLOCK_SIZE + BUF_OFFSET + 2];
} BIO_ENC_CTX;

94
static const BIO_METHOD methods_enc = {
95 96 97 98 99 100 101 102 103 104
    BIO_TYPE_CIPHER, "cipher",
    enc_write,
    enc_read,
    NULL,                       /* enc_puts, */
    NULL,                       /* enc_gets, */
    enc_ctrl,
    enc_new,
    enc_free,
    enc_callback_ctrl,
};
105

106
const BIO_METHOD *BIO_f_cipher(void)
107 108 109
{
    return (&methods_enc);
}
110

U
Ulf Möller 已提交
111
static int enc_new(BIO *bi)
112 113 114
{
    BIO_ENC_CTX *ctx;

R
Rich Salz 已提交
115
    ctx = OPENSSL_zalloc(sizeof(*ctx));
116
    if (ctx == NULL)
117
        return 0;
118

119 120 121 122 123
    ctx->cipher = EVP_CIPHER_CTX_new();
    if (ctx->cipher == NULL) {
        OPENSSL_free(ctx);
        return 0;
    }
124 125
    ctx->cont = 1;
    ctx->ok = 1;
M
Matt Caswell 已提交
126 127 128
    BIO_set_data(bi, ctx);
    BIO_set_init(bi, 1);

129
    return 1;
130
}
131

U
Ulf Möller 已提交
132
static int enc_free(BIO *a)
133 134 135 136
{
    BIO_ENC_CTX *b;

    if (a == NULL)
M
Matt Caswell 已提交
137 138 139 140 141 142
        return 0;

    b = BIO_get_data(a);
    if (b == NULL)
        return 0;

143
    EVP_CIPHER_CTX_free(b->cipher);
M
Matt Caswell 已提交
144 145 146 147 148
    OPENSSL_clear_free(b, sizeof(BIO_ENC_CTX));
    BIO_set_data(a, NULL);
    BIO_set_init(a, 0);

    return 1;
149 150
}

U
Ulf Möller 已提交
151
static int enc_read(BIO *b, char *out, int outl)
152 153 154
{
    int ret = 0, i;
    BIO_ENC_CTX *ctx;
M
Matt Caswell 已提交
155
    BIO *next;
156 157 158

    if (out == NULL)
        return (0);
M
Matt Caswell 已提交
159
    ctx = BIO_get_data(b);
160

M
Matt Caswell 已提交
161 162 163
    next = BIO_next(b);
    if ((ctx == NULL) || (next == NULL))
        return 0;
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

    /* First check if there are bytes decoded/encoded */
    if (ctx->buf_len > 0) {
        i = ctx->buf_len - ctx->buf_off;
        if (i > outl)
            i = outl;
        memcpy(out, &(ctx->buf[ctx->buf_off]), i);
        ret = i;
        out += i;
        outl -= i;
        ctx->buf_off += i;
        if (ctx->buf_len == ctx->buf_off) {
            ctx->buf_len = 0;
            ctx->buf_off = 0;
        }
    }

    /*
     * At this point, we have room of outl bytes and an empty buffer, so we
     * should read in some more.
     */

    while (outl > 0) {
        if (ctx->cont <= 0)
            break;

        /*
         * read in at IV offset, read the EVP_Cipher documentation about why
         */
M
Matt Caswell 已提交
193
        i = BIO_read(next, &(ctx->buf[BUF_OFFSET]), ENC_BLOCK_SIZE);
194 195 196

        if (i <= 0) {
            /* Should be continue next time we are called? */
M
Matt Caswell 已提交
197
            if (!BIO_should_retry(next)) {
198
                ctx->cont = i;
199
                i = EVP_CipherFinal_ex(ctx->cipher,
200 201 202 203 204 205 206 207 208
                                       (unsigned char *)ctx->buf,
                                       &(ctx->buf_len));
                ctx->ok = i;
                ctx->buf_off = 0;
            } else {
                ret = (ret == 0) ? i : ret;
                break;
            }
        } else {
209
            if (!EVP_CipherUpdate(ctx->cipher,
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
                                  (unsigned char *)ctx->buf, &ctx->buf_len,
                                  (unsigned char *)&(ctx->buf[BUF_OFFSET]),
                                  i)) {
                BIO_clear_retry_flags(b);
                return 0;
            }
            ctx->cont = 1;
            /*
             * Note: it is possible for EVP_CipherUpdate to decrypt zero
             * bytes because this is or looks like the final block: if this
             * happens we should retry and either read more data or decrypt
             * the final block
             */
            if (ctx->buf_len == 0)
                continue;
        }

        if (ctx->buf_len <= outl)
            i = ctx->buf_len;
        else
            i = outl;
        if (i <= 0)
            break;
        memcpy(out, ctx->buf, i);
        ret += i;
        ctx->buf_off = i;
        outl -= i;
        out += i;
    }

    BIO_clear_retry_flags(b);
    BIO_copy_next_retry(b);
    return ((ret == 0) ? ctx->cont : ret);
}
244

245
static int enc_write(BIO *b, const char *in, int inl)
246 247 248
{
    int ret = 0, n, i;
    BIO_ENC_CTX *ctx;
M
Matt Caswell 已提交
249 250 251 252 253 254
    BIO *next;

    ctx = BIO_get_data(b);
    next = BIO_next(b);
    if ((ctx == NULL) || (next == NULL))
        return 0;
255 256 257 258 259 260

    ret = inl;

    BIO_clear_retry_flags(b);
    n = ctx->buf_len - ctx->buf_off;
    while (n > 0) {
M
Matt Caswell 已提交
261
        i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
        if (i <= 0) {
            BIO_copy_next_retry(b);
            return (i);
        }
        ctx->buf_off += i;
        n -= i;
    }
    /* at this point all pending data has been written */

    if ((in == NULL) || (inl <= 0))
        return (0);

    ctx->buf_off = 0;
    while (inl > 0) {
        n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl;
277
        if (!EVP_CipherUpdate(ctx->cipher,
278 279 280 281 282 283 284 285 286 287 288
                              (unsigned char *)ctx->buf, &ctx->buf_len,
                              (unsigned char *)in, n)) {
            BIO_clear_retry_flags(b);
            return 0;
        }
        inl -= n;
        in += n;

        ctx->buf_off = 0;
        n = ctx->buf_len;
        while (n > 0) {
M
Matt Caswell 已提交
289
            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
290 291 292 293 294 295 296 297 298 299 300 301 302
            if (i <= 0) {
                BIO_copy_next_retry(b);
                return (ret == inl) ? i : ret - inl;
            }
            n -= i;
            ctx->buf_off += i;
        }
        ctx->buf_len = 0;
        ctx->buf_off = 0;
    }
    BIO_copy_next_retry(b);
    return (ret);
}
303

304
static long enc_ctrl(BIO *b, int cmd, long num, void *ptr)
305 306 307 308 309 310
{
    BIO *dbio;
    BIO_ENC_CTX *ctx, *dctx;
    long ret = 1;
    int i;
    EVP_CIPHER_CTX **c_ctx;
M
Matt Caswell 已提交
311
    BIO *next;
312

M
Matt Caswell 已提交
313 314 315 316
    ctx = BIO_get_data(b);
    next = BIO_next(b);
    if (ctx == NULL)
        return 0;
317 318 319 320 321

    switch (cmd) {
    case BIO_CTRL_RESET:
        ctx->ok = 1;
        ctx->finished = 0;
322 323
        if (!EVP_CipherInit_ex(ctx->cipher, NULL, NULL, NULL, NULL,
                               EVP_CIPHER_CTX_encrypting(ctx->cipher)))
324
            return 0;
M
Matt Caswell 已提交
325
        ret = BIO_ctrl(next, cmd, num, ptr);
326 327 328 329 330
        break;
    case BIO_CTRL_EOF:         /* More to read */
        if (ctx->cont <= 0)
            ret = 1;
        else
M
Matt Caswell 已提交
331
            ret = BIO_ctrl(next, cmd, num, ptr);
332 333 334 335
        break;
    case BIO_CTRL_WPENDING:
        ret = ctx->buf_len - ctx->buf_off;
        if (ret <= 0)
M
Matt Caswell 已提交
336
            ret = BIO_ctrl(next, cmd, num, ptr);
337 338 339 340
        break;
    case BIO_CTRL_PENDING:     /* More to read in buffer */
        ret = ctx->buf_len - ctx->buf_off;
        if (ret <= 0)
M
Matt Caswell 已提交
341
            ret = BIO_ctrl(next, cmd, num, ptr);
342 343 344 345 346 347 348 349 350 351 352 353 354
        break;
    case BIO_CTRL_FLUSH:
        /* do a final write */
 again:
        while (ctx->buf_len != ctx->buf_off) {
            i = enc_write(b, NULL, 0);
            if (i < 0)
                return i;
        }

        if (!ctx->finished) {
            ctx->finished = 1;
            ctx->buf_off = 0;
355
            ret = EVP_CipherFinal_ex(ctx->cipher,
356 357 358 359 360 361 362 363 364 365 366
                                     (unsigned char *)ctx->buf,
                                     &(ctx->buf_len));
            ctx->ok = (int)ret;
            if (ret <= 0)
                break;

            /* push out the bytes */
            goto again;
        }

        /* Finally flush the underlying BIO */
M
Matt Caswell 已提交
367
        ret = BIO_ctrl(next, cmd, num, ptr);
368 369 370 371 372 373
        break;
    case BIO_C_GET_CIPHER_STATUS:
        ret = (long)ctx->ok;
        break;
    case BIO_C_DO_STATE_MACHINE:
        BIO_clear_retry_flags(b);
M
Matt Caswell 已提交
374
        ret = BIO_ctrl(next, cmd, num, ptr);
375 376 377 378
        BIO_copy_next_retry(b);
        break;
    case BIO_C_GET_CIPHER_CTX:
        c_ctx = (EVP_CIPHER_CTX **)ptr;
379
        *c_ctx = ctx->cipher;
M
Matt Caswell 已提交
380
        BIO_set_init(b, 1);
381 382 383
        break;
    case BIO_CTRL_DUP:
        dbio = (BIO *)ptr;
M
Matt Caswell 已提交
384
        dctx = BIO_get_data(dbio);
385 386 387 388
        dctx->cipher = EVP_CIPHER_CTX_new();
        if (dctx->cipher == NULL)
            return 0;
        ret = EVP_CIPHER_CTX_copy(dctx->cipher, ctx->cipher);
389
        if (ret)
M
Matt Caswell 已提交
390
            BIO_set_init(dbio, 1);
391 392
        break;
    default:
M
Matt Caswell 已提交
393
        ret = BIO_ctrl(next, cmd, num, ptr);
394 395 396 397
        break;
    }
    return (ret);
}
398

D
 
Dr. Stephen Henson 已提交
399
static long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
400 401
{
    long ret = 1;
M
Matt Caswell 已提交
402
    BIO *next = BIO_next(b);
403

M
Matt Caswell 已提交
404
    if (next == NULL)
405 406 407
        return (0);
    switch (cmd) {
    default:
M
Matt Caswell 已提交
408
        ret = BIO_callback_ctrl(next, cmd, fp);
409 410 411 412
        break;
    }
    return (ret);
}
413

414
/*-
415 416 417
void BIO_set_cipher_ctx(b,c)
BIO *b;
EVP_CIPHER_ctx *c;
418 419 420 421 422 423 424 425 426 427 428 429 430 431
        {
        if (b == NULL) return;

        if ((b->callback != NULL) &&
                (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
                return;

        b->init=1;
        ctx=(BIO_ENC_CTX *)b->ptr;
        memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));

        if (b->callback != NULL)
                b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
        }
432 433
*/

434
int BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
435 436 437
                   const unsigned char *i, int e)
{
    BIO_ENC_CTX *ctx;
M
Matt Caswell 已提交
438
    long (*callback) (struct bio_st *, int, const char *, int, long, long);
439

M
Matt Caswell 已提交
440 441
    ctx = BIO_get_data(b);
    if (ctx == NULL)
442 443
        return 0;

M
Matt Caswell 已提交
444 445 446 447 448
    callback = BIO_get_callback(b);

    if ((callback != NULL) &&
            (callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e,
                      0L) <= 0))
449 450
        return 0;

M
Matt Caswell 已提交
451 452
    BIO_set_init(b, 1);

453
    if (!EVP_CipherInit_ex(ctx->cipher, c, NULL, k, i, e))
454 455
        return 0;

M
Matt Caswell 已提交
456 457
    if (callback != NULL)
        return callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L);
458 459
    return 1;
}