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