bio_enc.c 10.4 KB
Newer Older
R
Rich Salz 已提交
1 2
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8 9 10 11
 */

#include <stdio.h>
#include <errno.h>
12
#include "internal/cryptlib.h"
13 14
#include <openssl/buffer.h>
#include <openssl/evp.h>
M
Matt Caswell 已提交
15
#include "internal/bio.h"
16

17 18
static int enc_write(BIO *h, const char *buf, int num);
static int enc_read(BIO *h, char *buf, int size);
19 20 21 22 23 24
/*
 * static int enc_puts(BIO *h, const char *str);
 */
/*
 * static int enc_gets(BIO *h, char *str, int size);
 */
25
static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
26 27
static int enc_new(BIO *h);
static int enc_free(BIO *data);
D
 
Dr. Stephen Henson 已提交
28
static long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps);
29 30 31 32 33 34 35 36 37
#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 */
38
    EVP_CIPHER_CTX *cipher;
39 40 41 42 43 44 45
    /*
     * 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;

46
static const BIO_METHOD methods_enc = {
47 48 49 50 51 52 53 54 55 56
    BIO_TYPE_CIPHER, "cipher",
    enc_write,
    enc_read,
    NULL,                       /* enc_puts, */
    NULL,                       /* enc_gets, */
    enc_ctrl,
    enc_new,
    enc_free,
    enc_callback_ctrl,
};
57

58
const BIO_METHOD *BIO_f_cipher(void)
59 60 61
{
    return (&methods_enc);
}
62

U
Ulf Möller 已提交
63
static int enc_new(BIO *bi)
64 65 66
{
    BIO_ENC_CTX *ctx;

R
Rich Salz 已提交
67
    ctx = OPENSSL_zalloc(sizeof(*ctx));
68
    if (ctx == NULL)
69
        return 0;
70

71 72 73 74 75
    ctx->cipher = EVP_CIPHER_CTX_new();
    if (ctx->cipher == NULL) {
        OPENSSL_free(ctx);
        return 0;
    }
76 77
    ctx->cont = 1;
    ctx->ok = 1;
M
Matt Caswell 已提交
78 79 80
    BIO_set_data(bi, ctx);
    BIO_set_init(bi, 1);

81
    return 1;
82
}
83

U
Ulf Möller 已提交
84
static int enc_free(BIO *a)
85 86 87 88
{
    BIO_ENC_CTX *b;

    if (a == NULL)
M
Matt Caswell 已提交
89 90 91 92 93 94
        return 0;

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

95
    EVP_CIPHER_CTX_free(b->cipher);
M
Matt Caswell 已提交
96 97 98 99 100
    OPENSSL_clear_free(b, sizeof(BIO_ENC_CTX));
    BIO_set_data(a, NULL);
    BIO_set_init(a, 0);

    return 1;
101 102
}

U
Ulf Möller 已提交
103
static int enc_read(BIO *b, char *out, int outl)
104 105 106
{
    int ret = 0, i;
    BIO_ENC_CTX *ctx;
M
Matt Caswell 已提交
107
    BIO *next;
108 109 110

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

M
Matt Caswell 已提交
113 114 115
    next = BIO_next(b);
    if ((ctx == NULL) || (next == NULL))
        return 0;
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

    /* 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 已提交
145
        i = BIO_read(next, &(ctx->buf[BUF_OFFSET]), ENC_BLOCK_SIZE);
146 147 148

        if (i <= 0) {
            /* Should be continue next time we are called? */
M
Matt Caswell 已提交
149
            if (!BIO_should_retry(next)) {
150
                ctx->cont = i;
151
                i = EVP_CipherFinal_ex(ctx->cipher,
152 153 154 155 156 157 158 159 160
                                       (unsigned char *)ctx->buf,
                                       &(ctx->buf_len));
                ctx->ok = i;
                ctx->buf_off = 0;
            } else {
                ret = (ret == 0) ? i : ret;
                break;
            }
        } else {
161
            if (!EVP_CipherUpdate(ctx->cipher,
162 163 164 165
                                  (unsigned char *)ctx->buf, &ctx->buf_len,
                                  (unsigned char *)&(ctx->buf[BUF_OFFSET]),
                                  i)) {
                BIO_clear_retry_flags(b);
166
                ctx->ok = 0;
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 193 194 195 196
                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);
}
197

