Add Divisor and MSR member variables

Guard ASM based on CRYPTOPP_X86_ASM_AVAILABLE
Increased depth of internal buffer
Update documentation for using the generator
Whitespace check-in
pull/462/head
Jeffrey Walton 2017-08-20 04:09:19 -04:00
parent bc4bb9a952
commit 61c8b74951
No known key found for this signature in database
GPG Key ID: B36AB348921B1838
3 changed files with 132 additions and 71 deletions

View File

@ -461,7 +461,7 @@ NAMESPACE_END
#if !defined(CRYPTOPP_DISABLE_ASM) && ((defined(_MSC_VER) && defined(_M_IX86)) || (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))))
// C++Builder 2010 does not allow "call label" where label is defined within inline assembly
#define CRYPTOPP_X86_ASM_AVAILABLE
#define CRYPTOPP_X86_ASM_AVAILABLE 1
#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__))
#define CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE 1

View File

@ -7,66 +7,67 @@
#include "padlkrng.h"
#include "cpu.h"
// The Padlock Security Engine RNG has a few items to be aware of. You can
// find copies of the Programmer's manual, Cryptography Research Inc audit
// report, and other goodies at http://www.cryptopp.com/wiki/VIA_Padlock.
NAMESPACE_BEGIN(CryptoPP)
PadlockRNG::PadlockRNG()
PadlockRNG::PadlockRNG(word32 divisor)
: m_divisor(DivisorHelper(divisor))
{
#if CRYPTOPP_BOOL_X86
#if CRYPTOPP_X86_ASM_AVAILABLE
if (!HasPadlockRNG())
throw PadlockRNG_Err("HasPadlockRNG");
throw PadlockRNG_Err("PadlockRNG", "PadlockRNG generator not available");
#else
throw PadlockRNG_Err("HasPadlockRNG");
throw PadlockRNG_Err("PadlockRNG", "PadlockRNG generator not available");
#endif
}
void PadlockRNG::GenerateBlock(byte *output, size_t size)
{
CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
#if CRYPTOPP_BOOL_X86
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__GNUC__)
while (size)
{
# if defined(__GNUC__)
word32 result;
__asm__ __volatile__
(
"movl %1, %%edi ;\n"
"movl $1, %%edx ;\n"
"movl $2, %%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"
: "=g" (m_msr) : "g" (m_buffer.data()), "g" (m_divisor)
: "eax", "edx", "edi", "cc"
);
const size_t rem = STDMIN(result, STDMIN(size, m_buffer.SizeInBytes()));
const size_t ret = m_msr & 0x1f;
const size_t rem = STDMIN(ret, STDMIN(size, 16U));
std::memcpy(output, m_buffer, rem);
size -= rem; output += rem;
# elif defined(_MSC_VER)
word32 result;
byte* buffer = reinterpret_cast<byte*>(m_buffer.begin());
}
#elif defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(_MSC_VER)
while (size)
{
word32 result, divisor = m_divisor;
byte *buffer = reinterpret_cast<byte*>(m_buffer.data());
__asm {
mov edi, buffer
mov edx, 0x01
mov edx, divisor
_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);
const size_t ret = (m_msr = result) & 0x1f;
const size_t rem = STDMIN(ret, STDMIN(size, 16U));
std::memcpy(output, buffer, rem);
size -= rem; output += rem;
# else
throw NotImplemented("PadlockRNG::GenerateBlock");
# endif
}
#endif // CRYPTOPP_BOOL_X86
#else
throw PadlockRNG_Err("GenerateBlock", "PadlockRNG generator not available");
#endif // CRYPTOPP_X86_ASM_AVAILABLE
}
void PadlockRNG::DiscardBytes(size_t n)

View File

