avoid EVP_CIPHER_CTX_reset() & add speed test
This commit is contained in:
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user