1 // via-rng.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2
3 #include "pch.h"
4 #include "config.h"
5 #include "cryptlib.h"
6 #include "secblock.h"
7 #include "padlkrng.h"
8 #include "cpu.h"
9
10 // The Padlock Security Engine RNG has a few items to be aware of. You can
11 // find copies of the Programmer's manual, Cryptography Research Inc audit
12 // report, and other goodies at http://www.cryptopp.com/wiki/VIA_Padlock.
13
14 #if CRYPTOPP_MSC_VERSION
15 # pragma warning(disable: 4702)
16 #endif
17
NAMESPACE_BEGIN(CryptoPP)18 NAMESPACE_BEGIN(CryptoPP)
19
20 std::string PadlockRNG::AlgorithmProvider() const
21 {
22 return "Padlock";
23 }
24
PadlockRNG(word32 divisor)25 PadlockRNG::PadlockRNG(word32 divisor)
26 : m_divisor(DivisorHelper(divisor)), m_msr(0)
27 {
28 #if defined(CRYPTOPP_X86_ASM_AVAILABLE)
29 if (!HasPadlockRNG())
30 #endif
31 throw PadlockRNG_Err("PadlockRNG", "PadlockRNG generator not available");
32 }
33
GenerateBlock(byte * output,size_t size)34 void PadlockRNG::GenerateBlock(byte *output, size_t size)
35 {
36 CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
37 #if defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__GNUC__)
38 while (size)
39 {
40 __asm__ __volatile__
41 (
42 #if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
43 "mov %1, %%rdi ;\n"
44 "movl %2, %%edx ;\n"
45 #else
46 "mov %1, %%edi ;\n"
47 "movl %2, %%edx ;\n"
48 #endif
49
50 // xstore-rng
51 ".byte 0x0f, 0xa7, 0xc0 ;\n"
52 "movl %%eax, %0 ;\n"
53
54 : "=g" (m_msr) : "g" (m_buffer.data()), "g" (m_divisor)
55 #if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
56 : "rax", "rdx", "rdi", "cc"
57 #else
58 : "eax", "edx", "edi", "cc"
59 #endif
60 );
61
62 const size_t ret = m_msr & 0x1f;
63 const size_t rem = STDMIN<size_t>(ret, STDMIN<size_t>(size, 16U /*buffer size*/));
64 std::memcpy(output, m_buffer, rem);
65 size -= rem; output += rem;
66 }
67 #elif defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(_MSC_VER) && defined(_M_IX86)
68 while (size)
69 {
70 word32 result, divisor = m_divisor;
71 byte *buffer = reinterpret_cast<byte*>(m_buffer.data());
72 __asm {
73 mov edi, buffer
74 mov edx, divisor
75 _emit 0x0f
76 _emit 0xa7
77 _emit 0xc0
78 mov result, eax
79 }
80
81 const size_t ret = (m_msr = result) & 0x1f;
82 const size_t rem = STDMIN<size_t>(ret, STDMIN<size_t>(size, 16U /*buffer size*/));
83 std::memcpy(output, buffer, rem);
84 size -= rem; output += rem;
85 }
86 #else
87 throw PadlockRNG_Err("GenerateBlock", "PadlockRNG generator not available");
88 #endif // CRYPTOPP_X86_ASM_AVAILABLE
89 }
90
DiscardBytes(size_t n)91 void PadlockRNG::DiscardBytes(size_t n)
92 {
93 FixedSizeSecBlock<word32, 4> discard;
94 n = RoundUpToMultipleOf(n, sizeof(word32));
95
96 size_t count = STDMIN(n, discard.SizeInBytes());
97 while (count)
98 {
99 GenerateBlock(discard.BytePtr(), count);
100 n -= count;
101 count = STDMIN(n, discard.SizeInBytes());
102 }
103 }
104
105 NAMESPACE_END
106