@ -1,8 +1,10 @@
// via-rng.h - written and placed in public domain by Jeffrey Walton
//! \file PadlockRNG.h
//! \brief Class for VIA Padlock RNG
//! \file padlkrng.h
//! \brief Classes for VIA Padlock RNG
//! \since Crypto++ 6.0
//! \sa <A HREF="http://www.cryptopp.com/wiki/VIA_Padlock">VIA
//! Padlock</A> on the Crypto++ wiki
#ifndef CRYPTOPP_PADLOCK_RNG_H
#define CRYPTOPP_PADLOCK_RNG_H
@ -20,9 +22,26 @@ class PadlockRNG_Err : public Exception
public:
PadlockRNG_Err(const std::string &operation)
: Exception(OTHER_ERROR, "PadlockRNG: " + operation + " operation failed") {}
PadlockRNG_Err(const std::string &component, const std::string &message)
: Exception(OTHER_ERROR, component + ": " + message) {}
};
//! \brief Hardware generated random numbers using PadlockRNG instruction
//! \details The PadlockRNG uses an 8 byte FIFO buffer for random numbers. The
//! generator can be configured to discard bits from the buffer to resist analysis.
//! The <tt>divisor</tt> controls the number of bytes discarded. The formula for
//! the discard amount is <tt>2**divisor - 1</tt>. When <tt>divisor=0</tt> no bits
//! are discarded and the entire 8 byte buffer is read. If <tt>divisor=3</tt> then
//! 7 bytes are discarded and 1 byte is read. TheVIA SDK samples use <tt>divisor=1</tt>.
//! \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine
//! in 2003. CRI provided recommendations to operate the generator for secure and
//! non-secure applications. Additionally, the Programmers Guide and SDK provided a
//! different configuration in the sample code.
//! \details You can operate the generator according to CRI recommendations by setting
//! <tt>divisor</tt>, reading one word (or partial word) at a time, and then inspecting
//! the MSR after each read.
//! \details The audit report with recommendations is available on the Crypto++ wiki
//! at <A HREF="http://www.cryptopp.com/wiki/VIA_Padlock">VIA Padlock</A>.
//! \sa MaurerRandomnessTest() for random bit generators
//! \since Crypto++ 6.0
class PadlockRNG : public RandomNumberGenerator
@ -33,11 +52,21 @@ public:
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();
//! \param divisor the XSTORE divisor
//! \details The PadlockRNG uses an 8 byte FIFO buffer for random numbers. The
//! generator can be configured to discard bits from the buffer to resist analysis.
//! The <tt>divisor</tt> controls the number of bytes discarded. The formula for
//! the discard amount is <tt>2**divisor - 1</tt>. When <tt>divisor=0</tt> no bits
//! are discarded and the entire 8 byte buffer is read. If <tt>divisor=3</tt> then
//! 7 bytes are discarded and 1 byte is read. VIA SDK samples use <tt>divisor=1</tt>.
//! \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine
//! in 2003. CRI provided recommendations to operate the generator for secure and
//! non-secure applications. Additionally, the Programmers SDK provided a different
//! configuration in the sample code.
//! \details The audit report with recommendations is available on the Crypto++ wiki
//! at <A HREF="http://www.cryptopp.com/wiki/VIA_Padlock">VIA Padlock</A>.
//! \sa SetDivisor, GetDivisor
PadlockRNG(word32 divisor=1);
//! \brief Generate random array of bytes
//! \param output the byte buffer
@ -61,8 +90,39 @@ public:
CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
}
//! \brief Set the XSTORE divisor
//! \param divisor the XSTORE divisor
//! \returns the old XSTORE divisor
word32 SetDivisor(word32 divisor)
{
word32 old = m_divisor;
m_divisor = DivisorHelper(divisor);
return old;
}
//! \brief Get the XSTORE divisor
//! \returns the current XSTORE divisor
word32 GetDivisor() const
{
return m_divisor;
}
//! \brief Get the MSR for the last operation
//! \returns the MSR for the last read operation
word32 GetMSR() const
{
return m_msr;
}
protected:
inline word32 DivisorHelper(word32 divisor)
{
return divisor > 3 ? 3 : divisor;
}
private:
FixedSizeAlignedSecBlock<word32, 1, true> m_buffer;
FixedSizeAlignedSecBlock<word32, 4, true> m_buffer;
word32 m_divisor, m_msr;
};
NAMESPACE_END