levi...@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...

/* 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;
}
-- 
These are my opinions.  I hate spam.

Reply via email to