corecrypto/ccpad/crypto_test/crypto_test_pad.c

797 lines
39 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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 <corecrypto/ccaes.h>
#include <corecrypto/ccdes.h>
#include <corecrypto/ccmode.h>
#include <corecrypto/ccpad.h>
#include <corecrypto/cc_runtime_config.h>
#include <corecrypto/ccn.h>
#include <stdbool.h>
#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 <corecrypto/ccrng_test.h>
#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<CMP_TIMING_TEST_ITERATION;i++)
ok_or_warning(ccsymmetric_crypt_pad_timing_tests(&cryptor,padding_mode,&run_vector[0]), "Constant Time test");
}
// Plaintext tests
for(int i=0; run_vector[i].keyStr != NULL; i++) {
const ccpad_test_vector_t *test = &run_vector[i];
ok_or_fail(ccsymmetric_pad_plaintext_tests(&cryptor,padding_mode,test), "Test Vector Passed");
}
return 1;
}
// Generic test framework that checks input/output
static int test_pad_roundtrip(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;
ok_or_fail(cc_cipherAES==cryptor.cipher, "Test not implemented");
for(ccpad_select padding_mode=0; padding_mode<ccpad_cnt; padding_mode++) {
if ((cc_ModeCBC==cryptor.mode && cbc_pad_crypt_funcs[padding_mode][cc_Encrypt]!=NULL)
|| (cc_ModeECB==cryptor.mode && ecb_pad_crypt_funcs[padding_mode][cc_Encrypt]!=NULL))
{
// AES CBC
ok_or_fail(ccsymmetric_pad_roundtrip_tests(&cryptor,padding_mode,47), "Random roundtrip 47 bytes Passed");
ok_or_fail(ccsymmetric_pad_roundtrip_tests(&cryptor,padding_mode,48), "Random roundtrip 48 bytes Passed");
ok_or_fail(ccsymmetric_pad_roundtrip_tests(&cryptor,padding_mode,40), "Random roundtrip 40 bytes Passed");
}
}
return 1;
}
// Generic test framework that checks input/output
static int test_pad_ciphertext(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;
const ccpad_test_vector_t *run_vector=NULL;
if (cc_cipherAES==cryptor.cipher && cc_ModeCBC==cryptor.mode)
{
run_vector=aes_cbc_ciphertext_vectors;
}
else
{
fail("Test not implemented");
return 0;
}
// Plaintext tests
for(int i=0; run_vector[i].keyStr != NULL; i++) {
ok_or_fail(ccsymmetric_pad_ciphertext_tests(&cryptor,&run_vector[i]), "Encryption/Decryption KAT passed");
}
return 1;
}
// Main of the test
int ccpad_tests(TM_UNUSED int argc, TM_UNUSED char *const *argv)
{
plan_tests(kTestTestCount);
if (verbose) diag("Generic AES KAT padding tests");
ok(test_pad_ciphertext((ciphermode_t) ccaes_cbc_encrypt_mode(), (ciphermode_t) ccaes_cbc_decrypt_mode(),cc_cipherAES,cc_ModeCBC) == 1, "Generic KAT padding tests");
if (verbose) diag("Generic AES roundtrip padding tests");
ok(test_pad_roundtrip((ciphermode_t) ccaes_ecb_encrypt_mode(), (ciphermode_t) ccaes_ecb_decrypt_mode(),cc_cipherAES,cc_ModeECB) == 1, "Generic AES ECB roundtrip padding tests");
ok(test_pad_roundtrip((ciphermode_t) ccaes_cbc_encrypt_mode(), (ciphermode_t) ccaes_cbc_decrypt_mode(),cc_cipherAES,cc_ModeCBC) == 1, "Generic AES CBC roundtrip padding tests");
if (verbose) diag("PKCS7 Padding - Default AES-ECB");
ok(test_pad_plaintext_pkcs7((ciphermode_t) ccaes_ecb_encrypt_mode(), (ciphermode_t) ccaes_ecb_decrypt_mode(),cc_cipherAES,cc_ModeECB) == 1, "PKCS7 Padding - Default AES-ECB");
if (verbose) diag("PKCS7 Padding - Default AES-CBC");
ok(test_pad_plaintext_pkcs7((ciphermode_t) ccaes_cbc_encrypt_mode(), (ciphermode_t) ccaes_cbc_decrypt_mode(),cc_cipherAES,cc_ModeCBC) == 1, "PKCS7 Padding - Default AES-CBC");
if (verbose) diag("PKCS7 Padding - Default DES-ECB");
ok(test_pad_plaintext_pkcs7((ciphermode_t) ccdes_ecb_encrypt_mode(), (ciphermode_t) ccdes_ecb_decrypt_mode(),cc_cipherDES,cc_ModeECB) == 1, "PKCS7 Padding - Default DES-ECB");
if (verbose) diag("PKCS7 Padding - Default DES-CBC");
ok(test_pad_plaintext_pkcs7((ciphermode_t) ccdes_cbc_encrypt_mode(), (ciphermode_t) ccdes_cbc_decrypt_mode(),cc_cipherDES,cc_ModeCBC) == 1, "PKCS7 Padding - Default DES-CBC");
return 0;
}
#endif