CMAC timings
Hal Murray
hmurray at megapathdsl.net
Wed Jun 17 10:50:05 UTC 2020
levitte at openssl.org said:
> What does surprise me, though, is that direct EVP_MAC calls would be slower
> than going through the PKEY bridge. I would very much like to see your code
> to see what's going on.
Over on an ntpsec list, Kurt Roeckx reported that he was still waiting...
Richard's message said "I", so I sent him a copy off list. Correcting that...
-------------- next part --------------
/* Last modified on Sat Aug 28 14:30:11 PDT 1999 by murray */
/* Hack to time various implementations of CMAC.
*
* This is just the CMAC timing.
* It doesn't include the copy or compare or finding the right key.
*
* Beware of overflows in the timing computations.
*
* Disable AES-NI (Intel hardware: NI == New Instruction) with:
* OPENSSL_ia32cap="~0x200000200000000"
* Check /proc/cpuinfo flags for "aes" to see if you have it.
*/
#define CMAC_VERSION_CUTOFF 0x10000003
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
/* Silence warnings from CMAC routines in OpenSSL 3.0.0 */
#define OPENSSL_SUPPRESS_DEPRECATED 1
#include <openssl/opensslv.h>
#include <openssl/err.h>
#include <openssl/cmac.h>
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/objects.h>
#if OPENSSL_VERSION_NUMBER > 0x20000000L
#include <openssl/params.h>
#endif
#define UNUSED_ARG(arg) ((void)(arg))
int NUM = 1000000;
#define PACKET_LENGTH 48
#define MAX_KEY_LENGTH 64
CMAC_CTX *cmac;
#if OPENSSL_VERSION_NUMBER > 0x20000000L
EVP_MAC_CTX *evp;
#endif
unsigned char answer[EVP_MAX_MD_SIZE];
static void ssl_init(void)
{
#if OPENSSL_VERSION_NUMBER > 0x20000000L
EVP_MAC *mac;
#endif
ERR_load_crypto_strings();
OpenSSL_add_all_digests();
OpenSSL_add_all_ciphers();
cmac = CMAC_CTX_new();
#if OPENSSL_VERSION_NUMBER > 0x20000000L
mac = EVP_MAC_fetch(NULL, "cmac", NULL);
if (NULL == mac)
printf("## Oops, EVP_MAC_fetch() failed.\n");
evp = EVP_MAC_CTX_new(mac);
if (NULL == evp)
printf("## Oops, EVP_MAC_CTX_new() failed.\n");
#endif
}
static const EVP_CIPHER *CheckCipher(const char *name) {
const EVP_CIPHER *cipher;
char cbc[100];
snprintf(cbc, sizeof(cbc), "%s-CBC", name);
cipher = EVP_get_cipherbyname(cbc);
if (0 && NULL == cipher) {
/* no error available */
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops: EVP_get_cipherbyname() failed: %s\n %s\n", cbc, str);
return NULL;
}
return cipher;
}
static void PrintHex(const unsigned char* bytes, int length) {
printf(" ");
for (int i=0; i<length; i++) {
printf("%02x", bytes[i]);
}
}
static size_t One_CMAC(
const EVP_CIPHER *cipher, /* cipher algorithm */
uint8_t *key, /* key pointer */
int keylength, /* key size */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
) {
size_t len;
if (1 != CMAC_Init(cmac, key, keylength, cipher, NULL)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, CMAC_Init() failed:\n %s.\n", str);
return 0;
}
if (1 != CMAC_Update(cmac, pkt, pktlength)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, CMAC_Update() failed:\n %s.\n", str);
return 0;
}
if (1 != CMAC_Final(cmac, answer, &len)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, CMAC_Final() failed:\n %s.\n", str);
return 0;
}
return len;
}
static void DoCMAC(
const char *name, /* name of cipher */
uint8_t *key, /* key pointer */
int keylength, /* key length */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
)
{
const EVP_CIPHER *cipher = CheckCipher(name);
struct timespec start, stop;
double fast;
unsigned long digestlength = 0;
if (NULL == cipher) {
return;
}
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM; i++) {
digestlength = One_CMAC(cipher, key, keylength, pkt, pktlength);
if (0 == digestlength)
break;
}
clock_gettime(CLOCK_MONOTONIC, &stop);
fast = (stop.tv_sec-start.tv_sec)*1E9 + (stop.tv_nsec-start.tv_nsec);
printf("%12s %2d %2d %2lu %6.0f %6.3f",
name, keylength, pktlength, digestlength, fast/NUM, fast/1E9);
PrintHex(answer, digestlength);
printf("\n");
}
#if OPENSSL_VERSION_NUMBER > 0x10101000L
static size_t One_PKEY(
EVP_PKEY *pkey,
EVP_MD_CTX *ctx, /* context */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
) {
size_t len = EVP_MAX_MD_SIZE;
if (1 != EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_DigestSignInit() failed:\n %s.\n", str);
return 0;
}
EVP_DigestSign(ctx, answer, &len, pkt, pktlength);
return len;
}
static void DoPKEY(
const char *name, /* name of cipher */
uint8_t *key, /* key pointer */
int keylength, /* key length */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
)
{
struct timespec start, stop;
double fast;
unsigned long digestlength = 0;
const EVP_CIPHER *cipher = CheckCipher(name);
EVP_PKEY *pkey;
EVP_MD_CTX *ctx;
if (NULL == cipher) {
return;
}
pkey = EVP_PKEY_new_CMAC_key(NULL, key, keylength, cipher);
if (NULL == pkey) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_PKEY_new_CMAC_key() failed: %s\n %s.\n", \
name, str);
return;
}
ctx = EVP_MD_CTX_new();
if (NULL == ctx) {
printf("## Oops, EVP_MD_CTX_new() failed.\n");
return;
}
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM; i++) {
digestlength = One_PKEY(pkey, ctx, pkt, pktlength);
}
clock_gettime(CLOCK_MONOTONIC, &stop);
fast = (stop.tv_sec-start.tv_sec)*1E9 + (stop.tv_nsec-start.tv_nsec);
printf("%12s %2d %2d %2lu %6.0f %6.3f",
name, keylength, pktlength, digestlength, fast/NUM, fast/1E9);
PrintHex(answer, digestlength);
printf("\n");
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(pkey);
}
#endif
#if OPENSSL_VERSION_NUMBER > 0x20000000L
static size_t One_EVP_MAC(
EVP_MAC_CTX *ctx, /* context */
char *cipher,
uint8_t *key, /* key pointer */
int keylength, /* key length */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
) {
OSSL_PARAM params[3];
size_t len = EVP_MAX_MD_SIZE;
params[0] =
OSSL_PARAM_construct_utf8_string("cipher", cipher, 0);
params[1] =
OSSL_PARAM_construct_octet_string("key", key, keylength);
params[2] = OSSL_PARAM_construct_end();
if (0 == EVP_MAC_CTX_set_params(ctx, params)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_CTX_set_params() failed: %s.\n", str);
return 0;
}
if (0 == EVP_MAC_init(ctx)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_init() failed: %s.\n", str);
return 0;
}
if (0 == EVP_MAC_update(ctx, pkt, pktlength)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_init() failed: %s.\n", str);
return 0;
}
if (0 == EVP_MAC_final(ctx, answer, &len, sizeof(answer))) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_init() failed: %s.\n", str);
return 0;
}
return len;
}
static void Do_EVP_MAC(
const char *name, /* name of cipher */
uint8_t *key, /* key pointer */
int keylength, /* key length */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
)
{
const EVP_CIPHER *cipher = CheckCipher(name);
struct timespec start, stop;
double fast;
unsigned long digestlength = 0;
char cbc[100];
if (NULL == cipher) {
return;
}
snprintf(cbc, sizeof(cbc), "%s-CBC", name);
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM; i++) {
digestlength = One_EVP_MAC(evp, cbc, key, keylength, pkt, pktlength);
if (0 == digestlength) break;
}
clock_gettime(CLOCK_MONOTONIC, &stop);
fast = (stop.tv_sec-start.tv_sec)*1E9 + (stop.tv_nsec-start.tv_nsec);
printf("%12s %2d %2d %2lu %6.0f %6.3f",
name, keylength, pktlength, digestlength, fast/NUM, fast/1E9);
PrintHex(answer, digestlength);
printf("\n");
}
static size_t One_EVP_MAC2(
EVP_MAC_CTX *ctx, /* context */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
) {
size_t len = EVP_MAX_MD_SIZE;
if (0 == EVP_MAC_init(ctx)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_init() failed: %s.\n", str);
return 0;
}
if (0 == EVP_MAC_update(ctx, pkt, pktlength)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_init() failed: %s.\n", str);
return 0;
}
if (0 == EVP_MAC_final(ctx, answer, &len, sizeof(answer))) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_init() failed: %s.\n", str);
return 0;
}
return len;
}
static void Do_EVP_MAC2(
const char *name, /* name of cipher */
uint8_t *key, /* key pointer */
int keylength, /* key length */
uint8_t *pkt, /* packet pointer */
int pktlength /* packet length */
)
{
struct timespec start, stop;
double fast;
unsigned long digestlength = 0;
char cbc[100];
const EVP_CIPHER *cipher = CheckCipher(name);
OSSL_PARAM params[3];
if (NULL == cipher) {
return;
}
snprintf(cbc, sizeof(cbc), "%s-CBC", name);
params[0] =
OSSL_PARAM_construct_utf8_string("cipher", cbc, 0);
params[1] =
OSSL_PARAM_construct_octet_string("key", key, keylength);
params[2] = OSSL_PARAM_construct_end();
if (0 == EVP_MAC_CTX_set_params(evp, params)) {
unsigned long err = ERR_get_error();
char * str = ERR_error_string(err, NULL);
printf("## Oops, EVP_MAC_CTX_set_params() failed: %s.\n", str);
return;
}
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM; i++) {
digestlength = One_EVP_MAC2(evp, pkt, pktlength);
if (0 == digestlength) break;
}
clock_gettime(CLOCK_MONOTONIC, &stop);
fast = (stop.tv_sec-start.tv_sec)*1E9 + (stop.tv_nsec-start.tv_nsec);
printf("%12s %2d %2d %2lu %6.0f %6.3f",
name, keylength, pktlength, digestlength, fast/NUM, fast/1E9);
PrintHex(answer, digestlength);
printf("\n");
}
#endif
int main(int argc, char *argv[])
{
uint8_t key[MAX_KEY_LENGTH];
uint8_t packet[PACKET_LENGTH];
UNUSED_ARG(argc);
UNUSED_ARG(argv);
setlinebuf(stdout);
ssl_init();
RAND_bytes((unsigned char *)&key, MAX_KEY_LENGTH);
RAND_bytes((unsigned char *)&packet, PACKET_LENGTH);
for (int i=0; i< MAX_KEY_LENGTH; i++) key[i]=i*i+0x23;
for (int i=0; i< PACKET_LENGTH; i++) packet[i]=i*i+0x31;
printf("# %s\n", OPENSSL_VERSION_TEXT);
printf("\n");
printf("# KL=key length, PL=packet length, CL=CMAC length\n");
printf("# CMAC KL PL CL ns/op sec/run\n");
#if OPENSSL_VERSION_NUMBER < 0x20000000L
/* Hangs on 3.0.0 Checking OPENSSL_NO_DES doesn't work. */
DoCMAC("DES", key, 8, packet, PACKET_LENGTH);
#endif
DoCMAC("DES-EDE", key, 16, packet, PACKET_LENGTH);
DoCMAC("DES-EDE3", key, 24, packet, PACKET_LENGTH);
#ifndef OPENSSL_NO_SM4
DoCMAC("SM4", key, 16, packet, PACKET_LENGTH);
#endif
DoCMAC("AES-128", key, 16, packet, PACKET_LENGTH);
DoCMAC("AES-192", key, 24, packet, PACKET_LENGTH);
DoCMAC("AES-256", key, 32, packet, PACKET_LENGTH);
DoCMAC("CAMELLIA-128", key, 16, packet, PACKET_LENGTH);
DoCMAC("CAMELLIA-192", key, 24, packet, PACKET_LENGTH);
DoCMAC("CAMELLIA-256", key, 32, packet, PACKET_LENGTH);
DoCMAC("ARIA-128", key, 16, packet, PACKET_LENGTH);
DoCMAC("ARIA-192", key, 24, packet, PACKET_LENGTH);
DoCMAC("ARIA-256", key, 32, packet, PACKET_LENGTH);
#if OPENSSL_VERSION_NUMBER > 0x10101000L
printf("\n");
printf("# KL=key length, PL=packet length, CL=CMAC length\n");
printf("# PKEY KL PL CL ns/op sec/run\n");
#if OPENSSL_VERSION_NUMBER < 0x20000000L
DoPKEY("DES", key, 8, packet, PACKET_LENGTH);
#endif
DoPKEY("DES-EDE", key, 16, packet, PACKET_LENGTH);
DoPKEY("DES-EDE3", key, 24, packet, PACKET_LENGTH);
#ifndef OPENSSL_NO_SM4
DoPKEY("SM4", key, 16, packet, PACKET_LENGTH);
#endif
DoPKEY("AES-128", key, 16, packet, PACKET_LENGTH);
DoPKEY("AES-192", key, 24, packet, PACKET_LENGTH);
DoPKEY("AES-256", key, 32, packet, PACKET_LENGTH);
DoPKEY("CAMELLIA-128", key, 16, packet, PACKET_LENGTH);
DoPKEY("CAMELLIA-192", key, 24, packet, PACKET_LENGTH);
DoPKEY("CAMELLIA-256", key, 32, packet, PACKET_LENGTH);
DoPKEY("ARIA-128", key, 16, packet, PACKET_LENGTH);
DoPKEY("ARIA-192", key, 24, packet, PACKET_LENGTH);
DoPKEY("ARIA-256", key, 32, packet, PACKET_LENGTH);
#endif
#if OPENSSL_VERSION_NUMBER > 0x20000000L
printf("\n");
printf("# KL=key length, PL=packet length, CL=CMAC length\n");
printf("# EVP_MAC KL PL CL ns/op sec/run\n");
Do_EVP_MAC("DES-EDE", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC("DES-EDE3", key, 24, packet, PACKET_LENGTH);
#ifndef OPENSSL_NO_SM4
Do_EVP_MAC("SM4", key, 16, packet, PACKET_LENGTH);
#endif
Do_EVP_MAC("AES-128", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC("AES-192", key, 24, packet, PACKET_LENGTH);
Do_EVP_MAC("AES-256", key, 32, packet, PACKET_LENGTH);
Do_EVP_MAC("CAMELLIA-128", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC("CAMELLIA-192", key, 24, packet, PACKET_LENGTH);
Do_EVP_MAC("CAMELLIA-256", key, 32, packet, PACKET_LENGTH);
Do_EVP_MAC("ARIA-128", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC("ARIA-192", key, 24, packet, PACKET_LENGTH);
Do_EVP_MAC("ARIA-256", key, 32, packet, PACKET_LENGTH);
printf("\n");
printf("Preload cipher and key.\n");
Do_EVP_MAC2("DES-EDE", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC2("DES-EDE3", key, 24, packet, PACKET_LENGTH);
#ifndef OPENSSL_NO_SM4
Do_EVP_MAC2("SM4", key, 16, packet, PACKET_LENGTH);
#endif
Do_EVP_MAC2("AES-128", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC2("AES-192", key, 24, packet, PACKET_LENGTH);
Do_EVP_MAC2("AES-256", key, 32, packet, PACKET_LENGTH);
Do_EVP_MAC2("CAMELLIA-128", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC2("CAMELLIA-192", key, 24, packet, PACKET_LENGTH);
Do_EVP_MAC2("CAMELLIA-256", key, 32, packet, PACKET_LENGTH);
Do_EVP_MAC2("ARIA-128", key, 16, packet, PACKET_LENGTH);
Do_EVP_MAC2("ARIA-192", key, 24, packet, PACKET_LENGTH);
Do_EVP_MAC2("ARIA-256", key, 32, packet, PACKET_LENGTH);
#endif
return 0;
}
-------------- next part --------------
--
These are my opinions. I hate spam.
More information about the openssl-users
mailing list