I'm trying to execute AES in a high-speed manner. When I execute openssl speed test with the following command, I get the following result:
$ openssl speed -elapsed -evp aes-128-cbc
You have chosen to measure elapsed time instead of user CPU time.
Doing aes-128-cbc for 3s on 16 size blocks: 224201744 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 64 size blocks: 62982851 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 256 size blocks: 16102515 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 1024 size blocks: 4052200 aes-128-cbc's in 3.00s
Doing aes-128-cbc for 3s on 8192 size blocks: 510962 aes-128-cbc's in 3.00s
OpenSSL 1.0.2n 7 Dec 2017
built on: reproducible build, date unspecified
options:bn(64,64) rc4(16x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: gcc -I. -I.. -I../include -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O3 -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DRC4_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-128-cbc 1195742.63k 1343634.15k 1374081.28k 1383150.93k 1395266.90k
which means that the speed of each AES encryption for a 128 bit block should be 1.32 ns. But when I execute the following C++ code which is using openssl and EVP, the performance becomes 217 ns:
#include <stdio.h>
#include <openssl/evp.h>
#include <chrono>
#include <iostream>
using namespace std;
int main()
{
EVP_CIPHER_CTX ctx;
unsigned char key[16] = {0};
unsigned char iv[16] = {0};
unsigned char in[16] = {0};
unsigned char out[16]; /* at least one block longer than in[] */
int outlen1, outlen2;
std::chrono::time_point<std::chrono::high_resolution_clock> m_beg = std::chrono::high_resolution_clock::now();
for(int z=0;z<10000;z++){
EVP_EncryptInit(&ctx, EVP_aes_128_cbc(), key, iv);
EVP_EncryptUpdate(&ctx, out, &outlen1, in, sizeof(in));
EVP_EncryptFinal(&ctx, out + outlen1, &outlen2);
}
double t = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_beg).count();
cout<<t<<endl;
printf("ciphertext length: %d\n", outlen1 + outlen2);
return 0;
}
Does anyone have any idea what is the problem?
This is my release make file:
# Environment
MKDIR=mkdir
CP=cp
GREP=grep
NM=nm
CCADMIN=CCadmin
RANLIB=ranlib
CC=gcc
CCC=g++
CXX=g++
FC=g++
AS=as
# Macros
CND_PLATFORM=GNU-Linux
CND_DLIB_EXT=so
CND_CONF=Release
CND_DISTDIR=dist
CND_BUILDDIR=build
# Include project Makefile
include Makefile
# Object Directory
OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}
# Object Files
OBJECTFILES= \
${OBJECTDIR}/main.o
# C Compiler Flags
CFLAGS=
# CC Compiler Flags
CCFLAGS=
CXXFLAGS=
# Fortran Compiler Flags
FFLAGS=
# Assembler Flags
ASFLAGS=
# Link Libraries and Options
LDLIBSOPTIONS=
# Build Targets
.build-conf: ${BUILD_SUBPROJECTS}
"${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/aes_ni_test
${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/aes_ni_test: ${OBJECTFILES}
${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/aes_ni_test ${OBJECTFILES} ${LDLIBSOPTIONS} -lcrypto
${OBJECTDIR}/main.o: main.cpp
${MKDIR} -p ${OBJECTDIR}
${RM} "$@.d"
$(COMPILE.cc) -O3 -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/main.o main.cpp
# Subprojects
.build-subprojects:
# Clean Targets
.clean-conf: ${CLEAN_SUBPROJECTS}
${RM} -r ${CND_BUILDDIR}/${CND_CONF}
# Subprojects
.clean-subprojects:
# Enable dependency checking
.dep.inc: .depcheck-impl
include .dep.inc
The reason is the INIT and FINAL part of AES in c++ code. OPENSSL command does not execute it for every encryption. So, Its performance is much higher.