1/*
2 * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9#include <stdio.h>
10#include <string.h>
11#include <openssl/evp.h>
12#include <openssl/bio.h>
13#include <openssl/rand.h>
14
15#include "testutil.h"
16
17#define ENCRYPT  1
18#define DECRYPT  0
19
20#define DATA_SIZE    1024
21#define MAX_IV       32
22#define BUF_SIZE     (DATA_SIZE + MAX_IV)
23
24static const unsigned char KEY[] = {
25    0x51, 0x50, 0xd1, 0x77, 0x2f, 0x50, 0x83, 0x4a,
26    0x50, 0x3e, 0x06, 0x9a, 0x97, 0x3f, 0xbd, 0x7c,
27    0xe6, 0x1c, 0x43, 0x2b, 0x72, 0x0b, 0x19, 0xd1,
28    0x8e, 0xc8, 0xd8, 0x4b, 0xdc, 0x63, 0x15, 0x1b
29};
30
31static const unsigned char IV[] = {
32    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
33    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
34    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
35    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
36};
37
38static int do_bio_cipher(const EVP_CIPHER* cipher, const unsigned char* key,
39    const unsigned char* iv)
40{
41    BIO *b, *mem;
42    static unsigned char inp[BUF_SIZE] = { 0 };
43    unsigned char out[BUF_SIZE], ref[BUF_SIZE];
44    int i, lref, len;
45
46    /* Fill buffer with non-zero data so that over steps can be detected */
47    if (!TEST_int_gt(RAND_bytes(inp, DATA_SIZE), 0))
48        return 0;
49
50    /* Encrypt tests */
51
52    /* reference output for single-chunk operation */
53    b = BIO_new(BIO_f_cipher());
54    if (!TEST_ptr(b))
55        return 0;
56    if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT)))
57        goto err;
58    mem = BIO_new_mem_buf(inp, DATA_SIZE);
59    if (!TEST_ptr(mem))
60        goto err;
61    BIO_push(b, mem);
62    lref = BIO_read(b, ref, sizeof(ref));
63    BIO_free_all(b);
64
65    /* perform split operations and compare to reference */
66    for (i = 1; i < lref; i++) {
67        b = BIO_new(BIO_f_cipher());
68        if (!TEST_ptr(b))
69            return 0;
70        if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT))) {
71            TEST_info("Split encrypt failed @ operation %d", i);
72            goto err;
73        }
74        mem = BIO_new_mem_buf(inp, DATA_SIZE);
75        if (!TEST_ptr(mem))
76            goto err;
77        BIO_push(b, mem);
78        memset(out, 0, sizeof(out));
79        out[i] = ~ref[i];
80        len = BIO_read(b, out, i);
81        /* check for overstep */
82        if (!TEST_uchar_eq(out[i], (unsigned char)~ref[i])) {
83            TEST_info("Encrypt overstep check failed @ operation %d", i);
84            goto err;
85        }
86        len += BIO_read(b, out + len, sizeof(out) - len);
87        BIO_free_all(b);
88
89        if (!TEST_mem_eq(out, len, ref, lref)) {
90            TEST_info("Encrypt compare failed @ operation %d", i);
91            return 0;
92        }
93    }
94
95    /* perform small-chunk operations and compare to reference */
96    for (i = 1; i < lref / 2; i++) {
97        int delta;
98
99        b = BIO_new(BIO_f_cipher());
100        if (!TEST_ptr(b))
101            return 0;
102        if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT))) {
103            TEST_info("Small chunk encrypt failed @ operation %d", i);
104            goto err;
105        }
106        mem = BIO_new_mem_buf(inp, DATA_SIZE);
107        if (!TEST_ptr(mem))
108            goto err;
109        BIO_push(b, mem);
110        memset(out, 0, sizeof(out));
111        for (len = 0; (delta = BIO_read(b, out + len, i)); ) {
112            len += delta;
113        }
114        BIO_free_all(b);
115
116        if (!TEST_mem_eq(out, len, ref, lref)) {
117            TEST_info("Small chunk encrypt compare failed @ operation %d", i);
118            return 0;
119        }
120    }
121
122    /* Decrypt tests */
123
124    /* reference output for single-chunk operation */
125    b = BIO_new(BIO_f_cipher());
126    if (!TEST_ptr(b))
127        return 0;
128    if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT)))
129        goto err;
130    /* Use original reference output as input */
131    mem = BIO_new_mem_buf(ref, lref);
132    if (!TEST_ptr(mem))
133        goto err;
134    BIO_push(b, mem);
135    (void)BIO_flush(b);
136    memset(out, 0, sizeof(out));
137    len = BIO_read(b, out, sizeof(out));
138    BIO_free_all(b);
139
140    if (!TEST_mem_eq(inp, DATA_SIZE, out, len))
141        return 0;
142
143    /* perform split operations and compare to reference */
144    for (i = 1; i < lref; i++) {
145        b = BIO_new(BIO_f_cipher());
146        if (!TEST_ptr(b))
147            return 0;
148        if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) {
149            TEST_info("Split decrypt failed @ operation %d", i);
150            goto err;
151        }
152        mem = BIO_new_mem_buf(ref, lref);
153        if (!TEST_ptr(mem))
154            goto err;
155        BIO_push(b, mem);
156        memset(out, 0, sizeof(out));
157        out[i] = ~ref[i];
158        len = BIO_read(b, out, i);
159        /* check for overstep */
160        if (!TEST_uchar_eq(out[i], (unsigned char)~ref[i])) {
161            TEST_info("Decrypt overstep check failed @ operation %d", i);
162            goto err;
163        }
164        len += BIO_read(b, out + len, sizeof(out) - len);
165        BIO_free_all(b);
166
167        if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) {
168            TEST_info("Decrypt compare failed @ operation %d", i);
169            return 0;
170        }
171    }
172
173    /* perform small-chunk operations and compare to reference */
174    for (i = 1; i < lref / 2; i++) {
175        int delta;
176
177        b = BIO_new(BIO_f_cipher());
178        if (!TEST_ptr(b))
179            return 0;
180        if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) {
181            TEST_info("Small chunk decrypt failed @ operation %d", i);
182            goto err;
183        }
184        mem = BIO_new_mem_buf(ref, lref);
185        if (!TEST_ptr(mem))
186            goto err;
187        BIO_push(b, mem);
188        memset(out, 0, sizeof(out));
189        for (len = 0; (delta = BIO_read(b, out + len, i)); ) {
190            len += delta;
191        }
192        BIO_free_all(b);
193
194        if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) {
195            TEST_info("Small chunk decrypt compare failed @ operation %d", i);
196            return 0;
197        }
198    }
199
200    return 1;
201
202err:
203    BIO_free_all(b);
204    return 0;
205}
206
207static int do_test_bio_cipher(const EVP_CIPHER* cipher, int idx)
208{
209    switch(idx)
210    {
211        case 0:
212            return do_bio_cipher(cipher, KEY, NULL);
213        case 1:
214            return do_bio_cipher(cipher, KEY, IV);
215    }
216    return 0;
217}
218
219static int test_bio_enc_aes_128_cbc(int idx)
220{
221    return do_test_bio_cipher(EVP_aes_128_cbc(), idx);
222}
223
224static int test_bio_enc_aes_128_ctr(int idx)
225{
226    return do_test_bio_cipher(EVP_aes_128_ctr(), idx);
227}
228
229static int test_bio_enc_aes_256_cfb(int idx)
230{
231    return do_test_bio_cipher(EVP_aes_256_cfb(), idx);
232}
233
234static int test_bio_enc_aes_256_ofb(int idx)
235{
236    return do_test_bio_cipher(EVP_aes_256_ofb(), idx);
237}
238
239# ifndef OPENSSL_NO_CHACHA
240static int test_bio_enc_chacha20(int idx)
241{
242    return do_test_bio_cipher(EVP_chacha20(), idx);
243}
244
245#  ifndef OPENSSL_NO_POLY1305
246static int test_bio_enc_chacha20_poly1305(int idx)
247{
248    return do_test_bio_cipher(EVP_chacha20_poly1305(), idx);
249}
250#  endif
251# endif
252
253int setup_tests(void)
254{
255    ADD_ALL_TESTS(test_bio_enc_aes_128_cbc, 2);
256    ADD_ALL_TESTS(test_bio_enc_aes_128_ctr, 2);
257    ADD_ALL_TESTS(test_bio_enc_aes_256_cfb, 2);
258    ADD_ALL_TESTS(test_bio_enc_aes_256_ofb, 2);
259# ifndef OPENSSL_NO_CHACHA
260    ADD_ALL_TESTS(test_bio_enc_chacha20, 2);
261#  ifndef OPENSSL_NO_POLY1305
262    ADD_ALL_TESTS(test_bio_enc_chacha20_poly1305, 2);
263#  endif
264# endif
265    return 1;
266}
267