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__)))) #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 // 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__)) #if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__))
#define CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE 1 #define CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE 1

View File

@ -7,66 +7,67 @@
#include "padlkrng.h" #include "padlkrng.h"
#include "cpu.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) NAMESPACE_BEGIN(CryptoPP)
PadlockRNG::PadlockRNG() PadlockRNG::PadlockRNG(word32 divisor)
: m_divisor(DivisorHelper(divisor))
{ {
#if CRYPTOPP_BOOL_X86 #if CRYPTOPP_X86_ASM_AVAILABLE
if (!HasPadlockRNG()) if (!HasPadlockRNG())
throw PadlockRNG_Err("HasPadlockRNG"); throw PadlockRNG_Err("PadlockRNG", "PadlockRNG generator not available");
#else #else
throw PadlockRNG_Err("HasPadlockRNG"); throw PadlockRNG_Err("PadlockRNG", "PadlockRNG generator not available");
#endif #endif
} }
void PadlockRNG::GenerateBlock(byte *output, size_t size) void PadlockRNG::GenerateBlock(byte *output, size_t size)
{ {
CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size); CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
#if CRYPTOPP_BOOL_X86 #if defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__GNUC__)
while (size) while (size)
{ {
# if defined(__GNUC__)
word32 result;
__asm__ __volatile__ __asm__ __volatile__
( (
"movl %1, %%edi ;\n" "movl %1, %%edi ;\n"
"movl $1, %%edx ;\n" "movl $2, %%edx ;\n"
".byte 0x0f, 0xa7, 0xc0 ;\n" ".byte 0x0f, 0xa7, 0xc0 ;\n"
"andl $31, %%eax ;\n"
"movl %%eax, %0 ;\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); std::memcpy(output, m_buffer, rem);
size -= rem; output += rem; size -= rem; output += rem;
}
# elif defined(_MSC_VER) #elif defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(_MSC_VER)
while (size)
word32 result; {
byte* buffer = reinterpret_cast<byte*>(m_buffer.begin()); word32 result, divisor = m_divisor;
byte *buffer = reinterpret_cast<byte*>(m_buffer.data());
__asm { __asm {
mov edi, buffer mov edi, buffer
mov edx, 0x01 mov edx, divisor
_emit 0x0f _emit 0x0f
_emit 0xa7 _emit 0xa7
_emit 0xc0 _emit 0xc0
and eax, 31
mov result, eax mov result, eax
} }
const size_t rem = STDMIN(result, STDMIN(size, m_buffer.SizeInBytes())); const size_t ret = (m_msr = result) & 0x1f;
std::memcpy(output, m_buffer, rem); const size_t rem = STDMIN(ret, STDMIN(size, 16U));
std::memcpy(output, buffer, rem);
size -= rem; output += 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) void PadlockRNG::DiscardBytes(size_t n)

View File

@ -1,8 +1,10 @@
// via-rng.h - written and placed in public domain by Jeffrey Walton // via-rng.h - written and placed in public domain by Jeffrey Walton
//! \file PadlockRNG.h //! \file padlkrng.h
//! \brief Class for VIA Padlock RNG //! \brief Classes for VIA Padlock RNG
//! \since Crypto++ 6.0 //! \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 #ifndef CRYPTOPP_PADLOCK_RNG_H
#define CRYPTOPP_PADLOCK_RNG_H #define CRYPTOPP_PADLOCK_RNG_H
@ -20,9 +22,26 @@ class PadlockRNG_Err : public Exception
public: public:
PadlockRNG_Err(const std::string &operation) PadlockRNG_Err(const std::string &operation)
: Exception(OTHER_ERROR, "PadlockRNG: " + operation + " operation failed") {} : 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 //! \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 //! \sa MaurerRandomnessTest() for random bit generators
//! \since Crypto++ 6.0 //! \since Crypto++ 6.0
class PadlockRNG : public RandomNumberGenerator class PadlockRNG : public RandomNumberGenerator
@ -33,11 +52,21 @@ public:
virtual ~PadlockRNG() {} virtual ~PadlockRNG() {}
//! \brief Construct a PadlockRNG generator //! \brief Construct a PadlockRNG generator
//! \details According to DJ of Intel, the Intel PadlockRNG circuit does not underflow. //! \param divisor the XSTORE divisor
//! If it did hypothetically underflow, then it would return 0 for the random value. //! \details The PadlockRNG uses an 8 byte FIFO buffer for random numbers. The
//! AMD's PadlockRNG implementation appears to provide the same behavior. //! generator can be configured to discard bits from the buffer to resist analysis.
//! \throws PadlockRNG_Err if the random number generator is not available //! The <tt>divisor</tt> controls the number of bytes discarded. The formula for
PadlockRNG(); //! 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 //! \brief Generate random array of bytes
//! \param output the byte buffer //! \param output the byte buffer
@ -61,8 +90,39 @@ public:
CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); 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: private:
FixedSizeAlignedSecBlock<word32, 1, true> m_buffer; FixedSizeAlignedSecBlock<word32, 4, true> m_buffer;
word32 m_divisor, m_msr;
}; };
NAMESPACE_END NAMESPACE_END