1 /* 2 * Copyright 2016-2025 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 24 static 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 31 static 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 38 static 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, tmplen; 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 tmplen = BIO_read(b, out, i); 81 if (tmplen < 0) 82 goto err; 83 len = tmplen; 84 /* check for overstep */ 85 if (!TEST_uchar_eq(out[i], (unsigned char)~ref[i])) { 86 TEST_info("Encrypt overstep check failed @ operation %d", i); 87 goto err; 88 } 89 tmplen = BIO_read(b, out + len, sizeof(out) - len); 90 if (tmplen < 0) 91 goto err; 92 len += tmplen; 93 94 BIO_free_all(b); 95 96 if (!TEST_mem_eq(out, len, ref, lref)) { 97 TEST_info("Encrypt compare failed @ operation %d", i); 98 return 0; 99 } 100 } 101 102 /* perform small-chunk operations and compare to reference */ 103 for (i = 1; i < lref / 2; i++) { 104 int delta; 105 106 b = BIO_new(BIO_f_cipher()); 107 if (!TEST_ptr(b)) 108 return 0; 109 if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT))) { 110 TEST_info("Small chunk encrypt failed @ operation %d", i); 111 goto err; 112 } 113 mem = BIO_new_mem_buf(inp, DATA_SIZE); 114 if (!TEST_ptr(mem)) 115 goto err; 116 BIO_push(b, mem); 117 memset(out, 0, sizeof(out)); 118 for (len = 0; (delta = BIO_read(b, out + len, i)); ) { 119 len += delta; 120 } 121 BIO_free_all(b); 122 123 if (!TEST_mem_eq(out, len, ref, lref)) { 124 TEST_info("Small chunk encrypt compare failed @ operation %d", i); 125 return 0; 126 } 127 } 128 129 /* Decrypt tests */ 130 131 /* reference output for single-chunk operation */ 132 b = BIO_new(BIO_f_cipher()); 133 if (!TEST_ptr(b)) 134 return 0; 135 if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) 136 goto err; 137 /* Use original reference output as input */ 138 mem = BIO_new_mem_buf(ref, lref); 139 if (!TEST_ptr(mem)) 140 goto err; 141 BIO_push(b, mem); 142 #if 0 143 /* 144 * This is wrong to do, it always fails, and incorrectly ends up 145 * calling `EVP_CipherFinal()` and setting ctx->finished = 1, ... 146 * all of which are unwanted. But just deleting this is less 147 * instructive to future readers of the code. Don't call BIO_flush 148 * until you're done either reading or writing and want to finalise 149 * the state. 150 */ 151 (void)BIO_flush(b); 152 #endif 153 memset(out, 0, sizeof(out)); 154 len = BIO_read(b, out, sizeof(out)); 155 BIO_free_all(b); 156 157 if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) 158 return 0; 159 160 /* perform split operations and compare to reference */ 161 for (i = 1; i < lref; i++) { 162 b = BIO_new(BIO_f_cipher()); 163 if (!TEST_ptr(b)) 164 return 0; 165 if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) { 166 TEST_info("Split decrypt failed @ operation %d", i); 167 goto err; 168 } 169 mem = BIO_new_mem_buf(ref, lref); 170 if (!TEST_ptr(mem)) 171 goto err; 172 BIO_push(b, mem); 173 memset(out, 0, sizeof(out)); 174 out[i] = ~ref[i]; 175 len = BIO_read(b, out, i); 176 /* check for overstep */ 177 if (!TEST_uchar_eq(out[i], (unsigned char)~ref[i])) { 178 TEST_info("Decrypt overstep check failed @ operation %d", i); 179 goto err; 180 } 181 len += BIO_read(b, out + len, sizeof(out) - len); 182 BIO_free_all(b); 183 184 if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) { 185 TEST_info("Decrypt compare failed @ operation %d", i); 186 return 0; 187 } 188 } 189 190 /* perform small-chunk operations and compare to reference */ 191 for (i = 1; i < lref / 2; i++) { 192 int delta; 193 194 b = BIO_new(BIO_f_cipher()); 195 if (!TEST_ptr(b)) 196 return 0; 197 if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) { 198 TEST_info("Small chunk decrypt failed @ operation %d", i); 199 goto err; 200 } 201 mem = BIO_new_mem_buf(ref, lref); 202 if (!TEST_ptr(mem)) 203 goto err; 204 BIO_push(b, mem); 205 memset(out, 0, sizeof(out)); 206 for (len = 0; (delta = BIO_read(b, out + len, i)); ) { 207 len += delta; 208 } 209 BIO_free_all(b); 210 211 if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) { 212 TEST_info("Small chunk decrypt compare failed @ operation %d", i); 213 return 0; 214 } 215 } 216 217 return 1; 218 219 err: 220 BIO_free_all(b); 221 return 0; 222 } 223 224 static int do_test_bio_cipher(const EVP_CIPHER* cipher, int idx) 225 { 226 switch (idx) { 227 case 0: 228 return do_bio_cipher(cipher, KEY, NULL); 229 case 1: 230 return do_bio_cipher(cipher, KEY, IV); 231 } 232 return 0; 233 } 234 235 static int test_bio_enc_aes_128_cbc(int idx) 236 { 237 return do_test_bio_cipher(EVP_aes_128_cbc(), idx); 238 } 239 240 static int test_bio_enc_aes_128_ctr(int idx) 241 { 242 return do_test_bio_cipher(EVP_aes_128_ctr(), idx); 243 } 244 245 static int test_bio_enc_aes_256_cfb(int idx) 246 { 247 return do_test_bio_cipher(EVP_aes_256_cfb(), idx); 248 } 249 250 static int test_bio_enc_aes_256_ofb(int idx) 251 { 252 return do_test_bio_cipher(EVP_aes_256_ofb(), idx); 253 } 254 255 # ifndef OPENSSL_NO_CHACHA 256 static int test_bio_enc_chacha20(int idx) 257 { 258 return do_test_bio_cipher(EVP_chacha20(), idx); 259 } 260 261 # ifndef OPENSSL_NO_POLY1305 262 static int test_bio_enc_chacha20_poly1305(int idx) 263 { 264 return do_test_bio_cipher(EVP_chacha20_poly1305(), idx); 265 } 266 # endif 267 # endif 268 269 static int test_bio_enc_eof_read_flush(void) 270 { 271 /* Length chosen to ensure base64 encoding employs padding */ 272 const unsigned char pbuf[] = "Attack at dawn"; 273 unsigned char cbuf[16]; /* At least as long as pbuf */ 274 const EVP_CIPHER *cipher = EVP_aes_256_gcm(); 275 EVP_CIPHER_CTX *ctx = NULL; 276 BIO *mem = NULL, *b64 = NULL, *cbio = NULL; 277 unsigned char tag[16]; 278 size_t key_size, iv_size; 279 int n, ret = 0; 280 281 memset(tag, 0, sizeof(tag)); 282 if (!TEST_ptr(cipher) 283 || !TEST_int_gt((key_size = EVP_CIPHER_key_length(cipher)), 0) 284 || !TEST_int_gt((iv_size = EVP_CIPHER_iv_length(cipher)), 0) 285 || !TEST_ptr(mem = BIO_new(BIO_s_mem())) 286 || !TEST_ptr(b64 = BIO_new(BIO_f_base64())) 287 || !TEST_ptr(cbio = BIO_new(BIO_f_cipher())) 288 || !TEST_ptr(BIO_push(b64, mem)) 289 || !TEST_ptr(BIO_push(cbio, b64)) 290 || !TEST_int_gt(BIO_get_cipher_ctx(cbio, &ctx), 0) 291 || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, KEY, IV, ENCRYPT)) 292 || !TEST_int_gt(BIO_write(cbio, pbuf, sizeof(pbuf) - 1), 0) 293 || !TEST_int_gt(BIO_flush(cbio), 0) 294 || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 295 sizeof(tag), tag), 0)) 296 goto end; 297 BIO_free(cbio); 298 BIO_free(b64); 299 b64 = cbio = NULL; 300 301 BIO_set_mem_eof_return(mem, 0); 302 BIO_set_flags(mem, BIO_FLAGS_NONCLEAR_RST); 303 if (!TEST_int_gt(BIO_reset(mem), 0) 304 || !TEST_ptr(b64 = BIO_new(BIO_f_base64())) 305 || !TEST_ptr(cbio = BIO_new(BIO_f_cipher())) 306 || !TEST_ptr(BIO_push(b64, mem)) 307 || !TEST_ptr(BIO_push(cbio, b64)) 308 || !TEST_int_gt(BIO_get_cipher_ctx(cbio, &ctx), 0) 309 || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, KEY, IV, DECRYPT)) 310 || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 311 sizeof(tag), tag), 0) 312 || !TEST_int_gt((n = BIO_read(cbio, cbuf, sizeof(cbuf))), 0) 313 || !TEST_true(BIO_get_cipher_status(cbio)) 314 /* Evaluate both and report whether either or both failed */ 315 || (!TEST_int_gt(BIO_flush(cbio), 0) + 316 !TEST_true(BIO_get_cipher_status(cbio))) 317 || !TEST_mem_eq(cbuf, n, pbuf, sizeof(pbuf) - 1)) 318 goto end; 319 320 ret = 1; 321 322 end: 323 BIO_free(cbio); 324 BIO_free(b64); 325 BIO_free(mem); 326 return ret; 327 } 328 329 int setup_tests(void) 330 { 331 ADD_ALL_TESTS(test_bio_enc_aes_128_cbc, 2); 332 ADD_ALL_TESTS(test_bio_enc_aes_128_ctr, 2); 333 ADD_ALL_TESTS(test_bio_enc_aes_256_cfb, 2); 334 ADD_ALL_TESTS(test_bio_enc_aes_256_ofb, 2); 335 # ifndef OPENSSL_NO_CHACHA 336 ADD_ALL_TESTS(test_bio_enc_chacha20, 2); 337 # ifndef OPENSSL_NO_POLY1305 338 ADD_ALL_TESTS(test_bio_enc_chacha20_poly1305, 2); 339 # endif 340 # endif 341 ADD_TEST(test_bio_enc_eof_read_flush); 342 return 1; 343 } 344