Add VIA Padlock RNG

This commit is contained in:
Jeffrey Walton 2017-08-19 15:41:45 -04:00
parent 65a96fe983
commit 7fb5953055
No known key found for this signature in database
GPG Key ID: B36AB348921B1838
9 changed files with 282 additions and 0 deletions

View File

@ -191,6 +191,8 @@ oids.h
osrng.cpp
osrng.h
ossig.h
padlkrng.cpp
padlkrng.h
panama.cpp
panama.h
pch.cpp

View File

@ -15,6 +15,8 @@
#include "smartptr.h"
#include "cpu.h"
#include "drbg.h"
#include "rdrand.h"
#include "padlkrng.h"
#if CRYPTOPP_MSC_VERSION
# pragma warning(disable: 4355)
@ -439,6 +441,10 @@ void Benchmark1(double t, double hertz)
BenchMarkByNameKeyLess<RandomNumberGenerator>("AutoSeededX917RNG(AES)");
#endif
BenchMarkByNameKeyLess<RandomNumberGenerator>("MT19937");
#if (CRYPTOPP_BOOL_X86)
if (HasPadlockRNG())
BenchMarkByNameKeyLess<RandomNumberGenerator>("PadlockRNG");
#endif
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
if (HasRDRAND())
BenchMarkByNameKeyLess<RandomNumberGenerator>("RDRAND");

View File

@ -252,6 +252,7 @@
<ClCompile Include="network.cpp" />
<ClCompile Include="oaep.cpp" />
<ClCompile Include="osrng.cpp" />
<ClCompile Include="padlkrng.cpp" />
<ClCompile Include="panama.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
@ -434,6 +435,7 @@
<ClInclude Include="oaep.h" />
<ClInclude Include="oids.h" />
<ClInclude Include="osrng.h" />
<ClInclude Include="padlkrng.h" />
<ClInclude Include="panama.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="pkcspad.h" />

View File

@ -257,6 +257,9 @@
<ClCompile Include="osrng.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="padlkrng.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="panama.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -699,6 +702,9 @@
<ClInclude Include="osrng.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="padlkrng.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="panama.h">
<Filter>Header Files</Filter>
</ClInclude>

86
padlkrng.cpp Normal file
View File

@ -0,0 +1,86 @@
// via-rng.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
#include "pch.h"
#include "config.h"
#include "cryptlib.h"
#include "secblock.h"
#include "padlkrng.h"
#include "cpu.h"
NAMESPACE_BEGIN(CryptoPP)
PadlockRNG::PadlockRNG()
{
#if CRYPTOPP_BOOL_X86
if (!HasPadlockRNG())
throw PadlockRNG_Err("HasPadlockRNG");
#else
throw PadlockRNG_Err("HasPadlockRNG");
#endif
}
void PadlockRNG::GenerateBlock(byte *output, size_t size)
{
CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
#if CRYPTOPP_BOOL_X86
while (size)
{
# if defined(__GNUC__)
word32 result;
__asm__ __volatile__
(
"movl %1, %%edi ;\n"
"movl $1, %%edx ;\n"
".byte 0x0f, 0xa7, 0xc0 ;\n"
"andl $31, %%eax ;\n"
"movl %%eax, %0 ;\n"
: "=g" (result) : "g" (m_buffer.begin()) : "eax", "edx", "edi", "cc"
);
const size_t rem = STDMIN(result, STDMIN(size, m_buffer.SizeInBytes()));
std::memcpy(output, m_buffer, rem);
size -= rem; output += rem;
# elif defined(_MSC_VER)
word32 result;
byte* buffer = reinterpret_cast<byte*>(m_buffer.begin());
__asm {
mov edi, buffer
mov edx, 0x01
_emit 0x0f
_emit 0xa7
_emit 0xc0
and eax, 31
mov result, eax
}
const size_t rem = STDMIN(result, STDMIN(size, m_buffer.SizeInBytes()));
std::memcpy(output, m_buffer, rem);
size -= rem; output += rem;
# else
throw NotImplemented("PadlockRNG::GenerateBlock");
# endif
}
#endif // CRYPTOPP_BOOL_X86
}
void PadlockRNG::DiscardBytes(size_t n)
{
FixedSizeSecBlock<word32, 4> discard;
n = RoundUpToMultipleOf(n, sizeof(word32));
size_t count = STDMIN(n, discard.SizeInBytes());
while (count)
{
GenerateBlock(discard.BytePtr(), count);
n -= count;
count = STDMIN(n, discard.SizeInBytes());
}
}
NAMESPACE_END

70
padlkrng.h Normal file
View File

