Skip to content

Commit

Permalink
Add VIA Padlock RNG
Browse files Browse the repository at this point in the history
  • Loading branch information
noloader committed Aug 19, 2017
1 parent 65a96fe commit 7fb5953
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Filelist.txt
Expand Up @@ -191,6 +191,8 @@ oids.h
osrng.cpp
osrng.h
ossig.h
padlkrng.cpp
padlkrng.h
panama.cpp
panama.h
pch.cpp
Expand Down
6 changes: 6 additions & 0 deletions bench1.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down
2 changes: 2 additions & 0 deletions cryptlib.vcxproj
Expand Up @@ -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>
Expand Down Expand Up @@ -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" />
Expand Down
6 changes: 6 additions & 0 deletions cryptlib.vcxproj.filters
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down
86 changes: 86 additions & 0 deletions padlkrng.cpp
@@ -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 changes: 70 additions & 0 deletions padlkrng.h
@@ -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
5 changes: 5 additions & 0 deletions regtest1.cpp
Expand Up @@ -25,6 +25,7 @@
#include "drbg.h"
#include "mersenne.h"
#include "rdrand.h"
#include "padlkrng.h"

#include "modes.h"
#include "aes.h"
Expand Down Expand Up @@ -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>();
Expand Down
104 changes: 104 additions & 0 deletions validat1.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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";
Expand Down
1 change: 1 addition & 0 deletions validate.h
Expand Up @@ -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();
Expand Down

1 comment on commit 7fb5953

@noloader
Copy link
Collaborator Author

@noloader noloader commented on 7fb5953 Aug 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also see VIA Padlock on the Crypto++ wiki.

Please sign in to comment.