Skip to content

Commit 52d9455

Browse files
committed
Fix IV handling for consecutive AES CBC calls
1 parent 951f26b commit 52d9455

5 files changed

Lines changed: 171 additions & 2 deletions

File tree

scripts/env-setup

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ if [ $is_sourced -eq 0 ]; then
1313
exit 1
1414
fi
1515

16+
17+
if [ -n "$BASH_SOURCE" ]; then
18+
SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
19+
elif [ -n "$ZSH_VERSION" ]; then
20+
SCRIPT_DIR=$(dirname "${(%):-%x}")
21+
else
22+
echo "Unsupported shell"
23+
exit 1
24+
fi
25+
1626
SCRIPT_DIR="$(cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P)"
1727
pushd $SCRIPT_DIR
1828
REPO_ROOT="${GITHUB_WORKSPACE:-$(git rev-parse --show-toplevel)}"
@@ -56,4 +66,4 @@ else
5666
return 1
5767
fi
5868

59-
echo "Done!\n"
69+
echo "Done!"

src/wp_aes_block.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,9 @@ static int wp_aes_block_init(wp_AesBlockCtx *ctx, const unsigned char *key,
308308
#endif
309309
#ifdef WP_HAVE_AESCBC
310310
if (ok && (iv == NULL) && ctx->ivSet && (ctx->mode == EVP_CIPH_CBC_MODE)) {
311-
XMEMCPY(ctx->iv, ctx->oiv, ctx->ivLen);
311+
if (!wp_aes_init_iv(ctx, ctx->oiv, ctx->ivLen)) {
312+
ok = 0;
313+
}
312314
}
313315
#else
314316
(void)ivLen;

test/test_cipher.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,3 +1172,158 @@ int test_aes256_cts(void *data)
11721172

11731173
#endif /* WP_HAVE_AESCTS */
11741174

1175+
#ifdef WP_HAVE_AESCBC
1176+
1177+
int test_aes256_cbc_multiple(void *data)
1178+
{
1179+
/* Test vector from libmemcached/libhashkit */
1180+
static const unsigned char key_data[] = {
1181+
0x5f, 0x5f, 0x5f, 0x5f, 0x43, 0x5f, 0x41, 0x5f,
1182+
0x54, 0x5f, 0x43, 0x5f, 0x48, 0x5f, 0x5f, 0x5f,
1183+
0x5f, 0x54, 0x5f, 0x45, 0x5f, 0x53, 0x5f, 0x54,
1184+
0x5f, 0x5f, 0x5f, 0x5f, 0x30, 0x00, 0x00, 0x00
1185+
};
1186+
1187+
static const unsigned char plain_text[] = {
1188+
0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64,
1189+
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20,
1190+
0x74, 0x68, 0x69, 0x63, 0x68, 0x20, 0x69, 0x73,
1191+
0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x20,
1192+
0x74, 0x68, 0x61, 0x6e, 0x20, 0x41, 0x45, 0x53,
1193+
0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x53,
1194+
0x49, 0x5a, 0x45
1195+
};
1196+
static const int plain_text_len = sizeof(plain_text);
1197+
1198+
static const unsigned char aes_iv[] = {
1199+
0x44, 0x63, 0xff, 0xd3, 0x79, 0xcf, 0x04, 0x74,
1200+
0x9e, 0x75, 0xa2, 0x71, 0xa4, 0x2c, 0xc7, 0x0a
1201+
};
1202+
1203+
static const unsigned char ciphertext_exp[] = {
1204+
0x75, 0xdd, 0x24, 0xf5, 0xc1, 0x5c, 0x34, 0x65,
1205+
0xaf, 0xd3, 0xa9, 0x82, 0x74, 0xe2, 0xf3, 0xa1,
1206+
0x35, 0x95, 0x5a, 0x89, 0x6f, 0x59, 0xb9, 0xa2,
1207+
0x84, 0xec, 0xa8, 0x54, 0x9f, 0xcc, 0x6d, 0xe3,
1208+
0x99, 0xfc, 0xf0, 0xa3, 0xc4, 0x03, 0xc3, 0x56,
1209+
0xec, 0x6d, 0x1c, 0xcd, 0xe1, 0xc2, 0x17, 0xa0,
1210+
0x51, 0x0b, 0x00, 0x87, 0xde, 0x43, 0x8a, 0xf6,
1211+
0x1b, 0x03, 0x2c, 0x7f, 0x68, 0x67, 0x11, 0x72
1212+
};
1213+
1214+
(void)data;
1215+
int err = 0;
1216+
1217+
EVP_CIPHER_CTX *ctx_enc = NULL;
1218+
EVP_CIPHER_CTX *ctx_dec = NULL;
1219+
1220+
if (err == 0) {
1221+
ctx_enc = EVP_CIPHER_CTX_new();
1222+
ctx_dec = EVP_CIPHER_CTX_new();
1223+
if (ctx_dec == NULL || ctx_enc == NULL) {
1224+
PRINT_MSG("EVP_CIPHER_CTX_new failed");
1225+
err = 1;
1226+
}
1227+
else {
1228+
PRINT_MSG("CTXs created");
1229+
}
1230+
}
1231+
1232+
if (err == 0) {
1233+
if (EVP_EncryptInit_ex(ctx_enc, EVP_aes_256_cbc(), NULL, key_data, aes_iv) != 1
1234+
|| EVP_DecryptInit_ex(ctx_dec, EVP_aes_256_cbc(), NULL, key_data, aes_iv) != 1) {
1235+
PRINT_MSG("EVP_EncryptInit_ex or EVP_DecryptInit_ex failed");
1236+
err = 1;
1237+
}
1238+
else {
1239+
PRINT_MSG("EVP_EncryptInit_ex and EVP_DecryptInit_ex succeeded");
1240+
}
1241+
}
1242+
1243+
/* Test that we can encrypt and decrypt multiple times without creating
1244+
* a new context. We should get the same result each time: same ciphertext
1245+
* when encrypting and same plaintext when decrypting. */
1246+
for (int i = 0; i < 8; i++) {
1247+
int cipher_text_len = plain_text_len + EVP_CIPHER_CTX_block_size(ctx_enc);
1248+
int decrypted_text_len = 0;
1249+
int final_len = 0;
1250+
unsigned char* cipher_text = malloc(cipher_text_len);
1251+
unsigned char* decrypted_text = malloc(plain_text_len);
1252+
1253+
PRINT_MSG("Test iteration: %d", i);
1254+
1255+
if (cipher_text == NULL || decrypted_text == NULL) {
1256+
PRINT_MSG("Memory allocation failed");
1257+
err = 1;
1258+
}
1259+
1260+
if (err == 0) {
1261+
if (EVP_EncryptInit_ex(ctx_enc, NULL, NULL, NULL, NULL) != 1
1262+
|| EVP_EncryptUpdate(ctx_enc, cipher_text, &cipher_text_len, plain_text, plain_text_len) != 1
1263+
|| EVP_EncryptFinal_ex(ctx_enc, cipher_text + cipher_text_len, &final_len) != 1) {
1264+
PRINT_MSG("Encrypt failed");
1265+
err = 1;
1266+
}
1267+
else {
1268+
cipher_text_len += final_len;
1269+
PRINT_BUFFER("Plain text ", plain_text, plain_text_len);
1270+
PRINT_BUFFER("Cipher text ", cipher_text, cipher_text_len);
1271+
}
1272+
}
1273+
1274+
if (err == 0) {
1275+
if (cipher_text_len != sizeof(ciphertext_exp)) {
1276+
PRINT_MSG("Cipher text length does not match expected value");
1277+
err = 1;
1278+
}
1279+
}
1280+
1281+
if (err == 0) {
1282+
if (memcmp(cipher_text, ciphertext_exp, sizeof(ciphertext_exp)) != 0) {
1283+
PRINT_MSG("Cipher text does not match expected value");
1284+
err = 1;
1285+
} else {
1286+
PRINT_MSG("Cipher text matches expected value");
1287+
}
1288+
}
1289+
1290+
if (err == 0) {
1291+
if (EVP_DecryptInit_ex(ctx_dec, NULL, NULL, NULL, NULL) != 1
1292+
|| EVP_DecryptUpdate(ctx_dec, decrypted_text, &decrypted_text_len, cipher_text, cipher_text_len) != 1
1293+
|| EVP_DecryptFinal_ex(ctx_dec, decrypted_text + decrypted_text_len, &final_len) != 1) {
1294+
PRINT_MSG("Decrypt failed");
1295+
err = 1;
1296+
}
1297+
else {
1298+
decrypted_text_len += final_len;
1299+
PRINT_BUFFER("Decrypted text", decrypted_text, decrypted_text_len);
1300+
}
1301+
}
1302+
1303+
if (err == 0) {
1304+
if (plain_text_len != decrypted_text_len) {
1305+
PRINT_MSG("Decrypted text length does not match original");
1306+
err = 1;
1307+
}
1308+
}
1309+
1310+
if (err == 0) {
1311+
int res = memcmp(plain_text, decrypted_text, plain_text_len);
1312+
if (res != 0) {
1313+
PRINT_MSG("Decrypted text does not match original");
1314+
err = 1;
1315+
} else {
1316+
PRINT_MSG("Cipher test passed successfully");
1317+
}
1318+
}
1319+
1320+
free(cipher_text);
1321+
free(decrypted_text);
1322+
}
1323+
1324+
EVP_CIPHER_CTX_free(ctx_enc);
1325+
EVP_CIPHER_CTX_free(ctx_dec);
1326+
1327+
return err;
1328+
}
1329+
#endif /* WP_HAVE_AESCBC */

test/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ TEST_CASE test_case[] = {
118118
TEST_DECL(test_aes128_cbc_stream, NULL),
119119
TEST_DECL(test_aes192_cbc_stream, NULL),
120120
TEST_DECL(test_aes256_cbc_stream, NULL),
121+
TEST_DECL(test_aes256_cbc_multiple, NULL),
121122
#endif
122123
#ifdef WP_HAVE_AESCTR
123124
TEST_DECL(test_aes128_ctr_stream, NULL),

test/unit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ int test_aes256_cbc(void *data);
156156
int test_aes128_cbc_stream(void *data);
157157
int test_aes192_cbc_stream(void *data);
158158
int test_aes256_cbc_stream(void *data);
159+
int test_aes256_cbc_multiple(void *data);
159160

160161
#endif
161162

0 commit comments

Comments
 (0)