@ -0,0 +1,70 @@
// via-rng.h - written and placed in public domain by Jeffrey Walton
//! \file PadlockRNG.h
//! \brief Class for VIA Padlock RNG
//! \since Crypto++ 6.0
#ifndef CRYPTOPP_PADLOCK_RNG_H
#define CRYPTOPP_PADLOCK_RNG_H
#include "cryptlib.h"
#include "secblock.h"
NAMESPACE_BEGIN(CryptoPP)
//! \brief Exception thrown when a PadlockRNG generator encounters
//! a generator related error.
//! \since Crypto++ 6.0
class PadlockRNG_Err : public Exception
{
public:
PadlockRNG_Err(const std::string &operation)
: Exception(OTHER_ERROR, "PadlockRNG: " + operation + " operation failed") {}
};
//! \brief Hardware generated random numbers using PadlockRNG instruction
//! \sa MaurerRandomnessTest() for random bit generators
//! \since Crypto++ 6.0
class PadlockRNG : public RandomNumberGenerator
{
public:
CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "PadlockRNG"; }
virtual ~PadlockRNG() {}
//! \brief Construct a PadlockRNG generator
//! \details According to DJ of Intel, the Intel PadlockRNG circuit does not underflow.
//! If it did hypothetically underflow, then it would return 0 for the random value.
//! AMD's PadlockRNG implementation appears to provide the same behavior.
//! \throws PadlockRNG_Err if the random number generator is not available
PadlockRNG();
//! \brief Generate random array of bytes
//! \param output the byte buffer
//! \param size the length of the buffer, in bytes
virtual void GenerateBlock(byte *output, size_t size);
//! \brief Generate and discard n bytes
//! \param n the number of bytes to generate and discard
//! \details the RDSEED generator discards words, not bytes. If n is
//! not a multiple of a machine word, then it is rounded up to
//! that size.
virtual void DiscardBytes(size_t n);
//! \brief Update RNG state with additional unpredictable values
//! \param input unused
//! \param length unused
//! \details The operation is a nop for this generator.
virtual void IncorporateEntropy(const byte *input, size_t length)
{
// Override to avoid the base class' throw.
CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
}
private:
FixedSizeAlignedSecBlock<word32, 1, true> m_buffer;
};
NAMESPACE_END
#endif // CRYPTOPP_PADLOCK_RNG_H

View File

@ -25,6 +25,7 @@
#include "drbg.h"
#include "mersenne.h"
#include "rdrand.h"
#include "padlkrng.h"
#include "modes.h"
#include "aes.h"
@ -109,6 +110,10 @@ void RegisterFactories1()
RegisterDefaultFactoryFor<RandomNumberGenerator, AutoSeededX917RNG<AES> >();
#endif
RegisterDefaultFactoryFor<RandomNumberGenerator, MT19937>();
#if (CRYPTOPP_BOOL_X86)
if (HasPadlockRNG())
RegisterDefaultFactoryFor<RandomNumberGenerator, PadlockRNG>();
#endif
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
if (HasRDRAND())
RegisterDefaultFactoryFor<RandomNumberGenerator, RDRAND>();

View File

@ -45,6 +45,7 @@
#include "osrng.h"
#include "drbg.h"
#include "rdrand.h"
#include "padlkrng.h"
#include "mersenne.h"
#include "randpool.h"
#include "zdeflate.h"
@ -84,6 +85,7 @@ bool ValidateAll(bool thorough)
pass=TestMersenne() && pass;
#endif
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
pass=TestPadlockRNG() && pass;
pass=TestRDRAND() && pass;
pass=TestRDSEED() && pass;
#endif
@ -1043,6 +1045,108 @@ bool TestMersenne()
#endif
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
bool TestPadlockRNG()
{
std::cout << "\nTesting Padlock RNG generator...\n\n";
bool pass = true, fail = false;
member_ptr<RandomNumberGenerator> rng;
try {rng.reset(new PadlockRNG);}
catch (const PadlockRNG_Err &) {}
if (rng.get())
{
PadlockRNG& padlock = dynamic_cast<PadlockRNG&>(*rng.get());
static const unsigned int SIZE = 10000;
MeterFilter meter(new Redirector(TheBitBucket()));
Deflator deflator(new Redirector(meter));
MaurerRandomnessTest maurer;
ChannelSwitch chsw;
chsw.AddDefaultRoute(deflator);
chsw.AddDefaultRoute(maurer);
RandomNumberSource rns(padlock, SIZE, true, new Redirector(chsw));
deflator.Flush(true);
CRYPTOPP_ASSERT(0 == maurer.BytesNeeded());
const double mv = maurer.GetTestValue();
if (mv < 0.98f)
fail = true;
// Coverity finding, also see http://stackoverflow.com/a/34509163/608639.
StreamState ss(std::cout);
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(6);
pass &= !fail;
if (fail)
std::cout << "FAILED:";
else
std::cout << "passed:";
std::cout << " Maurer Randomness Test returned value " << mv << "\n";
fail = false;
if (meter.GetTotalBytes() < SIZE)
fail = true;
pass &= !fail;
if (fail)
std::cout << "FAILED:";
else
std::cout << "passed:";
std::cout << " " << SIZE << " generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";
try
{
fail = false;
padlock.DiscardBytes(SIZE);
}
catch (const Exception&)
{
fail = true;
}
pass &= !fail;
if (fail)
std::cout << "FAILED:";
else
std::cout << "passed:";
std::cout << " discarded " << SIZE << " bytes\n";
try
{
// Miscellaneous for code coverage
(void)padlock.AlgorithmName();
(void)padlock.CanIncorporateEntropy();
padlock.IncorporateEntropy(NULLPTR, 0);
word32 result = padlock.GenerateWord32();
result = padlock.GenerateWord32((result & 0xff), 0xffffffff - (result & 0xff));
padlock.GenerateBlock(reinterpret_cast<byte*>(&result), 4);
padlock.GenerateBlock(reinterpret_cast<byte*>(&result), 3);
padlock.GenerateBlock(reinterpret_cast<byte*>(&result), 2);
padlock.GenerateBlock(reinterpret_cast<byte*>(&result), 1);
fail = false;
}
catch (const Exception&)
{
fail = true;
}
pass &= !fail;
if (fail)
std::cout << "FAILED:";
else
std::cout << "passed:";
std::cout << " GenerateWord32 and Crop\n";
}
else
std::cout << "Padlock RNG generator not available, skipping test.\n";
return pass;
}
bool TestRDRAND()
{
std::cout << "\nTesting RDRAND generator...\n\n";

View File

@ -28,6 +28,7 @@ bool TestAutoSeededX917();
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
bool TestRDRAND();
bool TestRDSEED();
bool TestPadlockRNG();
#endif
bool ValidateBaseCode();
bool ValidateCRC32();