summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h2
-rw-r--r--padlkrng.cpp75
-rw-r--r--padlkrng.h136
3 files changed, 137 insertions, 76 deletions
diff --git a/config.h b/config.h
index c88c30a1..672d0af1 100644
--- a/config.h
+++ b/config.h
@@ -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
diff --git a/padlkrng.cpp b/padlkrng.cpp
index ebe7d4f2..c6a29035 100644
--- a/padlkrng.cpp
+++ b/padlkrng.cpp
@@ -7,80 +7,81 @@
#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 (!HasPadlockRNG())
- throw PadlockRNG_Err("HasPadlockRNG");
+#if CRYPTOPP_X86_ASM_AVAILABLE
+ if (!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)
{
- FixedSizeSecBlock<word32, 4> discard;
- n = RoundUpToMultipleOf(n, sizeof(word32));
+ 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());
- }
+ size_t count = STDMIN(n, discard.SizeInBytes());
+ while (count)
+ {
+ GenerateBlock(discard.BytePtr(), count);
+ n -= count;
+ count = STDMIN(n, discard.SizeInBytes());
+ }
}
NAMESPACE_END
diff --git a/padlkrng.h b/padlkrng.h
index 9a70fd87..f62dc5dd 100644
--- a/padlkrng.h
+++ b/padlkrng.h
@@ -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
@@ -13,56 +15,114 @@
NAMESPACE_BEGIN(CryptoPP)
//! \brief Exception thrown when a PadlockRNG generator encounters
-//! a generator related error.
+//! 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") {}
+ 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
{
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);
- }
+ CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "PadlockRNG"; }
+
+ virtual ~PadlockRNG() {}
+
+ //! \brief Construct a PadlockRNG generator
+ //! \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
+ //! \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);
+ }
+
+ //! \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