/* Copyright (c) (2014-2016,2018-2020) Apple Inc. All rights reserved. * * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which * is contained in the License.txt file distributed with corecrypto) and only to * people who accept that license. IMPORTANT: Any license rights granted to you by * Apple Inc. (if any) are limited to internal use within your organization only on * devices and computers you own or control, for the sole purpose of verifying the * security characteristics and correct functioning of the Apple Software. You may * not, directly or indirectly, redistribute the Apple Software or any portions thereof. */ #include "testmore.h" #include "testbyteBuffer.h" #include "cc_debug.h" #include #include #include #include #include #include #include #include "ccconstanttime.h" #if (CCPAD == 0) entryPoint(ccpad_tests,"ccpad") #else #include "crypto_test_modes.h" #include "ccsymmetric_pad.h" static const int kTestTestCount = 1205; static const int verbose=0; #include #include "cccycles.h" #include "ccstats.h" //====================================================================== // Constant time verification parameters //====================================================================== // Number of iteration of test where timings are not taken into account. // Made to reach a stable performance state #define CCPAD_WARMUP 0 // Each sample is the average time for many iteration with identical inputs #define CCPAD_TIMING_REPEAT 150 // Number of sample for the statistical analysis // typically 100~1000 is a good range #define CCPAD_TIMING_SAMPLES 200 // In case of failure, try many times // This is to reduce false positives due to noise/timing accuracy. // If implementation is not constant time, the behavior will be consistent // So that this does not reduce the detection power. #define CCPAD_TIMING_RETRIES 10 // Two statitical tools are available: T-test and Wilcoxon. // T-test assumes that the distribution to be compared are normal // Wilcoxon measure offset between distribution. // Due to potential switches between performance state or occasional // latencies, Wilcoxon is recommended. // > Set to 1 to use T-test instead of Wilcoxon #define T_TEST 1 // Number of iteration of the full test (to play with to evaluate chances of false positives) #define CMP_TIMING_TEST_ITERATION 1 // Quantile for the repeated timing. Empirical value. #define CCPAD_PERCENTILE 9 //====================================================================== // Local types typedef struct { ccpad_select padding_mode; char *keyStr; char *init_ivStr; char *ptStr; char *outputStr; } ccpad_test_vector_t; static int ccsymmetric_pad_ciphertext_tests(duplex_cryptor cryptor, const ccpad_test_vector_t *test); static int ccsymmetric_pad_plaintext_tests(duplex_cryptor cryptor, ccpad_select padding_mode, const ccpad_test_vector_t *test); static int ccsymmetric_pad_roundtrip_tests(duplex_cryptor cryptor, ccpad_select padding_mode, size_t message_size); // Test vectors // These are stock keys/IVs/blocks to encode - don't change them - add if you #define keystr64 "0001020304050607" #define keystr128 "000102030405060708090a0b0c0d0e0f" #define ivstr64 "0f0e0d0c0b0a0908" #define ivstr128 "0f0e0d0c0b0a09080706050403020100" #define MSG_01 "00" #define MSG_02 "0000" #define MSG_03 "000000" #define MSG_04 "00000000" #define MSG_05 "0000000000" #define MSG_06 "000000000000" #define MSG_07 "00000000000000" #define MSG_08 "0000000000000000" #define MSG_09 "000000000000000000" #define MSG_10 "00000000000000000000" #define MSG_11 "0000000000000000000000" #define MSG_12 "000000000000000000000000" #define MSG_13 "00000000000000000000000000" #define MSG_14 "0000000000000000000000000000" #define MSG_15 "000000000000000000000000000000" #define MSG_16 "00000000000000000000000000000000" #define MSG_17 "0000000000000000000000000000000000" #define MSG_18 "000000000000000000000000000000000000" #define MSG_19 "00000000000000000000000000000000000000" #define MSG_20 "0000000000000000000000000000000000000000" #define MSG_21 "000000000000000000000000000000000000000000" #define MSG_22 "00000000000000000000000000000000000000000000" #define MSG_23 "0000000000000000000000000000000000000000000000" #define MSG_24 "000000000000000000000000000000000000000000000000" #define MSG_25 "00000000000000000000000000000000000000000000000000" #define MSG_26 "0000000000000000000000000000000000000000000000000000" #define MSG_27 "000000000000000000000000000000000000000000000000000000" #define MSG_28 "00000000000000000000000000000000000000000000000000000000" #define MSG_29 "0000000000000000000000000000000000000000000000000000000000" #define MSG_30 "000000000000000000000000000000000000000000000000000000000000" #define MSG_31 "00000000000000000000000000000000000000000000000000000000000000" #define MSG_32 "0000000000000000000000000000000000000000000000000000000000000000" #define PAD_16 "10101010101010101010101010101010" #define PAD_15 "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f" #define PAD_14 "0e0e0e0e0e0e0e0e0e0e0e0e0e0e" #define PAD_13 "0d0d0d0d0d0d0d0d0d0d0d0d0d" #define PAD_12 "0c0c0c0c0c0c0c0c0c0c0c0c" #define PAD_11 "0b0b0b0b0b0b0b0b0b0b0b" #define PAD_10 "0a0a0a0a0a0a0a0a0a0a" #define PAD_09 "090909090909090909" #define PAD_08 "0808080808080808" #define PAD_07 "07070707070707" #define PAD_06 "060606060606" #define PAD_05 "0505050505" #define PAD_04 "04040404" #define PAD_03 "030303" #define PAD_02 "0202" #define PAD_01 "01" #define END_VECTOR {0, NULL, NULL, NULL, NULL} static const ccpad_test_vector_t aes_plaintext_vectors[] = { {ccpad_pkcs7,keystr128,ivstr128, MSG_01, PAD_15}, {ccpad_pkcs7,keystr128,ivstr128, MSG_02, PAD_14}, {ccpad_pkcs7,keystr128,ivstr128, MSG_03, PAD_13}, {ccpad_pkcs7,keystr128,ivstr128, MSG_04, PAD_12}, {ccpad_pkcs7,keystr128,ivstr128, MSG_05, PAD_11}, {ccpad_pkcs7,keystr128,ivstr128, MSG_06, PAD_10}, {ccpad_pkcs7,keystr128,ivstr128, MSG_07, PAD_09}, {ccpad_pkcs7,keystr128,ivstr128, MSG_08, PAD_08}, {ccpad_pkcs7,keystr128,ivstr128, MSG_09, PAD_07}, {ccpad_pkcs7,keystr128,ivstr128, MSG_10, PAD_06}, {ccpad_pkcs7,keystr128,ivstr128, MSG_11, PAD_05}, {ccpad_pkcs7,keystr128,ivstr128, MSG_12, PAD_04}, {ccpad_pkcs7,keystr128,ivstr128, MSG_13, PAD_03}, {ccpad_pkcs7,keystr128,ivstr128, MSG_14, PAD_02}, {ccpad_pkcs7,keystr128,ivstr128, MSG_15, PAD_01}, {ccpad_pkcs7,keystr128,ivstr128, MSG_16, PAD_16}, {ccpad_pkcs7,keystr128,ivstr128, MSG_17, PAD_15}, {ccpad_pkcs7,keystr128,ivstr128, MSG_18, PAD_14}, {ccpad_pkcs7,keystr128,ivstr128, MSG_19, PAD_13}, {ccpad_pkcs7,keystr128,ivstr128, MSG_20, PAD_12}, {ccpad_pkcs7,keystr128,ivstr128, MSG_21, PAD_11}, {ccpad_pkcs7,keystr128,ivstr128, MSG_22, PAD_10}, {ccpad_pkcs7,keystr128,ivstr128, MSG_23, PAD_09}, {ccpad_pkcs7,keystr128,ivstr128, MSG_24, PAD_08}, {ccpad_pkcs7,keystr128,ivstr128, MSG_25, PAD_07}, {ccpad_pkcs7,keystr128,ivstr128, MSG_26, PAD_06}, {ccpad_pkcs7,keystr128,ivstr128, MSG_27, PAD_05}, {ccpad_pkcs7,keystr128,ivstr128, MSG_28, PAD_04}, {ccpad_pkcs7,keystr128,ivstr128, MSG_29, PAD_03}, {ccpad_pkcs7,keystr128,ivstr128, MSG_30, PAD_02}, {ccpad_pkcs7,keystr128,ivstr128, MSG_31, PAD_01}, {ccpad_pkcs7,keystr128,ivstr128, MSG_32, PAD_16}, END_VECTOR }; static const ccpad_test_vector_t des_plaintext_vectors[] = { {ccpad_pkcs7,keystr64, ivstr64, MSG_01, PAD_07}, {ccpad_pkcs7,keystr64, ivstr64, MSG_02, PAD_06}, {ccpad_pkcs7,keystr64, ivstr64, MSG_03, PAD_05}, {ccpad_pkcs7,keystr64, ivstr64, MSG_04, PAD_04}, {ccpad_pkcs7,keystr64, ivstr64, MSG_05, PAD_03}, {ccpad_pkcs7,keystr64, ivstr64, MSG_06, PAD_02}, {ccpad_pkcs7,keystr64, ivstr64, MSG_07, PAD_01}, {ccpad_pkcs7,keystr64, ivstr64, MSG_08, PAD_08}, {ccpad_pkcs7,keystr64, ivstr64, MSG_09, PAD_07}, {ccpad_pkcs7,keystr64, ivstr64, MSG_10, PAD_06}, {ccpad_pkcs7,keystr64, ivstr64, MSG_11, PAD_05}, {ccpad_pkcs7,keystr64, ivstr64, MSG_12, PAD_04}, {ccpad_pkcs7,keystr64, ivstr64, MSG_13, PAD_03}, {ccpad_pkcs7,keystr64, ivstr64, MSG_14, PAD_02}, {ccpad_pkcs7,keystr64, ivstr64, MSG_15, PAD_01}, {ccpad_pkcs7,keystr64, ivstr64, MSG_16, PAD_08}, END_VECTOR }; #define keystr128_cts "636869636b656e207465726979616b69" #define ivstr128_cts "0f0e0d0c0b0a09080706050403020100" #define zeroX16 "00000000000000000000000000000000" static const ccpad_test_vector_t aes_cbc_ciphertext_vectors[] = { {ccpad_pkcs7, "badfd2102e1e180a634204249c5a6933", "84c06c16c151007ca9ed9bb926e66eec", "fb58510beb65062c525a3de42d934d4b4ec433d600a1467142751886a10e7bf96f236c196d12dcf0698e09efc79a4bea072bc0830da8886674cf6174206cca2d4e9e543f0016ec4dcc602ffd0a417c722879e259497f89aee5ad99a4f65887058242250fbe44f61eab5e668adbb780a4cba97393f6ff152c13c39b57ed727bb94cf19d1b4a55f45cceb22b6c4f26f736d20a48cb6230578591c8d33d72b778d30b304818b20d918ef654cabeae1038f2a0db5170d2b4df38c6efc887bc1f837fba34e97daf8920414b748a909ad5ef56fb47fa53c680aae808f3e6065689339728251e18cd264f5385c969f87104099563a411cfe681d19134e9479e059d09b69f5010912291d0232f733a2688b3042ec4e82ce5163c384ee54a9f10e48a8ab46fd7147351dd8514bda5d8c4ce8babcc3ef82dbf44799fc59e37d8f3c99506d2168c84d8381f4f9a84cbce7bd0bb4bbbcdef0c626356d3ca126c8776e3a291881af518e23dbd067016c5898bed5f64d6e8f8acefba83f92b0c318ec7b905165fb6b81bc60528c0a0e3db38ab1ee6f37e56dbf270c0751674e0ddb1a6076d8f78084ce31f0d3673e638e0110575b16d9d9f151c1b9aca8d15d7a8111c0de5acf5ae3b307e8064c90329e421e3434a1ecd253b153447c21c79c9946666dae444c49a31b1f94da603a8377168dc4f874e98fff5ae89dd35d44e89df5748223b7a24", "4b52b5e85aecaaaf886bd9e8805390c62e12e13357e4beb3b713e37d217c6f7a9e432a04f87bd8a4dd0ef79eb7bf41b5a2a27e63361d7cb7af7b3c9a8f0b56ae27dc9cfd6c10eb1a79c7be35d31c3965b8e7099775f7644029bd79321f5dd12c55280a30fabd1b95e27c2d4dec6ca4d8716f36e7abe3408f5120560b573e5495ae7aad668fa84d6a8a1156c231a5b6d983ece3e27d199a806dc629c1a60c08ccb0e4807d9fed88f28ce0f59583708f540f97110b2620b1679220abe13e3c4b727186b289794583b20154ce9a07a284df3e63572f462142cae8949d7dd6f2b26fb90d556ec75e93dd33b59d697883312af89e52945b9baedfebe28759cdba4dfbf6e6f201b087478642cf0b34f983593c68947e4ee05bd17716e6cfb7c74c876c0ba650f3979f5eceb72a71d0d46aac4474ae2048d2a9884aa12e292950c77b17de11e8d3e895e60b1c584b1c8d9edd40ba7917e396d1d3bfd1941923aa40213195e8b8f7f4d5ae1057cbecdf89c8959745d1fcece59115819dc661e7b097c132e8f98720a57a83469cb82c374fdebc97badd7cef8d160a7f27d50f35b7e4af6f1b78361828e32a55b25fd56efbc12f8fcb7e2e4f882afa0c7747a455a1fae00a561cbb878e01b32fafb23f397371a8b3441c8da654b902d8489383542188821859a44f0fb2b63a49835f8ba5f0231ff0f8f5fc3d5c812331b11e39bc03394e2875313166ac5f77e4900146c6faafba81"}, {ccpad_cts1, keystr128_cts, zeroX16, "4920776f756c64206c696b652074686520", "97c6353568f2bf8cb4d8a580362da7ff7f"}, {ccpad_cts1, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320", "97687268d6ecccc0c07b25e25ecfe5fc00783e0efdb2c1d445d4c8eff7ed22"}, {ccpad_cts1, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c2047617527732043", "97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a8"}, {ccpad_cts1, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c", "97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5b3fffd940c16a18c1b5549d2f838029e"}, {ccpad_cts1, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20", "97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a89dad8bbb96c4cdc03bc103e1a194bbd8"}, {ccpad_cts1, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e", "97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a89dad8bbb96c4cdc03bc103e1a194bbd84807efe836ee89a526730dbc2f7bc840"}, {ccpad_cts1, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee2dc88b70f6ae0243d2dbcd6822a1058604b1c432a7a71395b36d820e2c3de4ee"}, {ccpad_cts1, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee2dc88b70f6ae0243d2dbcd6822a105950b6576660739916d058623d688e27e"}, {ccpad_cts1, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee2dc88b70f6ae0243d2db751002ef7a0f9d915d15346571eee7aa"}, // Test vectors from CommonCrypto {ccpad_cts2, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee2dc88b70f6ae0243d2dbcd6822a1058604b1c432a7a71395b36d820e2c3de4ee"}, {ccpad_cts2, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee950b6576660739916d058623d688e27e2dc88b70f6ae0243d2dbcd6822a105"}, {ccpad_cts2, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee751002ef7a0f9d915d15346571eee7aa2dc88b70f6ae0243d2db"}, // Test vectors from RFC3962 {ccpad_cts3, keystr128_cts, zeroX16, "4920776f756c64206c696b652074686520", "c6353568f2bf8cb4d8a580362da7ff7f97"}, {ccpad_cts3, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320", "fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5"}, {ccpad_cts3, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c2047617527732043", "39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584"}, {ccpad_cts3, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c", "97687268d6ecccc0c07b25e25ecfe584b3fffd940c16a18c1b5549d2f838029e39312523a78662d5be7fcbcc98ebf5"}, {ccpad_cts3, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20", "97687268d6ecccc0c07b25e25ecfe5849dad8bbb96c4cdc03bc103e1a194bbd839312523a78662d5be7fcbcc98ebf5a8"}, {ccpad_cts3, keystr128_cts, zeroX16, "4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e", "97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a84807efe836ee89a526730dbc2f7bc8409dad8bbb96c4cdc03bc103e1a194bbd8"}, // Test vectors from CommonCrypto {ccpad_cts3, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee04b1c432a7a71395b36d820e2c3de4ee2dc88b70f6ae0243d2dbcd6822a10586"}, {ccpad_cts3, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee950b6576660739916d058623d688e27e2dc88b70f6ae0243d2dbcd6822a105"}, {ccpad_cts3, keystr128_cts, ivstr128_cts, "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", "e22abba9d2a201b18dc2f57e04aba21a16e0ed6358164c59ca64d204f33247ee751002ef7a0f9d915d15346571eee7aa2dc88b70f6ae0243d2db"}, END_VECTOR }; // Compare the padded plaintext with what is expected static int ccsymmetric_pad_plaintext_tests(duplex_cryptor cryptor, ccpad_select padding_mode, const ccpad_test_vector_t *test) { // Retrieve test case info byteBuffer key = hexStringToBytes(test->keyStr); byteBuffer init_iv = hexStringToBytes(test->init_ivStr); byteBuffer message = hexStringToBytes(test->ptStr); byteBuffer expected_padding = hexStringToBytes(test->outputStr); size_t len = message->len; size_t result_len; size_t block_size=0; size_t padded_len=0; byteBuffer ciphertext,padded_message; // Set cipher cc_ciphermode_descriptor_s encrypt_desc; cc_ciphermode_descriptor_s decrypt_desc; encrypt_desc.cipher = cryptor->cipher; encrypt_desc.mode = cryptor->mode; encrypt_desc.direction = cc_Encrypt; encrypt_desc.ciphermode = cryptor->encrypt_ciphermode; decrypt_desc.cipher = cryptor->cipher; decrypt_desc.mode = cryptor->mode; decrypt_desc.direction = cc_Decrypt; decrypt_desc.ciphermode = cryptor->decrypt_ciphermode; block_size=cc_symmetric_bloc_size(&encrypt_desc); padded_len=(len+block_size) & (~(block_size-1)); // Assumes block size is a power of 2. MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc); MAKE_GENERIC_MODE_CONTEXT(decrypt_ctx, &decrypt_desc); ok_or_fail((cc_symmetric_setup(&encrypt_desc, key->bytes, key->len, init_iv->bytes, encrypt_ctx) == 0), "Encrypted cipher-mode is initted"); ok_or_fail((cc_symmetric_setup(&decrypt_desc, key->bytes, key->len, init_iv->bytes, decrypt_ctx) == 0), "Decrypted cipher-mode is initted"); // Temporary buffers ciphertext = mallocByteBuffer(padded_len); padded_message = mallocByteBuffer(padded_len); //---------------------------------- // 1. Test padding encryption //---------------------------------- // a. Encrypt using padding function result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) encrypt_ctx,padding_mode, init_iv->bytes, message->bytes, ciphertext->bytes, len); ok_or_fail(result_len >= len, "Encryption with padding failed"); // b. Decrypt raw data cc_symmetric_crypt((cc_symmetric_context_p) decrypt_ctx, init_iv->bytes, ciphertext->bytes, padded_message->bytes, result_len); // c. Compare last block with expected value ok_memcmp_or_fail(&padded_message->bytes[result_len-expected_padding->len], expected_padding->bytes, expected_padding->len, "Padding as expected"); //---------------------------------- // 2. Test padding decryption //---------------------------------- // a. Construct the good padded zero message memcpy(padded_message->bytes,message->bytes, len); memcpy(&padded_message->bytes[len],expected_padding->bytes,expected_padding->len); // b. Encrypt with proper padding cc_symmetric_crypt((cc_symmetric_context_p) encrypt_ctx, init_iv->bytes, padded_message->bytes, ciphertext->bytes, len+expected_padding->len); memset(padded_message->bytes,0xff,padded_len); // Clean buffer to catch mismatches below // b. Decrypt with padding decrypt function result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) decrypt_ctx,padding_mode, init_iv->bytes, ciphertext->bytes, padded_message->bytes,len+expected_padding->len); ok_or_fail(result_len <= len+expected_padding->len, "Decryption with padding failed"); // c. Compare that the message is all there. ok_memcmp_or_fail(padded_message->bytes, message->bytes, len, "Decrypted handcrafted padding"); ok_or_fail(len == result_len, "Decrypted length from handcrafted padding"); free(ciphertext); free(padded_message); free(key); free(init_iv); free(message); free(expected_padding); return 1; } // Compare the ciphertext with what is expected static int ccsymmetric_pad_ciphertext_tests(duplex_cryptor cryptor, const ccpad_test_vector_t *test) { // Retrieve test case info byteBuffer key = hexStringToBytes(test->keyStr); byteBuffer init_iv = hexStringToBytes(test->init_ivStr); byteBuffer plaintext = hexStringToBytes(test->ptStr); byteBuffer expected_ciphertext = hexStringToBytes(test->outputStr); ccpad_select padding_mode=test->padding_mode; size_t len = plaintext->len; size_t result_len; byteBuffer computed_ciphertext,recomputed_plaintext; // Set cipher cc_ciphermode_descriptor_s encrypt_desc; cc_ciphermode_descriptor_s decrypt_desc; encrypt_desc.cipher = cryptor->cipher; encrypt_desc.mode = cryptor->mode; encrypt_desc.direction = cc_Encrypt; encrypt_desc.ciphermode = cryptor->encrypt_ciphermode; decrypt_desc.cipher = cryptor->cipher; decrypt_desc.mode = cryptor->mode; decrypt_desc.direction = cc_Decrypt; decrypt_desc.ciphermode = cryptor->decrypt_ciphermode; MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc); MAKE_GENERIC_MODE_CONTEXT(decrypt_ctx, &decrypt_desc); ok_or_fail((cc_symmetric_setup(&encrypt_desc, key->bytes, key->len, init_iv->bytes, encrypt_ctx) == 0), "Encrypted cipher-mode is initted"); ok_or_fail((cc_symmetric_setup(&decrypt_desc, key->bytes, key->len, init_iv->bytes, decrypt_ctx) == 0), "Decrypted cipher-mode is initted"); // Temporary buffers computed_ciphertext = mallocByteBuffer(expected_ciphertext->len); recomputed_plaintext = mallocByteBuffer(expected_ciphertext->len ); //---------------------------------- // Round Trip, out of place //---------------------------------- // a. Encrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) encrypt_ctx,padding_mode, init_iv->bytes, plaintext->bytes, computed_ciphertext->bytes, len); ok_or_fail(result_len == expected_ciphertext->len, "Ciphertext length mismatch"); ok_memcmp_or_fail(computed_ciphertext->bytes, expected_ciphertext->bytes, expected_ciphertext->len, "Wrong ciphertext"); // b. Decrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) decrypt_ctx,padding_mode, init_iv->bytes, expected_ciphertext->bytes, recomputed_plaintext->bytes, expected_ciphertext->len); ok_or_fail(result_len == plaintext->len, "Recovered plaintext length mismatch"); ok_memcmp_or_fail(recomputed_plaintext->bytes, plaintext->bytes, plaintext->len, "Wrong decrypted message"); //---------------------------------- // Round Trip, in place //---------------------------------- memcpy(computed_ciphertext->bytes,plaintext->bytes,len); // a. Encrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) encrypt_ctx,padding_mode, init_iv->bytes, computed_ciphertext->bytes, computed_ciphertext->bytes, len); ok_or_fail(result_len == expected_ciphertext->len, "Ciphertext computed in place length mismatch"); ok_memcmp_or_fail(computed_ciphertext->bytes, expected_ciphertext->bytes, expected_ciphertext->len, "Wrong ciphertext in place"); // b. Decrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) decrypt_ctx,padding_mode, init_iv->bytes, computed_ciphertext->bytes, computed_ciphertext->bytes, result_len); ok_or_fail(result_len == plaintext->len, "Recovered plaintext length mismatch"); // c. Compare with original messsage ok_memcmp_or_fail(computed_ciphertext->bytes, plaintext->bytes, len, "Recovered in place plaintext length mismatch"); //---------------------------------- free(recomputed_plaintext); free(plaintext); free(computed_ciphertext); free(expected_ciphertext); free(key); free(init_iv); return 1; } // Roundtrip: does the encrypt/decrypt recover the plaintext. static int ccsymmetric_pad_roundtrip_tests(duplex_cryptor cryptor, ccpad_select padding_mode, size_t message_size) { // Retrieve test case info byteBuffer key; byteBuffer init_iv; byteBuffer message; size_t len = message_size; size_t result_len; size_t block_size=0; size_t padded_len=0; int status; byteBuffer ciphertext,padded_message; // Set cipher cc_ciphermode_descriptor_s encrypt_desc; cc_ciphermode_descriptor_s decrypt_desc; encrypt_desc.cipher = cryptor->cipher; encrypt_desc.mode = cryptor->mode; encrypt_desc.direction = cc_Encrypt; encrypt_desc.ciphermode = cryptor->encrypt_ciphermode; decrypt_desc.cipher = cryptor->cipher; decrypt_desc.mode = cryptor->mode; decrypt_desc.direction = cc_Decrypt; decrypt_desc.ciphermode = cryptor->decrypt_ciphermode; block_size=cc_symmetric_bloc_size(&encrypt_desc); padded_len=(len+block_size) & (~(block_size-1)); // Assumes block size is a power of 2. key = mallocByteBuffer(block_size); status = ccrng_generate(global_test_rng, key->len, key->bytes); cc_assert(status == 0); (void)status; init_iv = mallocByteBuffer(block_size); status = ccrng_generate(global_test_rng, init_iv->len, init_iv->bytes); cc_assert(status == 0); (void)status; message = mallocByteBuffer(len); status = ccrng_generate(global_test_rng, message->len, message->bytes); cc_assert(status == 0); (void)status; MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc); MAKE_GENERIC_MODE_CONTEXT(decrypt_ctx, &decrypt_desc); ok_or_fail((cc_symmetric_setup(&encrypt_desc, key->bytes, key->len, init_iv->bytes, encrypt_ctx) == 0), "Encrypted cipher-mode is initted"); ok_or_fail((cc_symmetric_setup(&decrypt_desc, key->bytes, key->len, init_iv->bytes, decrypt_ctx) == 0), "Decrypted cipher-mode is initted"); // Temporary buffers ciphertext = mallocByteBuffer(padded_len); padded_message = mallocByteBuffer(padded_len); //---------------------------------- // Round Trip, out of place //---------------------------------- // a. Encrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) encrypt_ctx,padding_mode, init_iv->bytes, message->bytes, ciphertext->bytes, len); ok_or_fail(result_len >= len, "Encryption with padding failed"); // b. Decrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) decrypt_ctx,padding_mode, init_iv->bytes, ciphertext->bytes, padded_message->bytes, result_len); ok_or_fail(result_len <= len, "Decryption with padding failed"); // c. Compare with original messsage ok_memcmp_or_fail(padded_message->bytes, message->bytes, len, "Wrap/Unwrapped decrypted message"); ok_or_fail(message->len == result_len, "Wrap/Unwrapped decrypted length"); //---------------------------------- // Round Trip, in place //---------------------------------- // a. Encrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) encrypt_ctx,padding_mode, init_iv->bytes, padded_message->bytes, padded_message->bytes, len); ok_or_fail(result_len >= len, "Encryption in place failed"); // Makes sure the plaintext has been encrypted ok_or_fail(memcmp(padded_message->bytes,message->bytes,len)!=0, "Encryption in place did nothing?"); // b. Decrypt with padding result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) decrypt_ctx,padding_mode, init_iv->bytes, padded_message->bytes, padded_message->bytes, result_len); ok_or_fail(result_len <= len, "Decryption in place failed"); // c. Compare with original messsage ok_memcmp_or_fail(padded_message->bytes, message->bytes, len, "Wrap/Unwrapped in place decrypted message"); ok_or_fail(message->len == result_len, "Wrap/Unwrapped in place decrypted length"); //---------------------------------- free(ciphertext); free(padded_message); free(key); free(init_iv); free(message); return 1; } CC_UNUSED static int ccsymmetric_crypt_pad_timing_tests(duplex_cryptor cryptor, ccpad_select padding_mode, const ccpad_test_vector_t *test) { // Retrieve test case info // Message is ignore, random messages are generated byteBuffer key = hexStringToBytes(test->keyStr); byteBuffer init_iv = hexStringToBytes(test->init_ivStr); byteBuffer plaintext,output,ciphertext_valid,ciphertext_random; size_t len = 0; size_t max_len = 0; size_t result_len = 0; size_t block_size=0; size_t padded_len=0; int failure_cnt=0; int early_abort=1; uint32_t j,sample_counter; bool retry=true; // Random for messages struct ccrng_state *rng = global_test_rng; // Set cipher cc_ciphermode_descriptor_s encrypt_desc; cc_ciphermode_descriptor_s decrypt_desc; encrypt_desc.cipher = cryptor->cipher; encrypt_desc.mode = cryptor->mode; encrypt_desc.direction = cc_Encrypt; encrypt_desc.ciphermode = cryptor->encrypt_ciphermode; decrypt_desc.cipher = cryptor->cipher; decrypt_desc.mode = cryptor->mode; decrypt_desc.direction = cc_Decrypt; decrypt_desc.ciphermode = cryptor->decrypt_ciphermode; MAKE_GENERIC_MODE_CONTEXT(encrypt_ctx, &encrypt_desc); MAKE_GENERIC_MODE_CONTEXT(decrypt_ctx, &decrypt_desc); ok_or_fail((cc_symmetric_setup(&encrypt_desc, key->bytes, key->len, init_iv->bytes, encrypt_ctx) == 0), "Encrypted cipher-mode is initted"); ok_or_fail((cc_symmetric_setup(&decrypt_desc, key->bytes, key->len, init_iv->bytes, decrypt_ctx) == 0), "Decrypted cipher-mode is initted"); // Work on messages of size 0 < len <= blocksize block_size=cc_symmetric_bloc_size(&encrypt_desc); len=block_size; max_len=(len+block_size) & (~(block_size-1)); // Assumes block size is a power of 2. // Temporary buffers plaintext = mallocByteBuffer(max_len); ciphertext_valid = mallocByteBuffer(max_len); ciphertext_random = mallocByteBuffer(max_len); output = mallocByteBuffer(max_len); for (len=0; len<=block_size;len++) { j=0; while(retry) { sample_counter=0; // Index of current sample measurement_t timing_sample[2*CCPAD_TIMING_SAMPLES]; for (size_t i=0;i<2*CCPAD_TIMING_SAMPLES+(CCPAD_WARMUP/CCPAD_TIMING_REPEAT);i++) { padded_len=(len+block_size) & (~(block_size-1)); // Assumes block size is a power of 2. volatile size_t decode_result; if ((len==0) || ((i&1) == 0)) { // ------------------------- // Random // ------------------------- ccrng_generate(rng,padded_len,plaintext->bytes); // Full length cc_symmetric_crypt((cc_symmetric_context_p) encrypt_ctx, init_iv->bytes, plaintext->bytes, ciphertext_valid->bytes, padded_len); result_len=padded_len; } else { // ------------------------- // Correct padding // ------------------------- // Create message with good padding ccrng_generate(rng,len,plaintext->bytes); // Actual length result_len=cc_symmetric_crypt_pad((cc_symmetric_context_p) encrypt_ctx,padding_mode, init_iv->bytes, plaintext->bytes, ciphertext_valid->bytes, len); cc_assert(result_len == padded_len); } // Decrypt with padding decrypt function cc_symmetric_crypt((cc_symmetric_context_p) decrypt_ctx,init_iv->bytes, ciphertext_valid->bytes, output->bytes,result_len); TIMING_WITH_QUANTILE(timing_sample[sample_counter].timing, CCPAD_TIMING_REPEAT, CCPAD_PERCENTILE, decode_result=ccpad_pkcs7_decode(block_size,output->bytes+result_len-block_size),errOut); timing_sample[sample_counter].group=sample_counter&1; #if CCPAD_WARMUP if (i>=(CCPAD_WARMUP/CCPAD_TIMING_REPEAT)) #endif { sample_counter++; } } #if CCN_OSX if (verbose>1) { char file_name[64]; snprintf(file_name,sizeof(file_name),"corecrypto_test_timings_%.2zu.csv",len); export_measurement_to_file(file_name,timing_sample,sample_counter); } #endif // Process results #if T_TEST // T test int status=T_test_isRejected(timing_sample,sample_counter); #else // Wilcoxon Rank-Sum Test int status=WilcoxonRankSumTest(timing_sample,sample_counter); #endif if (status!=0) { j++; // retry counter if (j>=CCPAD_TIMING_RETRIES) { // If it fails for len==0 it's a test issue since it is all random if (len==0) { diag("Constant timing FAILED for all random, this is a test issue",len,j); } else { diag("Constant timing FAILED for len %d after %d attempts",len,j); //ok_or_fail((status==0),"Decrypt+padding constant timing"); failure_cnt++; } break; } } else { if ((verbose>1) && (j>0)) diag("Constant timing ok for len %d after %d attempts (of %d)",len,j+1,CCPAD_TIMING_RETRIES); break; } } // retry } early_abort=0; errOut: free(plaintext); free(ciphertext_valid); free(ciphertext_random); free(output); free(key); free(init_iv); if (failure_cnt || early_abort) { return 0; } return 1; } // For PKCS7 since it is special with regards to modes static int test_pad_plaintext_pkcs7(ciphermode_t encrypt_ciphermode, ciphermode_t decrypt_ciphermode,cc_cipher_select cipher,cc_mode_select mode) { duplex_cryptor_s cryptor; cryptor.cipher = cipher; cryptor.mode = mode; cryptor.encrypt_ciphermode = encrypt_ciphermode; cryptor.decrypt_ciphermode = decrypt_ciphermode; ccpad_select padding_mode=ccpad_pkcs7; const ccpad_test_vector_t *run_vector=NULL; if (cc_cipherAES==cryptor.cipher) { run_vector=aes_plaintext_vectors; } else if (cc_cipherDES==cryptor.cipher) { run_vector=des_plaintext_vectors; } else { fail("Test not implemented"); return 0; } // Detect timing attacks on PKCS7 padding if (cc_ModeECB!=cryptor.mode && padding_mode==ccpad_pkcs7) { // Timing attack not relevant on ECB for (int i=0;i