avoid EVP_CIPHER_CTX_reset() & add speed test

This commit is contained in:
Hanjie Wu
2021-12-10 01:36:50 +08:00
parent 1e762aa3f4
commit 8fb5f23226
2 changed files with 153 additions and 12 deletions

View File

@@ -37,11 +37,13 @@ using EvpCipherContext = std::unique_ptr<EVP_CIPHER_CTX, EvpCipherContextFree>;
struct CipherContext {
const EVP_CIPHER* cipher;
EvpCipherContext ctx;
EvpCipherContext encrypt_ctx;
EvpCipherContext decrypt_ctx;
std::vector<u8> key;
std::vector<u8> iv;
CipherContext(EVP_CIPHER_CTX* ctx_in) : ctx(ctx_in) {}
CipherContext(EVP_CIPHER_CTX* encrypt_ctx_in, EVP_CIPHER_CTX* decrypt_ctx_in)
: encrypt_ctx(encrypt_ctx_in), decrypt_ctx(decrypt_ctx_in) {}
};
const static std::map<Mode, decltype(&EVP_aes_128_ctr)> cipher_map = {
@@ -49,11 +51,16 @@ const static std::map<Mode, decltype(&EVP_aes_128_ctr)> cipher_map = {
template <typename Key, std::size_t KeySize>
Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
: ctx(std::make_unique<CipherContext>(EVP_CIPHER_CTX_new())) {
ASSERT_MSG((ctx->ctx.get() != NULL), "Failed to initialize OpenSSL ciphers.");
: ctx(std::make_unique<CipherContext>(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new())) {
ASSERT_MSG((ctx->encrypt_ctx.get() != NULL), "Failed to initialize OpenSSL ciphers.");
ASSERT_MSG((ctx->decrypt_ctx.get() != NULL), "Failed to initialize OpenSSL ciphers.");
ctx->cipher = cipher_map.at(mode)();
ctx->key.resize(KeySize);
std::memcpy(ctx->key.data(), key.data(), KeySize);
EVP_EncryptInit(ctx->encrypt_ctx.get(), ctx->cipher, ctx->key.data(), nullptr);
EVP_DecryptInit(ctx->decrypt_ctx.get(), ctx->cipher, ctx->key.data(), nullptr);
EVP_CIPHER_CTX_set_padding(ctx->encrypt_ctx.get(), 0);
EVP_CIPHER_CTX_set_padding(ctx->decrypt_ctx.get(), 0);
}
template <typename Key, std::size_t KeySize>
@@ -61,14 +68,11 @@ AESCipher<Key, KeySize>::~AESCipher() = default;
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
EVP_CIPHER_CTX_reset(ctx->ctx.get());
EVP_CipherInit(ctx->ctx.get(), ctx->cipher, ctx->key.data(), ctx->iv.data(),
op == Op::Encrypt ? 1 : 0);
EVP_CIPHER_CTX_set_padding(ctx->ctx.get(), 0);
EVP_CIPHER_CTX* cipher_ctx =
op == Op::Encrypt ? ctx->encrypt_ctx.get() : ctx->decrypt_ctx.get();
int written, last_written;
if (EVP_CIPHER_mode(ctx->cipher) == EVP_CIPH_XTS_MODE) {
EVP_CipherUpdate(ctx->ctx.get(), dest, &written, src, static_cast<int>(size));
EVP_CipherUpdate(cipher_ctx, dest, &written, src, static_cast<int>(size));
if (written != static_cast<int>(size)) {
LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
size, written);
@@ -76,11 +80,11 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
} else {
std::size_t block_size = EVP_CIPHER_block_size(ctx->cipher);
std::size_t remain = size % block_size;
EVP_CipherUpdate(ctx->ctx.get(), dest, &written, src, static_cast<int>(size - remain));
EVP_CipherUpdate(cipher_ctx, dest, &written, src, static_cast<int>(size - remain));
if (remain != 0) {
std::vector<u8> block(block_size);
std::memcpy(block.data(), src + size - remain, remain);
EVP_CipherUpdate(ctx->ctx.get(), dest + written, &last_written, block.data(),
EVP_CipherUpdate(cipher_ctx, dest + written, &last_written, block.data(),
static_cast<int>(block_size));
written += last_written;
}
@@ -106,6 +110,8 @@ template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
ctx->iv.resize(data.size());
std::memcpy(ctx->iv.data(), data.data(), data.size());
EVP_EncryptInit(ctx->encrypt_ctx.get(), nullptr, nullptr, ctx->iv.data());
EVP_DecryptInit(ctx->decrypt_ctx.get(), nullptr, nullptr, ctx->iv.data());
}
template class AESCipher<Key128>;

View File

@@ -8,8 +8,13 @@
#include <cstring>
#include "common/common_types.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/crypto.h"
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_detect.h"
#endif
constexpr static u8 msg[] = "The quick brown fox jumps over the lazy dog";
constexpr static u8 key[] = "key";
@@ -100,3 +105,133 @@ TEST_CASE("AES-128-XTS", "[core]") {
cipher.XTSTranscode(aes_plain, 32, aes_encrypted, 0, 16, Core::Crypto::Op::Encrypt);
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
}
double RunFunctionAndReturnTime(void (*f)(), const Core::Timing::CoreTiming& timing) {
const u64 start = timing.GetGlobalTimeNs().count();
f();
const u64 end = timing.GetGlobalTimeNs().count();
return static_cast<double>(end - start);
}
void MD5SpeedTest() {
std::array<u8, 16> hash;
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
std::memset(msg.get(), 0, 1024 * 1024);
for (int i = 0; i < 1024; i++) {
CalculateMD5(msg.get(), 1024 * 1024, hash.data());
}
}
void SHA256SpeedTest() {
std::array<u8, 32> hash;
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
std::memset(msg.get(), 0, 1024 * 1024);
for (int i = 0; i < 1024; i++) {
CalculateSHA256(msg.get(), 1024 * 1024, hash.data());
}
}
void HMACSHA256SpeedTest() {
constexpr static u8 key[] = "0123456789abcdef";
std::array<u8, 32> hash;
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
std::memset(msg.get(), 0, 1024 * 1024);
for (int i = 0; i < 1024; i++) {
CalculateHMACSHA256(hash.data(), key, sizeof(key) - 1, msg.get(), 1024 * 1024);
}
}
void CMACAESSpeedTest() {
constexpr static u8 key[] = "0123456789abcdef";
std::array<u8, 32> hash;
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
std::memset(msg.get(), 0, 1024 * 1024);
for (int i = 0; i < 1024; i++) {
CalculateCMAC(msg.get(), 1024 * 1024, key, hash.data());
}
}
void AES128CTRSpeedTest() {
constexpr static std::array<u8, 16> key = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
constexpr static std::array<u8, 16> iv = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
const std::unique_ptr<u8[]> encrypted(new u8[1024 * 1024]);
Core::Crypto::AESCipher cipher(key, Core::Crypto::Mode::CTR);
for (int i = 0; i < 1024; i++) {
cipher.SetIV(iv);
cipher.Transcode(msg.get(), 1024 * 1024, encrypted.get(), Core::Crypto::Op::Encrypt);
}
}
void AES128ECBSpeedTest() {
constexpr static std::array<u8, 16> key = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
const std::unique_ptr<u8[]> encrypted(new u8[1024 * 1024]);
Core::Crypto::AESCipher cipher(key, Core::Crypto::Mode::ECB);
for (int i = 0; i < 1024; i++) {
cipher.Transcode(msg.get(), 1024 * 1024, encrypted.get(), Core::Crypto::Op::Encrypt);
}
}
void AES128XTSSpeedTest() {
constexpr static std::array<u8, 32> xts_key = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0};
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
const std::unique_ptr<u8[]> encrypted(new u8[1024 * 1024]);
Core::Crypto::AESCipher cipher(xts_key, Core::Crypto::Mode::XTS);
for (int i = 0; i < 1024; i++) {
cipher.XTSTranscode(msg.get(), 1024 * 1024, encrypted.get(), 0, 16,
Core::Crypto::Op::Encrypt);
}
}
struct ScopeInit final {
ScopeInit() {
core_timing.SetMulticore(true);
core_timing.Initialize([]() {});
}
~ScopeInit() {
core_timing.Shutdown();
}
Core::Timing::CoreTiming core_timing;
};
TEST_CASE("SPEED", "[core]") {
#ifdef ARCHITECTURE_x86_64
const auto& caps = Common::GetCPUCaps();
std::string cpu_string = caps.cpu_string;
if (caps.avx || caps.avx2 || caps.avx512) {
cpu_string += " | AVX";
if (caps.avx512) {
cpu_string += "512";
} else if (caps.avx2) {
cpu_string += '2';
}
if (caps.fma || caps.fma4) {
cpu_string += " | FMA";
}
}
printf("Host CPU: %s\n", cpu_string.c_str());
#endif
ScopeInit guard;
double time;
time = RunFunctionAndReturnTime(MD5SpeedTest, guard.core_timing);
printf("MD5 speed: %fMB/s\n", 1024e9 / time);
time = RunFunctionAndReturnTime(SHA256SpeedTest, guard.core_timing);
printf("SHA256 speed: %fMB/s\n", 1024e9 / time);
time = RunFunctionAndReturnTime(HMACSHA256SpeedTest, guard.core_timing);
printf("HMACSHA256 speed: %fMB/s\n", 1024e9 / time);
time = RunFunctionAndReturnTime(CMACAESSpeedTest, guard.core_timing);
printf("CMAC-AES speed: %fMB/s\n", 1024e9 / time);
time = RunFunctionAndReturnTime(AES128CTRSpeedTest, guard.core_timing);
printf("AES-128-CTR speed: %fMB/s\n", 1024e9 / time);
time = RunFunctionAndReturnTime(AES128ECBSpeedTest, guard.core_timing);
printf("AES-128-ECB speed: %fMB/s\n", 1024e9 / time);
time = RunFunctionAndReturnTime(AES128XTSSpeedTest, guard.core_timing);
printf("AES-128-XTS speed: %fMB/s\n", 1024e9 / time);
}