Add Random Number Generator benchmarks (Issue 386)

Move HTML header and footer into benchmark functions
Switch to <cmath> and standard math routines
Switch to <ctime> and standard clock and time routines
Move static variable^Cinto anonymous namespace
Add TimeToString function for printing start and end times
pull/354/merge
Jeffrey Walton 2017-03-08 16:59:24 -05:00
parent 2416c0eaf5
commit ce38a411fc
No known key found for this signature in database
GPG Key ID: B36AB348921B1838
9 changed files with 583 additions and 393 deletions

40
bench.h
View File

@ -6,26 +6,36 @@
#include "cryptlib.h"
#include <iostream>
#include <iomanip>
#include <cmath>
#include <ctime>
NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)
ANONYMOUS_NAMESPACE_BEGIN
#ifdef CLOCKS_PER_SEC
const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC;
#elif defined(CLK_TCK)
const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK;
#else
const double CLOCK_TICKS_PER_SECOND = 1000000.0;
#endif
extern const double CLOCK_TICKS_PER_SECOND;
extern double g_allocatedTime;
extern double g_hertz;
extern double g_logTotal;
extern unsigned int g_logCount;
extern const byte defaultKey[];
static const byte defaultKey[] = "0123456789" // 168 + NULL
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
"00000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000";
NAMESPACE_END
// Test book keeping
extern time_t g_testBegin;
extern time_t g_testEnd;
void BenchmarkAll(double t, double hertz);
void BenchmarkAll2(double t, double hertz);
// Top level, prints preamble and postamble
void Benchmark(int suites, double t, double hertz);
// Unkeyed systems
void Benchmark1(double t, double hertz);
// Shared key systems
void Benchmark2(double t, double hertz);
// Public key systems
void Benchmark3(double t, double hertz);
void OutputResultBytes(const char *name, double length, double timeTaken);
void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken);
NAMESPACE_END // Test
NAMESPACE_END // CryptoPP

View File