198
static int enc_write(BIO *b, const char *in, int inl)
199 200 201
{
    int ret = 0, n, i;
    BIO_ENC_CTX *ctx;
M
Matt Caswell 已提交
202 203 204 205 206 207
    BIO *next;

    ctx = BIO_get_data(b);
    next = BIO_next(b);
    if ((ctx == NULL) || (next == NULL))
        return 0;
208 209 210 211 212 213

    ret = inl;

    BIO_clear_retry_flags(b);
    n = ctx->buf_len - ctx->buf_off;
    while (n > 0) {
M
Matt Caswell 已提交
214
        i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
        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;
230
        if (!EVP_CipherUpdate(ctx->cipher,
231 232 233
                              (unsigned char *)ctx->buf, &ctx->buf_len,
                              (unsigned char *)in, n)) {
            BIO_clear_retry_flags(b);
234
            ctx->ok = 0;
235 236 237 238 239 240 241 242
            return 0;
        }
        inl -= n;
        in += n;

        ctx->buf_off = 0;
        n = ctx->buf_len;
        while (n > 0) {
M
Matt Caswell 已提交
243
            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
244 245 246 247 248 249 250 251 252 253 254 255 256
            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);
}
257

258
static long enc_ctrl(BIO *b, int cmd, long num, void *ptr)
259 260 261 262 263 264
{
    BIO *dbio;
    BIO_ENC_CTX *ctx, *dctx;
    long ret = 1;
    int i;
    EVP_CIPHER_CTX **c_ctx;
M
Matt Caswell 已提交
265
    BIO *next;
266

M
Matt Caswell 已提交
267 268 269 270
    ctx = BIO_get_data(b);
    next = BIO_next(b);
    if (ctx == NULL)
        return 0;
271 272 273 274 275

    switch (cmd) {
    case BIO_CTRL_RESET:
        ctx->ok = 1;
        ctx->finished = 0;
276 277
        if (!EVP_CipherInit_ex(ctx->cipher, NULL, NULL, NULL, NULL,
                               EVP_CIPHER_CTX_encrypting(ctx->cipher)))
278
            return 0;
M
Matt Caswell 已提交
279
        ret = BIO_ctrl(next, cmd, num, ptr);
280 281 282 283 284
        break;
    case BIO_CTRL_EOF:         /* More to read */
        if (ctx->cont <= 0)
            ret = 1;
        else
M
Matt Caswell 已提交
285
            ret = BIO_ctrl(next, cmd, num, ptr);
286 287 288 289
        break;
    case BIO_CTRL_WPENDING:
        ret = ctx->buf_len - ctx->buf_off;
        if (ret <= 0)
M
Matt Caswell 已提交
290
            ret = BIO_ctrl(next, cmd, num, ptr);
291 292 293 294
        break;
    case BIO_CTRL_PENDING:     /* More to read in buffer */
        ret = ctx->buf_len - ctx->buf_off;
        if (ret <= 0)
M
Matt Caswell 已提交
295
            ret = BIO_ctrl(next, cmd, num, ptr);
296 297 298 299 300 301 302 303 304 305 306 307 308
        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;
309
            ret = EVP_CipherFinal_ex(ctx->cipher,
310 311 312 313 314 315 316 317 318 319 320
                                     (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 已提交
321
        ret = BIO_ctrl(next, cmd, num, ptr);
322 323 324 325 326 327
        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 已提交
328
        ret = BIO_ctrl(next, cmd, num, ptr);
329 330 331 332
        BIO_copy_next_retry(b);
        break;
    case BIO_C_GET_CIPHER_CTX:
        c_ctx = (EVP_CIPHER_CTX **)ptr;
333
        *c_ctx = ctx->cipher;
M
Matt Caswell 已提交
334
        BIO_set_init(b, 1);
335 336 337
        break;
    case BIO_CTRL_DUP:
        dbio = (BIO *)ptr;
M
Matt Caswell 已提交
338
        dctx = BIO_get_data(dbio);
339 340 341 342
        dctx->cipher = EVP_CIPHER_CTX_new();
        if (dctx->cipher == NULL)
            return 0;
        ret = EVP_CIPHER_CTX_copy(dctx->cipher, ctx->cipher);
343
        if (ret)
M
Matt Caswell 已提交
344
            BIO_set_init(dbio, 1);
345 346
        break;
    default:
M
Matt Caswell 已提交
347
        ret = BIO_ctrl(next, cmd, num, ptr);
348 349 350 351
        break;
    }
    return (ret);
}
352

D
 
Dr. Stephen Henson 已提交
353
static long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
354 355
{
    long ret = 1;
M
Matt Caswell 已提交
356
    BIO *next = BIO_next(b);
357

M
Matt Caswell 已提交
358
    if (next == NULL)
359 360 361
        return (0);
    switch (cmd) {
    default:
M
Matt Caswell 已提交
362
        ret = BIO_callback_ctrl(next, cmd, fp);
363 364 365 366
        break;
    }
    return (ret);
}
367

368
/*-
369 370 371
void BIO_set_cipher_ctx(b,c)
BIO *b;
EVP_CIPHER_ctx *c;
372 373 374 375 376 377 378 379 380 381 382 383 384 385
        {
        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);
        }
386 387
*/

388
int BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
389 390 391
                   const unsigned char *i, int e)
{
    BIO_ENC_CTX *ctx;
M
Matt Caswell 已提交
392
    long (*callback) (struct bio_st *, int, const char *, int, long, long);
393

M
Matt Caswell 已提交
394 395
    ctx = BIO_get_data(b);
    if (ctx == NULL)
396 397
        return 0;

M
Matt Caswell 已提交
398 399 400 401 402
    callback = BIO_get_callback(b);

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

M
Matt Caswell 已提交
405 406
    BIO_set_init(b, 1);

407
    if (!EVP_CipherInit_ex(ctx->cipher, c, NULL, k, i, e))
408 409
        return 0;

M
Matt Caswell 已提交
410 411
    if (callback != NULL)
        return callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L);
412 413
    return 1;
}