Using Intel’s Secure Key (RDRAND) in MS Visual C++ 2010

UPDATE (29/05/2016): added a function to use RDRAND to generate a random value within a specified range, and refactored the logic into a static library and wrapped it with a dynamic library for use with P/Invoke.

Among the features added to Intel’s 3rd-Generation Core i* processors is a Digital Random Number Generator (DRNG) backed by an on-die hardware entropy source. This new hardware feature is made available to software via the also-new RDRAND instruction.

If you’re still using the compiler which shipped with Visual C++ 2010, it seems the only way to leverage the DRNG is either via a third-party library (the one available from Intel’s website is, as of writing, broken) or by dipping into assembly programming. Of these the latter comes with a couple of catches: the mnenomic/intrinsic for the instruction is not available for older assemblers/compilers, and the assembly is slightly different for 32- and 64-bit environments.

The sample project illustrates testing whether the host processor supports the RDRAND instruction as well as invoking it (via assembly). When built for 32-bit CPUs, the assembly is inlined; when built for 64-bit CPUs, the assembly is linked in via an exernal module (the 64-bit compiler in Visual Studio 2010 does not support inline assembly).

For the most part, the project simply follows the Software Implementation Guide from Intel. Additionally, it demonstrates invoking the instruction via its opcode, and linking a module implemented in assembly into a VC++ project.

Advertisements