@ -14,18 +14,27 @@
#include "factory.h"
#include "smartptr.h"
#include "cpu.h"
#include <time.h>
#include <math.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "drbg.h"
NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)
double logTotal = 0.0, g_allocatedTime = 0, g_hertz = 0;
unsigned int logCount = 0;
#ifdef CLOCKS_PER_SEC
const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC;
#elif defined(CLK_TCK)
const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK;
#else
const double CLOCK_TICKS_PER_SECOND = 1000000.0;
#endif
const byte defaultKey[] = "0123456789" // 168 + NULL
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
"00000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000";
double g_allocatedTime = 0.0, g_hertz = 0.0, g_logTotal = 0.0;
unsigned int g_logCount = 0;
time_t g_testBegin, g_testEnd;
void OutputResultBytes(const char *name, double length, double timeTaken)
{
@ -33,19 +42,17 @@ void OutputResultBytes(const char *name, double length, double timeTaken)
StreamState ss(std::cout);
// Coverity finding
if (length < 0.0000000001f) length = 0.000001f;
if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
if (length < 0.000001f) length = 0.000001f;
if (timeTaken < 0.000001f) timeTaken = 0.000001f;
double mbs = length / timeTaken / (1024*1024);
std::cout << "\n<TR><TH>" << name;
// std::cout << "<TD>" << std::setprecision(3) << length / (1024*1024);
std::cout << std::setiosflags(std::ios::fixed);
// std::cout << "<TD>" << std::setprecision(3) << timeTaken;
std::cout << "<TD>" << std::setprecision(0) << std::setiosflags(std::ios::fixed) << mbs;
if (g_hertz)
if (g_hertz > 1.0f)
std::cout << "<TD>" << std::setprecision(1) << std::setiosflags(std::ios::fixed) << timeTaken * g_hertz / length;
logTotal += log(mbs);
logCount++;
g_logTotal += std::log(mbs);
g_logCount++;
}
void OutputResultKeying(double iterations, double timeTaken)
@ -54,11 +61,13 @@ void OutputResultKeying(double iterations, double timeTaken)
StreamState ss(std::cout);
// Coverity finding
if (iterations < 0.0000000001f) iterations = 0.000001f;
if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
if (iterations < 0.000001f) iterations = 0.000001f;
if (timeTaken < 0.000001f) timeTaken = 0.000001f;
std::cout << "<TD>" << std::setprecision(3) << std::setiosflags(std::ios::fixed) << (1000*1000*timeTaken/iterations);
if (g_hertz)
// Coverity finding
if (g_hertz > 1.0f)
std::cout << "<TD>" << std::setprecision(0) << std::setiosflags(std::ios::fixed) << timeTaken * g_hertz / iterations;
}
@ -69,15 +78,17 @@ void OutputResultOperations(const char *name, const char *operation, bool pc, un
// Coverity finding
if (!iterations) iterations++;
if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
if (timeTaken < 0.000001f) timeTaken = 0.000001f;
std::cout << "\n<TR><TH>" << name << " " << operation << (pc ? " with precomputation" : "");
std::cout << "<TD>" << std::setprecision(2) << std::setiosflags(std::ios::fixed) << (1000*timeTaken/iterations);
if (g_hertz)
// Coverity finding
if (g_hertz > 1.0f)
std::cout << "<TD>" << std::setprecision(2) << std::setiosflags(std::ios::fixed) << timeTaken * g_hertz / iterations / 1000000;
logTotal += log(iterations/timeTaken);
logCount++;
g_logTotal += std::log(iterations/timeTaken);
g_logCount++;
}
/*
@ -85,17 +96,19 @@ void BenchMark(const char *name, BlockTransformation &cipher, double timeTotal)
{
const int BUF_SIZE = RoundUpToMultipleOf(2048U, cipher.OptimalNumberOfParallelBlocks() * cipher.BlockSize());
AlignedSecByteBlock buf(BUF_SIZE);
const int nBlocks = BUF_SIZE / cipher.BlockSize();
clock_t start = clock();
buf.SetMark(16);
const int nBlocks = BUF_SIZE / cipher.BlockSize();
unsigned long i=0, blocks=1;
double timeTaken;
clock_t start = ::clock();
do
{
blocks *= 2;
for (; i<blocks; i++)
cipher.ProcessAndXorMultipleBlocks(buf, NULLPTR, buf, nBlocks);
timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
}
while (timeTaken < 2.0/3*timeTotal);
@ -108,16 +121,18 @@ void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal)
const int BUF_SIZE=RoundUpToMultipleOf(2048U, cipher.OptimalBlockSize());
AlignedSecByteBlock buf(BUF_SIZE);
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
clock_t start = clock();
buf.SetMark(16);
unsigned long i=0, blocks=1;
double timeTaken;
clock_t start = ::clock();
do
{
blocks *= 2;
for (; i<blocks; i++)
cipher.ProcessString(buf, BUF_SIZE);
timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
}
while (timeTaken < 2.0/3*timeTotal);
@ -137,16 +152,18 @@ void BenchMark(const char *name, HashTransformation &ht, double timeTotal)
const int BUF_SIZE=2048U;
AlignedSecByteBlock buf(BUF_SIZE);
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
clock_t start = clock();
buf.SetMark(16);
unsigned long i=0, blocks=1;
double timeTaken;
clock_t start = ::clock();
do
{
blocks *= 2;
for (; i<blocks; i++)
ht.Update(buf, BUF_SIZE);
timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
}
while (timeTaken < 2.0/3*timeTotal);
@ -158,32 +175,82 @@ void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal)
const int BUF_SIZE=2048U;
AlignedSecByteBlock buf(BUF_SIZE);
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
clock_t start = clock();
buf.SetMark(16);
unsigned long i=0, blocks=1;
double timeTaken;
clock_t start = ::clock();
do
{
blocks *= 2;
for (; i<blocks; i++)
bt.Put(buf, BUF_SIZE);
timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
}
while (timeTaken < 2.0/3*timeTotal);
OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
}
void BenchMark(const char *name, RandomNumberGenerator &rng, double timeTotal)
{
const int BUF_SIZE = 2048U;
AlignedSecByteBlock buf(BUF_SIZE);
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
buf.SetMark(16);
unsigned long long blocks = 1;
double timeTaken;
clock_t start = ::clock();
do
{
rng.GenerateBlock(buf, buf.size());
blocks++;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
} while (timeTaken < timeTotal);
OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
}
// Hack, but we probably need a KeyedRandomNumberGenerator interface
// and a few methods to generalize keying a RNG. X917RNG, Hash_DRBG,
// HMAC_DRBG, AES/CFB RNG and a few others could use it. "A few others"
// includes BLAKE2, ChaCha and Poly1305 when used as a RNG.
void BenchMark(const char *name, NIST_DRBG &rng, double timeTotal)
{
const int BUF_SIZE = 2048U;
AlignedSecByteBlock buf(BUF_SIZE);
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
buf.SetMark(16);
rng.IncorporateEntropy(buf, rng.GetMinEntropy());
unsigned long long blocks = 1;
double timeTaken;
clock_t start = ::clock();
do
{
rng.GenerateBlock(buf, buf.size());
blocks++;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
} while (timeTaken < timeTotal);
OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
}
void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs &params)
{
unsigned long iterations = 0;
clock_t start = clock();
double timeTaken;
clock_t start = ::clock();
do
{
for (unsigned int i=0; i<1024; i++)
c.SetKey(defaultKey, keyLength, params);
timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
iterations += 1024;
}
while (timeTaken < g_allocatedTime);
@ -230,70 +297,121 @@ void BenchMarkByNameKeyLess(const char *factoryName, const char *displayName=NUL
BenchMark(name.c_str(), *obj, g_allocatedTime);
}
void BenchmarkAll(double t, double hertz)
void AddHtmlHeader()
{
// HTML5
std::cout << "<!DOCTYPE HTML>";
std::cout << "\n<HTML lang=\"en\">";
std::cout << "\n<HEAD>";
std::cout << "\n<META charset=\"UTF-8\">";
std::cout << "\n<TITLE>Speed Comparison of Popular Crypto Algorithms</TITLE>";
std::cout << "\n<STYLE>\n table {border-collapse: collapse;}";
std::cout << "\n table, th, td, tr {border: 1px solid black;}\n</STYLE>";
std::cout << "\n</HEAD>";
std::cout << "\n<BODY>";
std::cout << "\n<H1><A href=\"http://www.cryptopp.com\">Crypto++</A> " << CRYPTOPP_VERSION / 100;
std::cout << '.' << (CRYPTOPP_VERSION % 100) / 10 << '.' << CRYPTOPP_VERSION % 10 << " Benchmarks</H1>";
std::cout << "\n<P>Here are speed benchmarks for some commonly used cryptographic algorithms.</P>";
if (g_hertz > 1.0f)
std::cout << "\n<P>CPU frequency of the test platform is " << g_hertz << " Hz.</P>";
else
std::cout << "\n<P>CPU frequency of the test platform was not provided.</P>" << std::endl;
}
void AddHtmlFooter()
{
std::cout << "\n</BODY>";
std::cout << "\n</HTML>" << std::endl;
}
void Benchmark(int suites, double t, double hertz)
{
#if 1
logTotal = 0;
logCount = 0;
g_allocatedTime = t;
g_hertz = hertz;
const char *cpb, *cpk;
if (g_hertz)
g_testBegin = std::time(NULLPTR);
AddHtmlHeader();
if (suites > 7)
suites = 7;
// Unkeyed algorithms
if (suites & 1)
Benchmark1(t, hertz);
if (suites > 1)
std::cout << "\n<BR>";
// Shared key algorithms
if (suites & 2)
Benchmark2(t, hertz);
if (suites > 2)
std::cout << "\n<BR>";
// Public key algorithms
if (suites & 4)
Benchmark3(t, hertz);
g_testEnd = std::time(NULLPTR);
{
StreamState state(std::cout);
std::cout << "\n<P>Throughput Geometric Average: " << std::setiosflags(std::ios::fixed);
std::cout << std::exp(g_logTotal/(g_logCount > 0.0f ? g_logCount : 1.0f)) << std::endl;
}
std::cout << "\n<P>Test started at " << TimeToString(g_testBegin);
std::cout << "\n<BR>Test ended at " << TimeToString(g_testEnd);
std::cout << std::endl;
AddHtmlFooter();
}
void Benchmark1(double t, double hertz)
{
g_allocatedTime = t;
g_hertz = hertz;
const char *cpb;
if (g_hertz > 1.0f)
cpb = "<TH>Cycles Per Byte";
cpk = "<TH>Cycles to<br>Setup Key and IV";
std::cout << "CPU frequency of the test platform is " << g_hertz << " Hz.\n";
}
else
cpb = "";
std::cout << "\n<TABLE style=\"border:1px solid\">";
std::cout << "\n<COLGROUP><COL style=\"text-align: left;\"><COL style=\"text-align: right;\">";
std::cout << "<COL style=\"text-align: right;\">";
std::cout << "\n<THEAD style=\"background: #F0F0F0\"><TR><TH>Algorithm<TH>MiB/Second" << cpb;
std::cout << "\n<TBODY style=\"background: white;\">";
{
cpb = cpk = "";
std::cout << "CPU frequency of the test platform was not provided.\n";
}
std::cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right><COL align=right><COL align=right>" << std::endl;
std::cout << "<THEAD><TR><TH>Algorithm<TH>MiB/Second" << cpb << "<TH>Microseconds to<br>Setup Key and IV" << cpk << std::endl;
std::cout << "\n<TBODY style=\"background: yellow\">";
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
if (HasCLMUL())
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
else
#elif CRYPTOPP_BOOL_ARM_PMULL_AVAILABLE
if (HasPMULL())
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
else
#ifdef NONBLOCKING_RNG_AVAILABLE
BenchMarkByNameKeyLess<RandomNumberGenerator>("NonblockingRng");
#endif
{
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (2K tables)", MakeParameters(Name::TableSize(), 2048));
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
}
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/CCM");
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/EAX");
std::cout << "\n<TBODY style=\"background: white\">";
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
if (HasCLMUL())
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES)");
else
#ifdef OS_RNG_AVAILABLE
BenchMarkByNameKeyLess<RandomNumberGenerator>("AutoSeededRandomPool");
BenchMarkByNameKeyLess<RandomNumberGenerator>("AutoSeededX917RNG(AES)");
#endif
{
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (2K tables)", MakeParameters(Name::TableSize(), 2048));
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
BenchMarkByNameKeyLess<RandomNumberGenerator>("MT19937");
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
if (HasRDRAND())
BenchMarkByNameKeyLess<RandomNumberGenerator>("RDRAND");
if (HasRDSEED())
BenchMarkByNameKeyLess<RandomNumberGenerator>("RDSEED");
#endif
BenchMarkByNameKeyLess<NIST_DRBG>("Hash_DRBG(SHA1)");
BenchMarkByNameKeyLess<NIST_DRBG>("HMAC_DRBG(SHA1)");
}
BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-64");
BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-128");
BenchMarkByName<MessageAuthenticationCode>("HMAC(SHA-1)");
BenchMarkByName<MessageAuthenticationCode>("Two-Track-MAC");
BenchMarkByName<MessageAuthenticationCode>("CMAC(AES)");
BenchMarkByName<MessageAuthenticationCode>("DMAC(AES)");
BenchMarkByName<MessageAuthenticationCode>("Poly1305(AES)");
BenchMarkByName<MessageAuthenticationCode>("BLAKE2s");
BenchMarkByName<MessageAuthenticationCode>("BLAKE2b");
BenchMarkByName<MessageAuthenticationCode>("SipHash-2-4");
BenchMarkByName<MessageAuthenticationCode>("SipHash-4-8");
std::cout << "\n<TBODY style=\"background: yellow\">";
std::cout << "\n<TBODY style=\"background: yellow;\">";
{
BenchMarkByNameKeyLess<HashTransformation>("CRC32");
BenchMarkByNameKeyLess<HashTransformation>("CRC32C");
BenchMarkByNameKeyLess<HashTransformation>("Adler32");
@ -317,8 +435,64 @@ void BenchmarkAll(double t, double hertz)
BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-256");
BenchMarkByNameKeyLess<HashTransformation>("BLAKE2s");
BenchMarkByNameKeyLess<HashTransformation>("BLAKE2b");
}
std::cout << "\n<TBODY style=\"background: white\">";
std::cout << "\n</TABLE>" << std::endl;
}
void Benchmark2(double t, double hertz)
{
g_allocatedTime = t;
g_hertz = hertz;
const char *cpb, *cpk;
if (g_hertz > 1.0f)
{
cpb = "<TH>Cycles Per Byte";
cpk = "<TH>Cycles to<BR>Setup Key and IV";
}
else
{
cpb = cpk = "";
}
std::cout << "\n<TABLE style=\"border:1px solid\">";
std::cout << "\n<COLGROUP><COL style=\"text-align: left;\"><COL style=\"text-align: right;\"><COL style=";
std::cout << "\"text-align: right;\"><COL style=\"text-align: right;\"><COL style=\"text-align: right;\">";
std::cout << "\n<THEAD style=\"background: #F0F0F0\"><TR><TH>Algorithm<TH>MiB/Second" << cpb;
std::cout << "<TH>Microseconds to<BR>Setup Key and IV" << cpk;
std::cout << "\n<TBODY style=\"background: white;\">";
{
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
if (HasCLMUL())
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES)");
else
#elif CRYPTOPP_BOOL_ARM_PMULL_AVAILABLE
if (HasPMULL())
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES)");
else
#endif
{
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (2K tables)", MakeParameters(Name::TableSize(), 2048));
BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (64K tables)", MakeParameters(Name::TableSize(), 64 * 1024));
}
BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-64");
BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-128");
BenchMarkByName<MessageAuthenticationCode>("HMAC(SHA-1)");
BenchMarkByName<MessageAuthenticationCode>("Two-Track-MAC");
BenchMarkByName<MessageAuthenticationCode>("CMAC(AES)");
BenchMarkByName<MessageAuthenticationCode>("DMAC(AES)");
BenchMarkByName<MessageAuthenticationCode>("Poly1305(AES)");
BenchMarkByName<MessageAuthenticationCode>("BLAKE2s");
BenchMarkByName<MessageAuthenticationCode>("BLAKE2b");
BenchMarkByName<MessageAuthenticationCode>("SipHash-2-4");
BenchMarkByName<MessageAuthenticationCode>("SipHash-4-8");
}
std::cout << "\n<TBODY style=\"background: yellow;\">";
{
BenchMarkByName<SymmetricCipher>("Panama-LE");
BenchMarkByName<SymmetricCipher>("Panama-BE");
BenchMarkByName<SymmetricCipher>("Salsa20");
@ -331,8 +505,10 @@ void BenchmarkAll(double t, double hertz)
BenchMarkByName<SymmetricCipher>("MARC4");
BenchMarkByName<SymmetricCipher>("SEAL-3.0-LE");
BenchMarkByName<SymmetricCipher>("WAKE-OFB-LE");
}
std::cout << "\n<TBODY style=\"background: yellow\">";
std::cout << "\n<TBODY style=\"background: white;\">";
{
BenchMarkByName<SymmetricCipher>("AES/CTR", 16);
BenchMarkByName<SymmetricCipher>("AES/CTR", 24);
BenchMarkByName<SymmetricCipher>("AES/CTR", 32);
@ -362,29 +538,28 @@ void BenchmarkAll(double t, double hertz)
BenchMarkByName<SymmetricCipher>("CAST-128/CTR");
BenchMarkByName<SymmetricCipher>("SKIPJACK/CTR");
BenchMarkByName<SymmetricCipher>("SEED/CTR", 0, "SEED/CTR (1/2 K table)");
std::cout << "</TABLE>" << std::endl;
}
BenchmarkAll2(t, hertz);
std::cout << "Throughput Geometric Average: " << std::setiosflags(std::ios::fixed) << exp(logTotal/(logCount ? logCount : 1)) << std::endl;
// Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
#if (CRYPTOPP_MSC_VERSION >= 1400)
tm localTime = {};
char timeBuf[64];
errno_t err;
const time_t endTime = time(NULLPTR);
err = localtime_s(&localTime, &endTime);
CRYPTOPP_ASSERT(err == 0);
err = asctime_s(timeBuf, sizeof(timeBuf), &localTime);
CRYPTOPP_ASSERT(err == 0);
std::cout << "\nTest ended at " << timeBuf;
#else
const time_t endTime = time(NULLPTR);
std::cout << "\nTest ended at " << asctime(localtime(&endTime));
#endif
std::cout << "\n<TBODY style=\"background: yellow;\">";
{
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
if (HasCLMUL())
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
else
#elif CRYPTOPP_BOOL_ARM_PMULL_AVAILABLE
if (HasPMULL())
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
else
#endif
{
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (2K tables)", MakeParameters(Name::TableSize(), 2048));
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (64K tables)", MakeParameters(Name::TableSize(), 64 * 1024));
}
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/CCM");
BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/EAX");
}
std::cout << "\n</TABLE>" << std::endl;
}
NAMESPACE_END // Test

View File

@ -30,26 +30,20 @@
#include "oids.h"
#include "randpool.h"
#include <time.h>
#include <math.h>
#include <iostream>
#include <iomanip>
NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)
void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken);
void BenchMarkEncryption(const char *name, PK_Encryptor &key, double timeTotal, bool pc=false)
{
unsigned int len = 16;
SecByteBlock plaintext(len), ciphertext(key.CiphertextLength(len));
Test::GlobalRNG().GenerateBlock(plaintext, len);
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
key.Encrypt(Test::GlobalRNG(), plaintext, len, ciphertext);
OutputResultOperations(name, "Encryption", pc, i, timeTaken);
@ -69,10 +63,11 @@ void BenchMarkDecryption(const char *name, PK_Decryptor &priv, PK_Encryptor &pub
Test::GlobalRNG().GenerateBlock(plaintext, len);
pub.Encrypt(Test::GlobalRNG(), plaintext, len, ciphertext);
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
priv.Decrypt(Test::GlobalRNG(), ciphertext, ciphertext.size(), plaintext);
OutputResultOperations(name, "Decryption", false, i, timeTaken);
@ -84,11 +79,12 @@ void BenchMarkSigning(const char *name, PK_Signer &key, double timeTotal, bool p
AlignedSecByteBlock message(len), signature(key.SignatureLength());
Test::GlobalRNG().GenerateBlock(message, len);
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
key.SignMessage(Test::GlobalRNG(), message, len, signature);
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
(void)key.SignMessage(Test::GlobalRNG(), message, len, signature);
OutputResultOperations(name, "Signature", pc, i, timeTaken);
@ -106,15 +102,12 @@ void BenchMarkVerification(const char *name, const PK_Signer &priv, PK_Verifier
Test::GlobalRNG().GenerateBlock(message, len);
priv.SignMessage(Test::GlobalRNG(), message, len, signature);
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
{
// The return value is ignored because we are interested in throughput
bool unused = pub.VerifyMessage(message, len, signature, signature.size());
CRYPTOPP_UNUSED(unused);
}
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
(void)pub.VerifyMessage(message, len, signature, signature.size());
OutputResultOperations(name, "Verification", pc, i, timeTaken);
@ -129,10 +122,11 @@ void BenchMarkKeyGen(const char *name, SimpleKeyAgreementDomain &d, double timeT
{
SecByteBlock priv(d.PrivateKeyLength()), pub(d.PublicKeyLength());
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
d.GenerateKeyPair(Test::GlobalRNG(), priv, pub);
OutputResultOperations(name, "Key-Pair Generation", pc, i, timeTaken);
@ -148,10 +142,11 @@ void BenchMarkKeyGen(const char *name, AuthenticatedKeyAgreementDomain &d, doubl
{
SecByteBlock priv(d.EphemeralPrivateKeyLength()), pub(d.EphemeralPublicKeyLength());
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i++)
d.GenerateEphemeralKeyPair(Test::GlobalRNG(), priv, pub);
OutputResultOperations(name, "Key-Pair Generation", pc, i, timeTaken);
@ -171,10 +166,11 @@ void BenchMarkAgreement(const char *name, SimpleKeyAgreementDomain &d, double ti
d.GenerateKeyPair(Test::GlobalRNG(), priv2, pub2);
SecByteBlock val(d.AgreedValueLength());
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2)
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2)
{
d.Agree(val, priv1, pub2);
d.Agree(val, priv2, pub1);
@ -195,10 +191,11 @@ void BenchMarkAgreement(const char *name, AuthenticatedKeyAgreementDomain &d, do
d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv2, epub2);
SecByteBlock val(d.AgreedValueLength());
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2)
const clock_t start = ::clock();
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2)
{
d.Agree(val, spriv1, epriv1, spub2, epub2);
d.Agree(val, spriv2, epriv2, spub1, epub1);
@ -207,36 +204,10 @@ void BenchMarkAgreement(const char *name, AuthenticatedKeyAgreementDomain &d, do
OutputResultOperations(name, "Key Agreement", pc, i, timeTaken);
}
#if 0
void BenchMarkAgreement(const char *name, AuthenticatedKeyAgreementDomainWithRoles &d, double timeTotal, bool pc=false)
{
SecByteBlock spriv1(d.StaticPrivateKeyLength()), spriv2(d.StaticPrivateKeyLength());
SecByteBlock epriv1(d.EphemeralPrivateKeyLength()), epriv2(d.EphemeralPrivateKeyLength());
SecByteBlock spub1(d.StaticPublicKeyLength()), spub2(d.StaticPublicKeyLength());
SecByteBlock epub1(d.EphemeralPublicKeyLength()), epub2(d.EphemeralPublicKeyLength());
d.GenerateStaticKeyPair(Test::GlobalRNG(), spriv1, spub1);
d.GenerateStaticKeyPair(Test::GlobalRNG(), spriv2, spub2);
d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv1, epub1);
d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv2, epub2);
SecByteBlock val(d.AgreedValueLength());
const clock_t start = clock();
unsigned int i;
double timeTaken;
for (timeTaken=(double)0, i=0; timeTaken < timeTotal; timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND, i+=2)
{
d.Agree(val, spriv1, epriv1, spub2, epub2);
d.Agree(val, spriv2, epriv2, spub1, epub1);
}
OutputResultOperations(name, "Key Agreement", pc, i, timeTaken);
}
#endif
template <class SCHEME>
void BenchMarkCrypto(const char *filename, const char *name, double timeTotal)
{
FileSource f(filename, true, new HexDecoder());
FileSource f(filename, true, new HexDecoder);
typename SCHEME::Decryptor priv(f);
typename SCHEME::Encryptor pub(priv);
BenchMarkEncryption(name, pub, timeTotal);
@ -246,7 +217,7 @@ void BenchMarkCrypto(const char *filename, const char *name, double timeTotal)
template <class SCHEME>
void BenchMarkSignature(const char *filename, const char *name, double timeTotal)
{
FileSource f(filename, true, new HexDecoder());
FileSource f(filename, true, new HexDecoder);
typename SCHEME::Signer priv(f);
typename SCHEME::Verifier pub(priv);
BenchMarkSigning(name, priv, timeTotal);
@ -256,34 +227,41 @@ void BenchMarkSignature(const char *filename, const char *name, double timeTotal
template <class D>
void BenchMarkKeyAgreement(const char *filename, const char *name, double timeTotal)
{
FileSource f(filename, true, new HexDecoder());
FileSource f(filename, true, new HexDecoder);
D d(f);
BenchMarkKeyGen(name, d, timeTotal);
BenchMarkAgreement(name, d, timeTotal);
}
extern double g_hertz;
void BenchmarkAll2(double t, double hertz)
void Benchmark3(double t, double hertz)
{
g_allocatedTime = t;
g_hertz = hertz;
std::cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right>" << std::endl;
std::cout << "<THEAD><TR><TH>Operation<TH>Milliseconds/Operation" << (g_hertz ? "<TH>Megacycles/Operation" : "") << std::endl;
std::cout << "\n<TABLE style=\"border:1px solid\">";
std::cout << "\n<COLGROUP><COL style=\"text-align: left;\"><COL style=";
std::cout << "\"text-align: right;\"><COL style=\"text-align: right;\">";
std::cout << "\n<THEAD style=\"background: #F0F0F0\"><TR><TH>Operation<TH>Milliseconds/Operation";
std::cout << (g_hertz > 1.0f ? "<TH>Megacycles/Operation" : "") << std::endl;
std::cout << "\n<TBODY style=\"background: yellow\">";
std::cout << "\n<TBODY style=\"background: white;\">";
{
BenchMarkCrypto<RSAES<OAEP<SHA> > >(CRYPTOPP_DATA_DIR "TestData/rsa1024.dat", "RSA 1024", t);
BenchMarkCrypto<LUCES<OAEP<SHA> > >(CRYPTOPP_DATA_DIR "TestData/luc1024.dat", "LUC 1024", t);
BenchMarkCrypto<DLIES<> >(CRYPTOPP_DATA_DIR "TestData/dlie1024.dat", "DLIES 1024", t);
BenchMarkCrypto<LUC_IES<> >(CRYPTOPP_DATA_DIR "TestData/lucc512.dat", "LUCELG 512", t);
}
std::cout << "\n<TBODY style=\"background: white\">";
std::cout << "\n<TBODY style=\"background: yellow;\">";
{
BenchMarkCrypto<RSAES<OAEP<SHA> > >(CRYPTOPP_DATA_DIR "TestData/rsa2048.dat", "RSA 2048", t);
BenchMarkCrypto<LUCES<OAEP<SHA> > >(CRYPTOPP_DATA_DIR "TestData/luc2048.dat", "LUC 2048", t);
BenchMarkCrypto<DLIES<> >(CRYPTOPP_DATA_DIR "TestData/dlie2048.dat", "DLIES 2048", t);
BenchMarkCrypto<LUC_IES<> >(CRYPTOPP_DATA_DIR "TestData/lucc1024.dat", "LUCELG 1024", t);
}
std::cout << "\n<TBODY style=\"background: yellow\">";
std::cout << "\n<TBODY style=\"background: white;\">";
{
BenchMarkSignature<RSASS<PSSR, SHA> >(CRYPTOPP_DATA_DIR "TestData/rsa1024.dat", "RSA 1024", t);
BenchMarkSignature<RWSS<PSSR, SHA> >(CRYPTOPP_DATA_DIR "TestData/rw1024.dat", "RW 1024", t);
BenchMarkSignature<LUCSS<PSSR, SHA> >(CRYPTOPP_DATA_DIR "TestData/luc1024.dat", "LUC 1024", t);
@ -292,16 +270,20 @@ void BenchmarkAll2(double t, double hertz)
BenchMarkSignature<LUC_HMP<SHA> >(CRYPTOPP_DATA_DIR "TestData/lucs512.dat", "LUC-HMP 512", t);
BenchMarkSignature<ESIGN<SHA> >(CRYPTOPP_DATA_DIR "TestData/esig1023.dat", "ESIGN 1023", t);
BenchMarkSignature<ESIGN<SHA> >(CRYPTOPP_DATA_DIR "TestData/esig1536.dat", "ESIGN 1536", t);
}
std::cout << "\n<TBODY style=\"background: white\">";
std::cout << "\n<TBODY style=\"background: yellow;\">";
{
BenchMarkSignature<RSASS<PSSR, SHA> >(CRYPTOPP_DATA_DIR "TestData/rsa2048.dat", "RSA 2048", t);
BenchMarkSignature<RWSS<PSSR, SHA> >(CRYPTOPP_DATA_DIR "TestData/rw2048.dat", "RW 2048", t);
BenchMarkSignature<LUCSS<PSSR, SHA> >(CRYPTOPP_DATA_DIR "TestData/luc2048.dat", "LUC 2048", t);
BenchMarkSignature<NR<SHA> >(CRYPTOPP_DATA_DIR "TestData/nr2048.dat", "NR 2048", t);
BenchMarkSignature<LUC_HMP<SHA> >(CRYPTOPP_DATA_DIR "TestData/lucs1024.dat", "LUC-HMP 1024", t);
BenchMarkSignature<ESIGN<SHA> >(CRYPTOPP_DATA_DIR "TestData/esig2046.dat", "ESIGN 2046", t);
}
std::cout << "\n<TBODY style=\"background: yellow\">";
std::cout << "\n<TBODY style=\"background: white;\">";
{
BenchMarkKeyAgreement<XTR_DH>(CRYPTOPP_DATA_DIR "TestData/xtrdh171.dat", "XTR-DH 171", t);
BenchMarkKeyAgreement<XTR_DH>(CRYPTOPP_DATA_DIR "TestData/xtrdh342.dat", "XTR-DH 342", t);
BenchMarkKeyAgreement<DH>(CRYPTOPP_DATA_DIR "TestData/dh1024.dat", "DH 1024", t);
@ -322,8 +304,9 @@ void BenchmarkAll2(double t, double hertz)
BenchMarkKeyAgreement<ECFHMQV384>(CRYPTOPP_DATA_DIR "TestData/fhmqv384.dat", "FHMQV P-384", t);
BenchMarkKeyAgreement<ECFHMQV512>(CRYPTOPP_DATA_DIR "TestData/fhmqv512.dat", "FHMQV P-512", t);
#endif
}
std::cout << "\n<TBODY style=\"background: white\">";
std::cout << "\n<TBODY style=\"background: yellow;\">";
{
ECIES<ECP>::Decryptor cpriv(Test::GlobalRNG(), ASN1::secp256k1());
ECIES<ECP>::Encryptor cpub(cpriv);
@ -350,7 +333,7 @@ void BenchmarkAll2(double t, double hertz)
BenchMarkAgreement("ECMQVC over GF(p) 256", ecmqvc, t);
}
std::cout << "<TBODY style=\"background: yellow\">" << std::endl;
std::cout << "\n<TBODY style=\"background: white;\">";
{
ECIES<EC2N>::Decryptor cpriv(Test::GlobalRNG(), ASN1::sect233r1());
ECIES<EC2N>::Encryptor cpub(cpriv);
@ -376,7 +359,8 @@ void BenchmarkAll2(double t, double hertz)
BenchMarkKeyGen("ECMQVC over GF(2^n) 233", ecmqvc, t);
BenchMarkAgreement("ECMQVC over GF(2^n) 233", ecmqvc, t);
}
std::cout << "</TABLE>" << std::endl;
std::cout << "\n</TABLE>" << std::endl;
}
NAMESPACE_END // Test

60
drbg.h
View File

@ -45,9 +45,10 @@ public:
//! \param input the entropy to add to the generator
//! \param length the size of the input buffer
//! \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy
//! \details NIST instantiation and reseed requirements demand the generator is constructed with at least <tt>MINIMUM_ENTROPY</tt>
//! entropy. The byte array for <tt>input</tt> must meet <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST
//! SP 800-90B or SP 800-90C</A> requirements.
//! \details NIST instantiation and reseed requirements demand the generator is constructed
//! with at least <tt>MINIMUM_ENTROPY</tt> entropy. The byte array for <tt>input</tt> must
//! meet <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
//! SP 800-90C</A> requirements.
virtual void IncorporateEntropy(const byte *input, size_t length)=0;
//! \brief Update RNG state with additional unpredictable values
@ -56,10 +57,11 @@ public:
//! \param additional additional input to add to the generator
//! \param additionaLength the size of the additional input buffer
//! \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy
//! \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST instantiation and
//! reseed requirements demand the generator is constructed with at least <tt>MINIMUM_ENTROPY</tt> entropy.
//! The byte array for <tt>entropy</tt> must meet <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST
//! SP 800-90B or SP 800-90C</A> requirements.
//! \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST
//! instantiation and reseed requirements demand the generator is constructed with at least
//! <tt>MINIMUM_ENTROPY</tt> entropy. The byte array for <tt>entropy</tt> must meet
//! <A HREF ="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
//!! SP 800-90C</A> requirements.
virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0;
//! \brief Generate random array of bytes
@ -76,8 +78,9 @@ public:
//! \param size the length of the buffer, in bytes
//! \throws NIST_DRBG::Err if a reseed is required
//! \throws NIST_DRBG::Err if the size exceeds <tt>MAXIMUM_BYTES_PER_REQUEST</tt>
//! \details GenerateBlock() is an overload provided to match NIST requirements. The byte array for <tt>additional</tt>
//! input is optional. If present the additional randomness is mixed before generating the output bytes.
//! \details GenerateBlock() is an overload provided to match NIST requirements. The byte
//! array for <tt>additional</tt> input is optional. If present the additional randomness
//! is mixed before generating the output bytes.
virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0;
//! \brief Provides the security strength
@ -93,31 +96,33 @@ public:
//! \brief Provides the minimum entropy size
//! \returns The minimum entropy size required by the generator, in bytes
//! \details The equivalent class constant is <tt>MINIMUM_ENTROPY</tt>. All NIST DRBGs must be instaniated with at least
//! <tt>MINIMUM_ENTROPY</tt> bytes of entropy. The bytes must meet <A
//! HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or SP 800-90C</A> requirements.
//! \details The equivalent class constant is <tt>MINIMUM_ENTROPY</tt>. All NIST DRBGs must
//! be instaniated with at least <tt>MINIMUM_ENTROPY</tt> bytes of entropy. The bytes must
//! meet <A HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
//! SP 800-90C</A> requirements.
virtual unsigned int GetMinEntropy() const=0;
//! \brief Provides the maximum entropy size
//! \returns The maximum entropy size that can be consumed by the generator, in bytes
//! \details The equivalent class constant is <tt>MAXIMUM_ENTROPY</tt>. The bytes must meet <A
//! HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or SP 800-90C</A> requirements.
//! <tt>MAXIMUM_ENTROPY</tt> has been reduced from 2<sup>35</sup> to <tt>INT_MAX</tt> to fit the underlying C++ datatype.
//! \details The equivalent class constant is <tt>MAXIMUM_ENTROPY</tt>. The bytes must
//! meet <A HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90B or
//! SP 800-90C</A> requirements. <tt>MAXIMUM_ENTROPY</tt> has been reduced from
//! 2<sup>35</sup> to <tt>INT_MAX</tt> to fit the underlying C++ datatype.
virtual unsigned int GetMaxEntropy() const=0;
//! \brief Provides the minimum nonce size
//! \returns The minimum nonce size recommended for the generator, in bytes
//! \details The equivalent class constant is <tt>MINIMUM_NONCE</tt>. If a nonce is not required then
//! <tt>MINIMUM_NONCE</tt> is 0. <tt>Hash_DRBG</tt> does not require a nonce, while <tt>HMAC_DRBG</tt>
//! and <tt>CTR_DRBG</tt> require a nonce.
//! \details The equivalent class constant is <tt>MINIMUM_NONCE</tt>. If a nonce is not
//! required then <tt>MINIMUM_NONCE</tt> is 0. <tt>Hash_DRBG</tt> does not require a
//! nonce, while <tt>HMAC_DRBG</tt> and <tt>CTR_DRBG</tt> require a nonce.
virtual unsigned int GetMinNonce() const=0;
//! \brief Provides the maximum nonce size
//! \returns The maximum nonce that can be consumed by the generator, in bytes
//! \details The equivalent class constant is <tt>MAXIMUM_NONCE</tt>. <tt>MAXIMUM_NONCE</tt> has been reduced from
//! 2<sup>35</sup> to <tt>INT_MAX</tt> to fit the underlying C++ datatype. If a nonce is not required then
//! <tt>MINIMUM_NONCE</tt> is 0. <tt>Hash_DRBG</tt> does not require a nonce, while <tt>HMAC_DRBG</tt>
//! and <tt>CTR_DRBG</tt> require a nonce.
//! \details The equivalent class constant is <tt>MAXIMUM_NONCE</tt>. <tt>MAXIMUM_NONCE</tt>
//! has been reduced from 2<sup>35</sup> to <tt>INT_MAX</tt> to fit the underlying C++ datatype.
//! If a nonce is not required then <tt>MINIMUM_NONCE</tt> is 0. <tt>Hash_DRBG</tt> does not
//! require a nonce, while <tt>HMAC_DRBG</tt> and <tt>CTR_DRBG</tt> require a nonce.
virtual unsigned int GetMaxNonce() const=0;
//! \brief Provides the maximum size of a request to GenerateBlock
@ -150,8 +155,9 @@ protected:
//! Security Strength and Seed Length, depend on the hash and are specified as template parameters.
//! The remaining parameters are included in the class. The parameters and their values are listed
//! in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38).
//! \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto 2<sup>48</sup> requests
//! before a reseed. However, Hash_DRBG limits it to <tt>INT_MAX</tt> due to the limited data range of an int.
//! \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto
//! 2<sup>48</sup> requests before a reseed. However, Hash_DRBG limits it to <tt>INT_MAX</tt> due
//! to the limited data range of an int.
//! \sa <A HREF="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">Recommendation
//! for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015)</A>
//! \since Crypto++ 6.0
@ -199,10 +205,11 @@ public:
//! Hash_DRBG<SHA256, 128/8, 440/8> drbg(entropy, 32, entropy+32, 16);
//! drbg.GenerateBlock(result, result.size());
//! </pre>
Hash_DRBG(const byte* entropy, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR,
Hash_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR,
size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0)
: NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH)
{
if (entropy != NULLPTR && entropyLength != 0)
DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
}
@ -312,10 +319,11 @@ public:
//! HMAC_DRBG<SHA256, 128/8, 440/8> drbg(entropy, 32, entropy+32, 16);
//! drbg.GenerateBlock(result, result.size());
//! </pre>
HMAC_DRBG(const byte* entropy, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR,
HMAC_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR,
size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0)
: NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE)
{
if (entropy != NULLPTR && entropyLength != 0)
DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
}

View File

@ -30,7 +30,7 @@ template <unsigned int K, unsigned int M, unsigned int N, unsigned int F, unsign
class MersenneTwister : public RandomNumberGenerator
{
public:
CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "MT19937"; }
CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return (S==5489 ? "MT19937ar" : (S==4537 ? "MT19937" : "MT19937")); }
~MersenneTwister() {}

View File

@ -4,6 +4,7 @@
#include "cryptlib.h"
#include "factory.h"
#include "cpu.h"
#include "modes.h"
#include "dh.h"
#include "esign.h"
@ -57,15 +58,16 @@
#include "hkdf.h"
#include "siphash.h"
#include "osrng.h"
#include "drbg.h"
#include "mersenne.h"
#include "rdrand.h"
// Aggressive stack checking with VS2005 SP1 and above.
#if (CRYPTOPP_MSC_VERSION >= 1410)
# pragma strict_gs_check (on)
#endif
#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
USING_NAMESPACE(CryptoPP)
void RegisterFactories()
@ -191,5 +193,25 @@ void RegisterFactories()
RegisterDefaultFactoryFor<KeyDerivationFunction, HKDF<SHA512> >();
RegisterDefaultFactoryFor<KeyDerivationFunction, HKDF<Whirlpool> >();
#ifdef BLOCKING_RNG_AVAILABLE
RegisterDefaultFactoryFor<RandomNumberGenerator, BlockingRng>();
#endif
#ifdef NONBLOCKING_RNG_AVAILABLE
RegisterDefaultFactoryFor<RandomNumberGenerator, NonblockingRng>();
#endif
#ifdef OS_RNG_AVAILABLE
RegisterDefaultFactoryFor<RandomNumberGenerator, AutoSeededRandomPool>();
RegisterDefaultFactoryFor<RandomNumberGenerator, AutoSeededX917RNG<AES> >();
#endif
RegisterDefaultFactoryFor<RandomNumberGenerator, MT19937>();
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
if (HasRDRAND())
RegisterDefaultFactoryFor<RandomNumberGenerator, RDRAND>();
if (HasRDSEED())
RegisterDefaultFactoryFor<RandomNumberGenerator, RDSEED>();
#endif
RegisterDefaultFactoryFor<NIST_DRBG, Hash_DRBG<SHA1> >("Hash_DRBG(SHA1)");
RegisterDefaultFactoryFor<NIST_DRBG, HMAC_DRBG<SHA1> >("HMAC_DRBG(SHA1)");
s_registered = true;
}

12
rng.cpp
View File

@ -5,8 +5,8 @@
#include "rng.h"
#include "fips140.h"
#include <time.h>
#include <math.h>
#include <ctime>
#include <cmath>
NAMESPACE_BEGIN(CryptoPP)
@ -76,7 +76,7 @@ X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *determini
if (!deterministicTimeVector)
{
time_t tstamp1 = time(NULLPTR);
time_t tstamp1 = std::time(NULLPTR);
xorbuf(m_datetime, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), m_size));
m_cipher->ProcessBlock(m_datetime);
clock_t tstamp2 = clock();
@ -102,7 +102,7 @@ void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target,
{
clock_t c = clock();
xorbuf(m_datetime, (byte *)&c, UnsignedMin(sizeof(c), m_size));
time_t t = time(NULLPTR);
time_t t = std::time(NULLPTR);
xorbuf(m_datetime+m_size-UnsignedMin(sizeof(t), m_size), (byte *)&t, UnsignedMin(sizeof(t), m_size));
m_cipher->ProcessBlock(m_datetime);
}
@ -142,7 +142,7 @@ size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int /*mes
{
byte inByte = *inString++;
if (n >= Q)
sum += log(double(n - tab[inByte]));
sum += std::log(double(n - tab[inByte]));
tab[inByte] = n;
n++;
}
@ -154,7 +154,7 @@ double MaurerRandomnessTest::GetTestValue() const
if (BytesNeeded() > 0)
throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed");
double fTu = (sum/(n-Q))/log(2.0); // this is the test value defined by Maurer
double fTu = (sum/(n-Q))/std::log(2.0); // this is the test value defined by Maurer
double value = fTu * 0.1392; // arbitrarily normalize it to
return value > 1.0 ? 1.0 : value; // a number between 0 and 1

115
test.cpp
View File

@ -22,18 +22,17 @@
#include "whrlpool.h"
#include "tiger.h"
#include "smartptr.h"
#include "stdcpp.h"
#include "ossig.h"
#include "trap.h"
#include "validate.h"
#include "bench.h"
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <locale>
#include <time.h>
#include <ctime>
#ifdef CRYPTOPP_WIN32_AVAILABLE
#define WIN32_LEAN_AND_MEAN
@ -118,6 +117,43 @@ int (*AdhocTest)(int argc, char *argv[]) = NULLPTR;
NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)
// Coverity finding
template <class T, bool NON_NEGATIVE>
T StringToValue(const std::string& str)
{
std::istringstream iss(str);
// Arbitrary, but we need to clear a Coverity finding TAINTED_SCALAR
if (iss.str().length() > 25)
throw InvalidArgument(str + "' is too long");
T value;
iss >> std::noskipws >> value;
// Use fail(), not bad()
if (iss.fail() || !iss.eof())
throw InvalidArgument(str + "' is not a value");
if (NON_NEGATIVE && value < 0)
throw InvalidArgument(str + "' is negative");
return value;
}
// Coverity finding
template<>
int StringToValue<int, true>(const std::string& str)
{
Integer n(str.c_str());
long l = n.ConvertToLong();
int r;
if (!SafeConvert(l, r))
throw InvalidArgument(str + "' is not an integer value");
return r;
}
ANONYMOUS_NAMESPACE_BEGIN
OFB_Mode<AES>::Encryption s_globalRNG;
NAMESPACE_END
@ -367,10 +403,14 @@ int CRYPTOPP_API main(int argc, char *argv[])
InformationRecoverFile(argc-3, argv[2], argv+3);
else if (command == "v" || command == "vv")
return !Validate(argc>2 ? Test::StringToValue<int, true>(argv[2]) : 0, argv[1][1] == 'v', argc>3 ? argv[3] : NULLPTR);
else if (command == "b")
Test::BenchmarkAll(argc<3 ? 1 : Test::StringToValue<float, true>(argv[2]), argc<4 ? 0.0f : Test::StringToValue<float, true>(argv[3])*1e9);
else if (command == "b2")
Test::BenchmarkAll2(argc<3 ? 1 : Test::StringToValue<float, true>(argv[2]), argc<4 ? 0.0f : Test::StringToValue<float, true>(argv[3])*1e9);
else if (command == "b") // All benchmarks
Test::Benchmark(7, argc<3 ? 1 : Test::StringToValue<float, true>(argv[2]), argc<4 ? 0.0f : Test::StringToValue<float, true>(argv[3])*1e9);
else if (command == "b3") // Public key algorithms
Test::Benchmark(4, argc<3 ? 1 : Test::StringToValue<float, true>(argv[2]), argc<4 ? 0.0f : Test::StringToValue<float, true>(argv[3])*1e9);
else if (command == "b2") // Shared key algorithms
Test::Benchmark(2, argc<3 ? 1 : Test::StringToValue<float, true>(argv[2]), argc<4 ? 0.0f : Test::StringToValue<float, true>(argv[3])*1e9);
else if (command == "b1") // Unkeyed algorithms
Test::Benchmark(1, argc<3 ? 1 : Test::StringToValue<float, true>(argv[2]), argc<4 ? 0.0f : Test::StringToValue<float, true>(argv[3])*1e9);
else if (command == "z")
GzipFile(argv[3], argv[4], argv[2][0]-'0');
else if (command == "u")
@ -437,41 +477,6 @@ void FIPS140_GenerateRandomFiles()
#endif
}
template <class T, bool NON_NEGATIVE>
T Test::StringToValue(const std::string& str)
{
std::istringstream iss(str);
// Arbitrary, but we need to clear a Coverity finding TAINTED_SCALAR
if(iss.str().length() > 25)
throw InvalidArgument("cryptest.exe: '" + str +"' is too long");
T value;
iss >> std::noskipws >> value;
// Use fail(), not bad()
if (iss.fail() || !iss.eof())
throw InvalidArgument("cryptest.exe: '" + str +"' is not a value");
if (NON_NEGATIVE && value < 0)
throw InvalidArgument("cryptest.exe: '" + str +"' is negative");
return value;
}
template<>
int Test::StringToValue<int, true>(const std::string& str)
{
Integer n(str.c_str());
long l = n.ConvertToLong();
int r;
if(!SafeConvert(l, r))
throw InvalidArgument("cryptest.exe: '" + str +"' is not an integer value");
return r;
}
void PrintSeedAndThreads(const std::string& seed)
{
std::cout << "Using seed: " << seed << std::endl;
@ -893,12 +898,12 @@ bool Validate(int alg, bool thorough, const char *seedInput)
// Some editors have problems with the '\0' character when redirecting output.
// seedInput is argv[3] when issuing 'cryptest.exe v all <seed>'
std::string seed = (seedInput ? seedInput : IntToString(time(NULLPTR)));
std::string seed = (seedInput ? seedInput : IntToString(std::time(NULLPTR)));
seed.resize(16, ' ');
OFB_Mode<AES>::Encryption& prng = dynamic_cast<OFB_Mode<AES>::Encryption&>(Test::GlobalRNG());
prng.SetKeyWithIV((byte *)seed.data(), 16, (byte *)seed.data());
Test::g_testBegin = std::time(NULLPTR);
PrintSeedAndThreads(seed);
switch (alg)
@ -1001,25 +1006,11 @@ bool Validate(int alg, bool thorough, const char *seedInput)
default: return false;
}
// Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
#if (CRYPTOPP_MSC_VERSION >= 1400)
tm localTime = {};
char timeBuf[64];
errno_t err;
Test::g_testEnd = std::time(NULLPTR);
const time_t endTime = time(NULLPTR);
err = localtime_s(&localTime, &endTime);
CRYPTOPP_ASSERT(err == 0);
err = asctime_s(timeBuf, sizeof(timeBuf), &localTime);
CRYPTOPP_ASSERT(err == 0);
std::cout << "\nTest ended at " << timeBuf;
#else
const time_t endTime = time(NULLPTR);
std::cout << "\nTest ended at " << asctime(localtime(&endTime));
#endif
std::cout << "Seed used was: " << seed << std::endl;
std::cout << "\nSeed used was " << seed << std::endl;
std::cout << "Test started at " << Test::TimeToString(Test::g_testBegin) << std::endl;
std::cout << "Test ended at " << Test::TimeToString(Test::g_testEnd) << std::endl;
return result;
}