16 Responses to “Using Intel’s Secure Key (RDRAND) in MS Visual C++ 2010”


  1. 1 murgatroyd June 9, 2016 at 12:49 pm

    I’ve been trying to edit your code for a project of mine for a couple of days now. C++ just isn’t my strong suit. Could you help me or provide an executable that outputs infinite lines of 16 digit 0-9 numerical strings?

    like:

    5678711286310891
    8568981672868163

    I could do it without RDRAND but then it wouldn’t help me with my statistics project. It is a private project, nothing I need for uni, I’m a natural scientist, not a computer scientist, so my knowledge is limited regarding this subject. The ASM file already had me stumped.

    Kind greetings
    murgatroyd

    • 2 SjH June 9, 2016 at 2:02 pm

      Hi,

      To generate the numbers you want with the library I’ve written, as it is, you could take the 32-bit output from rdrand_next(), get it as a floating point number between 0 and 1.0 (i.e. divide it by 2^32) and then multiply by 10^16, and thereafter round off or truncate to get as an integer, if desired. (I am presuming that by “16 digit 0-9 numerical strings” you are describing numbers uniformly distributed between 0 and 10^16.)

      This would generate numbers uniformly distributed (or at least with a distribution which matches that of RDRAND..) between 0 and 10^16, but it would only generate 2^32 such numbers, which is a bit less than “infinite”. Would 4 billion-plus numbers be enough?

      An alternative would be to use the 64-bit version of the RDRAND instruction. This is not provided for in the library, but it can generate numbers uniformly distributed between 0 and 2^64, i.e. it’d cover the entire range 0 to 10^16 (with repetitions).

      I’m curious as to why RDRAND, and not some other RNG, is particularly important for your project (if it is)?

      Steve

      • 3 murgatroyd June 9, 2016 at 3:11 pm

        Thank you for the friendly AND helpful advice. I sat down for another try and made all changes to create a 64-bit version of your nice piece of software. Even figured out the REX prefix and made changes to the max float / int sizes (I guess?).

        Removed project files as well that were not required (want to deploy this as mere exe on my system).

        14 kb project file (zipped) https://jii.moe/E1VfPDfNW.zip

        I hope your code is not too butchered now, if you can spare the time to look at my changes, perhaps you can see where I messed up, everything should be 64-bit now, I still get tiny 7-10 digit numbers instead of 16 digit numbers.

        Thanks for your patience
        murgatroyd

      • 4 SjH June 9, 2016 at 7:32 pm

        Hi,

        Have had a look, and:

        1. in RdRandStatic/rdrand64.asm, the 64-bit random value is put in RAX (a 64-bit register), but you’re returning the value from EAX (which is the lower 32-bits of RAX) – see lines 20 and 65, although it looks as though only the one at line 20 is relevant.

        2. in RdRand/Rdrand.cpp, when you print out the returned value, you’re using the “%u” format specifier, which may only print the number in the lower 32 bits of the number. Google says that the format specifier for an unsigned 64-bit integer is “%I64u”.

        3. I can’t see anywhere that the value is restricted, or mapped, to 0 to 10^16? I mention this because you appear to be expecting 16-digit numbers, but even if the bugs outlined above were fixed you would still see 7/10 digit numbers (as well as 17/18/19 digit numbers).

        Steve

      • 5 murgatroyd June 9, 2016 at 3:20 pm

        Addendum:
        Pardon, I didn’t answer your questions. I’m interested how random RDRAND is, as far as I could figure out from more skilled people reviewing it, you can say sufficiently for the normal desktop user. Also I’m impressed by it’s output. Something around 2.5 Gbps as a stackexchange user claimed.

        >Would 4 billion-plus numbers be enough?
        That would be wonderful, this is more than I had hoped for.

      • 6 SjH June 9, 2016 at 9:49 pm

        The following program will, I think, use RDRAND to generate 16-digit decimal numbers, that is in the range 1000000000000000 to 9999999999999999, rather than 0 to 10^16 – I misinterpreted your earlier message, sorry.


        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.Runtime.InteropServices;

        namespace viaTheFalcon
        {
        class Program
        {
        static void Main(string[] args)
        {
        if (rdrand_supported())
        {
        decimal left = 1.0e15M;
        decimal factor = 8999999999999999M / 4294967295M;

        UInt64 iterations = (args.Length > 0) ? UInt64.Parse(args[0]) : 64;
        for (UInt64 u = 0; u < iterations; u++)
        {
        UInt32 value = 0;
        if (rdrand_next(ref value))
        {
        decimal right = factor * Convert.ToDecimal(value);
        Console.WriteLine("RDRAND returned: {0}", Math.Floor(left + right));
        }
        else
        {
        Console.WriteLine("RDRAND did not return a value.");
        }
        }
        }
        else
        {
        Console.WriteLine("RDRAND is not supported on this host.");
        }
        }

        [DllImport("RdRandLib.dll")]
        private static extern bool rdrand_supported();

        [DllImport("RdRandLib.dll")]
        private static extern bool rdrand_next(ref UInt32 value);
        }
        }

        Steve

  2. 7 murgatroyd June 9, 2016 at 7:59 pm

    Thanks Steve,

    I’ll check the lines you mentioned and put more effort in my follow up attempts to make it work. At least it still compiles and executes. My few adventures into assembly have been with cheap µcontrollers and nothing too impressive in particular. Usually I only ever code solutions for tiny problems and then in environments like labview, comsol or matlab.

    I’ll try to report back next week if I was successful.

    Cheers!

  3. 8 murgatroyd June 10, 2016 at 11:14 am

    Hello again,

    that C# code snippet is exactly what I needed! Works wonderful with your library. Thanks a lot for the heavy lifting! I made a small comparison with John Walker’s ENT entropy test kit and I got for both around 0.42 randomness where 0.5 would be truly random.

    But I take the value with a grain of salt, the tool was written for binaries rather than text files.

    As far as I can tell this is perfect for my needs. Hope you didn’t waste too much of your personal time on helping me out.

    Have a great day

    • 9 SjH June 10, 2016 at 12:41 pm

      Hi,

      No, it didn’t take long, and such time as was spent was mostly on realising that double-precision floating point doesn’t (uniformly) cover the desired range of integers from 10^15 to (10^16 – 1). Hence the switch to C# with its built-in (128-bit) decimal type.

      Steve

  4. 10 M. Kirisame June 11, 2016 at 11:03 pm

    however the code you posted doesn’t even allow him to generate his strings starting with a zero

    thus 10% of the entire range you can generate is lost, major caveat

    • 11 SjH June 12, 2016 at 1:19 am

      Yes, this is correct, but it’s not wholly clear (to me) what murgatroyd’s purpose for the program’s output is. If it is to be treated as numbers, then do 0-padded 16-digit numbers really count as 16-digit numbers?

      murgatroyd does refer, in their first comment, to “numerical strings”, but I was clear in stating that the program I provided generated numbers between 1000000000000000 to 9999999999999999, and this prompted no objection. If 0-padded numbers less than 1000000000000000 are acceptable, or desired, then modifying the program to generate them seems pretty straightforward to me. If not, let me know.

      In any case, restricting the program’s output to between 1000000000000000 and 9999999999999999 shouldn’t seem like it would affect the randomness of the output, since the interval is considerably larger than the output space of the 32-bit version of RDRAND.

      Thanks for pointing this out; it likely wouldn’t have occurred to me otherwise.

      Steve

      • 12 M. Kirisame June 12, 2016 at 10:36 am

        my guess would be pentesting wifi:

        0000000000000000 to 9999999999999999

        is typical for default factory pw 😉

      • 13 murgatroyd June 12, 2016 at 6:12 pm

        @ M. Kirisame
        Yes indeed that would be a useful way to use it, though not a morally encouraged unless you try it on your own net. I don’t think modern wireless hardware actually uses this short passwords anymore, mine came with a 20 digit one. You’d have a better chance at winning the lottery.

        @ Steve
        This explanation could also be the reason why the first entropy tests gave me around 0.42 instead of 0.5

        Yes I tried to choose my words carefully, but I excuse myself if they were not scientifically accurate enough. To my understanding a string allows me better to compare each random “number” I’ve picked the quotes here on purpose because I really want strings. 0001 is not a way you’d normally print an integer of 1.

        My intentions were to use them as seeds for virtual machines, precisely an OS inside said VM, which sometimes cannot use certain hardware interrupts due to limited access inside their virtual environment.

        Still I want to figure out how random this randomness is. I can only have Linus’ word on this, that RdRand is just an aspect, since the linux kernel uses various sources, so one “foul” apple had little impact.

        Then again it is an adventure into opcodes for myself, I’m still far away from writing any project like this myself, but I’m growing fond of the insights I gained from this.

        Could there be a way to get the “lost” 1/10 of the space if the string without too hard workarounds?

        Sorry for accidental typos, sent from my mobile.

        greetings
        murgatroyd

      • 14 SjH June 12, 2016 at 7:22 pm

        @murgatroyd:

        The <0.5 entropy you're observing may be because the output of RDRAND is a “Cryptographically secure pseudorandom number generator”, as distinct from a truly random number generator.

        If you have a Broadwell CPU (or newer; alas, I have neither), then there is a further instruction, RDSEED, which outputs “seed-grade entropy” which may be a better fit for your requirement. Speaking of which, if your CPU does not support RDSEED, then Intel recommends further steps to “generate random seeds from values obtained via RDRAND”; see section 4.2.6 of Intel® Digital Random Number Generator (DRNG) Software Implementation Guide.

        Additionally, Intel say that “RDRAND and RDSEED can be used freely by multiple VMs without the need for hypervisor intervention or resource management.”

        Finally, we can change the program to generate numbers from 0 to (10^16 – 1), rather than numbers from 10^15 to (10^16 – 1), fairly straightforwardly (as previously mentioned) but it don’t think it’ll improve the randomness of the output, because 10^15 to (10^16 – 1) is already several orders of magnitude greater than 2^32. Changing the program to output numbers from 0 to (10^16 – 1) would just increase the interval between the numbers.

        Nevertheless, if you want to do it, then it should be as simple as initialising the ‘left’ variable to 0 and the ‘factor’ variable to (1.0e16M – 1M) / 4294967295M. (I’m away from my PC, so I can’t double-check this, sorry.)

        Steve

      • 15 SjH June 13, 2016 at 7:53 am

        I should have added that to get the program to print the leading zeros, you will want to change the call to Console.WriteLine(..) along the lines of this:
        https://msdn.microsoft.com/en-us/library/dd260048(v=vs.110).aspx

        Steve


  1. 1 Multiplying Matrices with AVX. For Fun* | via The Falcon Trackback on February 15, 2014 at 5:59 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s





%d bloggers like this: