首页 > 技术文章 > csrng

Janly 2021-04-07 13:43 原文

版本2.1
2018年10月17日

资料下载

下载英特尔®数字随机数发生器(DRNG)软件实施指南 [PDF 650KB]
下载 英特尔®数字随机数发生器软件代码示例

相关软件

有关Microsoft * Windows *,Linux *和OS X *的信息,请参见DRNG库和手册

1.简介

英特尔®安全密钥,代号为Bull Mountain Technology,是英特尔®64和IA-32架构指令RDRAND和RDSEED以及底层数字随机数生成器(DRNG)硬件实现的英特尔名称。除其他事项外,使用RDRAND指令的DRNG可用于生成用于加密协议的高质量密钥,并且提供RSEED指令用于为基于软件的伪随机数生成器(PRNG)播种。

本数字随机数生成器软件实施指南旨在提供有关RDRAND使用的完整技术信息,包括代码示例。本文档包括以下部分:

第2节:随机数发生器(RNG)的基本知识和DRNG简介。本节描述了RNG的性质及其伪(PRNG)和true(TRNG)实现变体,包括现代级联构造RNG。然后,我们介绍DRNG在此更广泛的分类法中的立场。

第3节:DRNG概述。在本节中,我们提供了DRNG的技术概述,包括其组件体系结构,健壮性功能,访问方式,性能和功耗要求。

第4节:RDRAND和RDSEED指令用法。本节提供有关RDRAND和RDSEED指令的参考信息,以及显示其用法的代码示例。这包括平台支持验证以及有关基于DRNG的库的建议。

已经了解RNG本质的程序员可以直接参考第4节以获取指令参考和代码示例。需要对概念进行一些了解以了解DRNG的性质和重要性的RNG新手可以参阅第2节。几乎所有开发人员都希望参阅第3节,该节提供了DRNG的技术概述。

2. RNG基础知识和DRNG简介

使用RDRAND指令的数字随机数发生器是一种创新的硬件方法,用于高质量,高性能的熵和随机数生成。为了了解它与现有RNG解决方案的不同之处,本节详细介绍了随机数生成基础的一些基本概念。

2.1随机数发生器(RNG)

RNG是某种实用程序或某种类型的设备,会在间隔[min,max]上生成一系列数字,从而使值看起来不可预测。从技术上讲,我们正在寻找以下特征:

  • 每个新值必须在 统计上 独立 于先前值。也就是说,给定生成的值序列,在RNG随机序列中,下一个值不太可能跟随特定值。
  • 从间隔中选择的数字的整体分布是 均匀 分布的。 换句话说,所有数字都有同等的可能性,并且没有一个比其他数字更“受欢迎”或出现在RNG输出中的频率更高。
  • 顺序是 不可预测的攻击者无法猜测所生成序列中的部分或全部值。可预测性可以采取 前向 预测(未来值)和回溯(过去值)的形式。

由于计算系统本质上是确定性的,因此产生具有这些属性(统计独立性,均匀分布和不可预测性)的质量随机数比看起来要困难得多。从系统时钟采样秒值,这是一种常见的方法,可能看起来足够随机,但是过程调度和其他系统影响可能导致某些值的发生频率远高于其他值。进一步的分析表明,外部熵源(如用户的击键或鼠标移动之间的时间)可能同样表明,值在所有可能值的空间中分布不均。有些价值观比其他价值观更可能出现,而某些价值观在实践中几乎从未出现过。

除了这些要求之外,其他一些所需的RNG属性还包括:

  • RNG快速返回一个值(即响应时间短),并且可以在短时间间隔(即高度可伸缩)内处理大量请求。
  • RNG对攻击者是安全的,攻击者可能会观察或更改其基本状态以预测或影响其输出或以其他方式干扰其运行。

2.2伪随机数生成器(PRNG)

实现良好的RNG统计行为的一种广泛使用的方法是在创建伪随机数生成器时利用数学建模。PRNG是一种确定性算法,通常在计算“看起来”随机的数字序列的软件中实施。PRNG需要种子值,该种子值用于初始化基础模型的状态。播种后,它便可以生成显示良好统计行为的数字序列。

PRNG的周期性取决于其内部状态模型的大小。也就是说,在生成一个长序列的数字之后,内部状态的所有变化都将被耗尽,随后的数字序列将重复一个较早的序列。但是,当今可用的最佳PRNG算法的周期如此之大,几乎可以忽略不计。例如,字长为32位的Mersenne Twister MT19937 PRNG的周期性为2 19937 -1。(1)

所有PRNG的一个关键特征是它们具有 确定性也就是说,给定特定的种子值,相同的PRNG将始终产生与“随机”数字完全相同的序列。这是因为PRNG正在基于特定的内部状态和特定的,定义明确的算法来计算下一个值。因此,尽管生成的值序列显示出随机性(独立性,均匀分布)的统计特性,但PRNG的总体行为是完全可预测的。

在某些情况下,PRNG的确定性是一个优势。例如,在某些模拟和实验环境中,研究人员希望使用相同的输入数据序列比较不同方法的结果。PRNG提供了一种生成长序列的随机数据输入的方法,这些输入可以通过使用相同的PRNG(具有相同的值)进行重复。

但是,在其他情况下,这种确定性是非常不希望的。考虑一个服务器应用程序,该服务器应用程序生成随机数,以用作通过安全通信通道与客户端应用程序进行数据交换时的加密密钥。知道使用中的PRNG并知道种子值(或用于获得种子值的算法)的攻击者将能够迅速预测生成的每个密钥(随机数)。即使使用复杂且未知的种子算法,知道(或可以猜测)使用中的PRNG的攻击者也可以通过观察输出值的顺序来推断PRNG的状态。经过令人惊讶的少量观察(例如,对于Mersenne Twister MT19937,为624),可以预测每个后续值。因此,PRNG被认为在密码上是不安全的。

PRNG研究人员通过创建所谓的加密安全PRNG(CSPRNG)来解决此问题。在该领域中已经发明了各种技术,例如,将密码哈希应用于连续整数序列,使用分组密码对连续整数序列进行加密(“计数器模式”)以及对PRNG生成的数字流进行XOR运算。明文(“流密码”)。这些方法通过大大增加PRNG及其状态的计算复杂性来改善推断PRNG及其状态的问题,但是结果值可能会或可能不会显示鲁棒随机数生成器所需的正确统计属性(即,独立性,均匀分布)。此外,攻击者可以通过各种方式(例如反汇编程序,复杂的内存攻击,心怀不满的员工)。更常见的是,攻击者可能通过缩小PRNG可能值的范围或以某种方式监听内存来发现或推断PRNG种子。一旦知道了确定性算法及其种子,攻击者便可以预测过去和将来生成的每个随机数。

2.3真随机数生成器(TRNG)

对于需要避免PRNG确定性的情况(例如游戏和计算机安全性),更好的方法是使用真正随机数生成器。

TRNG不是使用数学模型来确定性地生成看起来是随机的并且具有正确的统计属性的数字,而是从某种类型的物理源中提取随机性(熵),然后使用它来生成随机数。物理源也称为 熵源, 并且可以从使用TRNG的计算系统自然可用或可以使用的多种物理现象中进行选择。例如,人们可以尝试将用户按键或鼠标移动之间的时间用作熵源。如前所述,该技术在实践中是粗略的,并且所得的值序列通常无法严格满足所需的统计属性。在TRNG中用作熵源的工具是TRNG设计人员面临的主要挑战。

除了严格的统计之外,TRNG还希望快速且可扩展(即,能够在一个小的时间间隔内生成大量随机数)。这对于许多TRNG来说是一个严重的问题,因为对计算系统外部的熵源进行采样通常需要设备I / O和相对于当今计算机系统的处理速度而言较长的延迟时间。通常,与PRNG简单地计算其下一个随机值所需的计算相比,在TRNG中对熵源进行采样的速度较慢。因此,PRNG具有比TRNG更好的性能,并且具有更大的可伸缩性。

但是,与PRNG不同,TRNG并不是确定性的。即,不需要播种TRNG,并且在任何给定序列中对随机值的选择都是高度不可预测的。因此,攻击者无法使用对特定随机数序列的观察来有效地预测后续值。此属性还暗示TRNG没有周期性。尽管可以按随机顺序重复(尽管不太可能),但无法以对攻击者有用的方式预测重复。

2.4级联施工RNG

现代操作系统(例如Linux *(2))和密码库中使用的一种常见方法是从熵源获取输入,以提供熵的缓冲或池(请参见图1)。然后,此熵池用于提供不确定的随机数,该随机数会定期播种密码安全的PRNG(CSPRNG)。此CSPRNG提供了密码安全的随机数,这些随机数看起来确实是随机的,并且具有明确定义的计算攻击强度。

图1.级联构造随机数生成器

该方案的主要优势是性能。上面已经指出,对熵源进行采样通常很慢,因为它通常涉及某种类型的设备I / O,并且常常需要额外的等待实时采样事件才能完成。相比之下,CSPRNG计算是快速的,因为它们是基于处理器的,并且避免了I / O和熵源延迟。这种方法提供了改进的性能:缓慢的熵源定期播种能够从单个CS生成大量随机值的快速CSPRNG种子。

尽管这种方法似乎很理想,但在实践中通常远远不够。首先,由于实施通常是在软件中进行的,因此容易受到广泛的软件攻击。例如,相当多的状态要求为基于内存的攻击或定时攻击创造了可能。其次,该方法不能解决使用什么熵源的问题。没有某种类型的外部来源,熵质量可能很差。例如,如果系统驻留在大型数据中心中,则不可能采样用户事件(例如,鼠标,键盘)。即使使用外部熵源,熵采样也可能会很慢,从而使播种事件的发生频率比预期的要少。

2.5引入数字随机数发生器(DRNG)

数字随机数发生器(DRNG)是一种创新的硬件方法,用于高质量,高性能的熵和随机数生成。它由新的英特尔64架构指令RDRAND和RDSEED以及底层的DRNG硬件实现组成。

关于上面讨论的RNG分类,DRNG遵循级联构造RNG模型,使用处理器常驻熵源重复播种硬件实现的CSPRNG。与软件方法不同,它包括高质量的熵源实现,可以快速对其进行采样,从而以高质量的熵反复播种CSPRNG。此外,它代表了一个独立的硬件模块,该模块与内部状态的软件攻击隔离开来。结果是实现了具有相当强健性的RNG目标的解决方案:统计质量(独立性,均匀分布),高度不可预测的随机数序列,高性能和防御攻击。

这种数字随机数生成方法在其真正的随机数生成方法中是独特的,因为它是在处理器的硬件中实现的,并且可以通过添加到Intel 64指令集的指令来利用。因此,响应时间可与软件中实施的竞争PRNG方法相媲美。该方法具有足够的可伸缩性,即使要求苛刻的应用程序也可以将其用作随机数的唯一来源,而不仅仅是基于软件的PRNG的高质量种子。在所有特权级别运行的软件都可以通过指令集访问随机数,从而绕过中间软件堆栈,库或操作系统处理。

RDRAND和RDSEED的使用利用了多种加密标准,以确保其实施的鲁棒性并提供其操作方式的透明性。其中包括NIST SP800-90A,B和C,FIPS-140-2和ANSI X9.82。符合这些标准使数字随机数生成成为政府和商业中受到严格监管的应用程序领域的可行解决方案。

第三部分详细描述了数字随机数的生成。第4节介绍了RDRAND和RDSEED的使用,这是使用DRNG的Intel指令集扩展。

2.6数字随机数发生器的应用

信息安全是利用DRNG的关键应用程序。加密协议依靠RNG生成密钥和新的会话值(例如,随机数)以防止重放攻击。实际上,加密协议可能具有相当的鲁棒性,但由于其底层的弱密钥生成方法而遭受广泛的攻击(例如,Debian * / OpenSSL *惨败(3))。DRNG可用于修复此漏洞,从而显着提高密码的鲁棒性。

与政府和行业应用密切相关。由于信息敏感性,许多此类应用程序必须证明其符合安全标准,例如FISMA,HIPPA,PCIAA等。RDRAND经过精心设计,可以满足现有的安全标准,例如NIST SP800-90,FIPS 140-2和ANSI X9.82,从而提供了可用于证明符合信息安全标准的基础RNG解决方案。

DRNG的其他用途包括:

  • 通讯协议
  • 蒙特卡洛模拟和科学计算
  • 游戏应用
  • 大量熵应用程序,例如安全磁盘擦除或文档粉碎
  • 保护在线服务免受RNG攻击
  • 基于种子软件的任意宽度的PRNG

3. DRNG概述

在本节中,我们将使用RDRAND和RDSEED指令及其相互作用来详细描述DRNG的组件。

3.1处理器视图

图2提供了RDRAND和RDSEED随机数发生器的高级示意图。如图所示,DRNG在处理器上显示为硬件模块。互连总线将其与每个内核连接。

图2.数字随机数发生器设计

RDRAND和RDSEED指令(在第4节中详细介绍)由每个内核上的微代码处理。这包括一个RNG微代码模块,该模块处理与处理器上DRNG硬件模块的交互。

3.2组件架构

如图3所示,可以将DRNG视为构成异步生产流水线的三个逻辑组件:熵源(ES),它以3 Gbps左右的速度从不确定性硬件过程中产生随机位,而调节器则使用AES(4)在CBC-MAC(5)模式下将熵提炼为高质量的不确定性随机数和两个并行输出:

  1. 从调节器播种的确定性随机位生成器(DRBG)。
  2. 增强的不确定性随机数生成器(ENRNG),它从熵调节器提供种子。

请注意,调节器不会向DRBG和ENRNG发送相同的种子值。可以将此路径视为交替切换,一个种子进入DRGB,下一个种子进入ENRNG。这种构造可确保软件应用程序永远不会获得用于为DRBG设置种子的值,也不会通过重复执行RDSEED指令而对DRBG发起拒绝服务(DoS)攻击。

调节器可以等同于前述级联构造RNG中的熵池。但是,由于它是由高质量,高速,连续的熵流馈送的,其馈送速度比下游过程消耗的速度要快,因此它不需要维护熵池。相反,它总是在不依赖于过去和将来的熵的情况下调节新鲜的熵。

图3. DRNG组件架构

最后两个阶段是:

  1. 基于CTR模式下的AES且与SP800-90A兼容的硬件CSPRNG。在SP800-90A术语中,这称为DRBG(确定性随机位发生器),该术语在本文档的其余部分中始终使用。
  2. 符合SP800-90B和C的ENRNG(增强型不确定性随机数生成器)。

 

3.2.1熵源(ES)

全数字熵源(ES),也称为非确定性随机位生成器(NRBG),以零和一的形式提供熵数据的串行流。

ES在自定时电路上异步运行,并使用硅内部的热噪声以3 GHz的速率输出随机的比特流。ES不需要专用的外部电源来运行,而是使用与其他核心逻辑相同的电源。ES旨在在超过处理器正常运行范围的广泛运行条件下正常运行。

来自ES的位将传递到调节器以进行进一步处理。

3.2.2护发素

调节器获取ES生成的成对的256位原始熵样本,并使用AES-CBC-MAC将其简化为单个256位条件化熵样本。这具有将熵蒸馏成更浓缩的样品的作用。

AES(高级加密标准)在FIPS-197高级加密标准(4)中定义。CBC-MAC,密码块链接-消息认证代码,在NIST SP 800-38A建议的块密码模式中进行了定义(5)。

条件熵以256位值的形式输出,并传递到流水线中的下一级,以用作DRBG种子值。

3.2.3确定性随机位发生器(DRBG)

确定性随机位发生器(DRBG)的作用是将条件熵样本“扩展”为一大组随机值,​​从而增加了硬件模块可用的随机数。这是通过采用符合标准的DRBG并将其与条件熵样本连续进行重新播种来完成的。

为此功能选择的DRBG是使用AES分组密码在NIST SP 800-90A(6)的10.2.1节中定义的CTR_DRBG。产生的值将填充FIFO输出缓冲区,然后将其用于响应RDRAND对随机数的请求。

DRBG自主决定何时需要重新填充以刷新缓冲区中的随机数池,并且对于RDRAND调用者而言,DRBG既不可预测又透明。每个种子将生成511个128位样本的上限。也就是说,将从同一种子值生成不超过511 * 2 = 1022个连续DRNG随机数。

3.2.4增强型非确定性随机数生成器

增强型非确定性随机数生成器的作用是使条件熵样本直接可用于软件,以用作其他基于软件的DRBG的种子。从ENRNG得出的值具有可乘的蛮力预测阻力,这意味着可以串联样本,并且蛮力预测阻力将随它们成比例。将两个64位样本连接在一起时,所得的128位值将具有128位的蛮力预测阻力(2 64 * 2 64 = 2 128)。此操作可以无限重复,并且可以用来轻松生成任意大小的随机种子。由于此属性,这些值可用于播种任何大小的DRBG。

3.2.5稳健性和自我验证

为了确保DRNG功能具有高度的可靠性和健壮性,已包含验证功能,这些功能在系统启动时会不断运行。其中分别包括DRNG在线健康测试(OHT)和内置自测(BIST)。两者都如图4所示。

图4. DRNG自我验证组件

3.2.6在线健康测试(OHT)

在线健康测试(OHT)旨在使用硬件中的每个样本和滑动窗口统计测试来测量ES生成的熵的质量。

每个样本测试将位模式与ES的数学模型指定的预期模式到达分布进行比较。未通过此测试的ES样本被标记为“不健康”。利用这种区别,调理剂可以确保将至少两个健康样品混入每个种子中。这可以抵御可能试图减少ES输出的熵内容的硬件攻击。

滑动窗口测试会检查许多样本的样本健康状况,以确保它们保持在所需阈值以上。滑动窗口的大小很大(65536位),并且机制可确保ES在发出随机数之前整体上正常运行。在极少数情况下,DRNG在运行时失败,它将停止发出随机数,而不是发出质量差的随机数。

3.2.7内置自测(BIST)

内置自测(BIST)旨在在将DRNG提供给软件之前验证ES的运行状况。其中包括本质上具有统计意义的熵源测试(ES-BIST),以及通过BIST已知答案测试(KAT-BIST)对所有DRNG确定性下游逻辑进行的全面测试。

ES-BIST涉及在将DRNG提供给软件之前,以正常模式在试用期内运行DRNG。这样,OHT可以在确定ES操作正常之前检查整个滑动窗口(256个样本)的ES样本运行状况。它还填充滑动窗口样本管线,以确保后续ES样本的运行状况,为PRNG注入种子,并为DRNG的输出队列填充随机数。

KAT-BIST使用确定性的输入和输出验证来测试OHT和端对端正确性。首先,将各种比特流样本输入到OHT,包括统计质量较差的数字。样本涵盖了广泛的统计属性,并测试OHT逻辑是否正确识别了那些“不健康”的属性。在KAT-BIST阶段,确定性随机数从管道末端连续输出。BIST输出测试逻辑验证是否收到了预期的输出。

如果启动期间BIST发生故障,则DRNG将不会发出随机数,并且会向处理器上的测试电路发出BIST失败通知。这种BIST逻辑避免了可能会破坏DRNG安全性的常规处理器上测试机制(例如,扫描和JTAG)的需要。

3.3说明

通过(7)第3章中记录的RDRAND和RDSEED指令对DRNG进行软件访问。

3.3.1 RDRAND

RDRAND从兼容SP800-90A的DRGB中检索硬件生成的随机值,并将其存储在目标寄存器中,该寄存器作为指令的自变量给出。随机值(16位,32位或64位)的大小由给定寄存器的大小确定。必须检查进位标志(CF),以确定在执行指令时是否有随机值可用。

请注意,RDRAND可用于平台上运行的任何系统或应用程序软件。即,没有硬件环要求根据进程特权级别限制访问。这样,RDRAND可以作为操作系统或系统管理程序系统库,共享软件库的一部分或直接由应用程序调用。

为了以编程方式确定给定的英特尔平台是否支持RDRAND,开发人员可以使用CPUID指令检查ECX寄存器的第30位。有关详细信息,请参见参考文献(7)。

3.3.2 RDSEED

RDSEED从符合SP800-90B和C的ENRNG中检索硬件生成的随机种子值,并将其存储在目标寄存器中,该寄存器作为指令的自变量给出。与RDRAND指令一样,随机值的大小由给定寄存器的大小确定,必须检查进位标志(CF)以确定执行该指令时是否有随机种子可用。

与RDRAND一样,也没有硬件环要求,可以根据进程特权级别来限制对RDSEED的访问。

为了以编程方式确定给定的英特尔平台是否支持RDSEED指令,开发人员可以使用CPUID指令检查EBX寄存器的第18位。有关详细信息,请参见参考文献(8)。

3.4 DRNG性能

数字随机数生成器被设计为在多个内核/线程之间共享的高性能熵资源,代表了新一代RNG性能。

DRNG作为Intel处理器的一部分在硬件中实现。这样,熵源和DRBG均以处理器时钟速度执行。与其他基于硬件的解决方案不同,在发出多个请求时,不需要系统I / O来获取熵样本,也不需要处理器外总线延迟来减慢熵传递或创建瓶颈。

随机值通过指令级请求(RDRAND和RDSEED)直接传递。这绕过了对请求的操作系统和软件库的处理。DRNG具有足够的可伸缩性,可以支持繁重的服务器应用程序工作负载。在虚拟化的背景下,DRNG的无状态设计和原子指令访问意味着RDRAND和RDSEED可以由多个VM自由使用,而无需管理程序干预或资源管理。

3.4.1 RDRAND性能

在当前的Intel处理器中,DRBG在时钟为800 MHz的自定时电路上运行,并且可以每8个时钟为RDRAND事务(1 Tx)提供服务,最大速度为每秒100 MTx。事务可以用于16位,32位或64位RDRAND,使用64位RDRAND可以实现最大的吞吐量,将吞吐量上限限制为800 MB /秒。这些限制是CPU上所有内核上所有硬件线程的上限。

单线程性能受总线基础结构施加的指令等待时间的限制,这也部分受时钟速度的影响。在实际系统上,取决于SPU体系结构,连续执行RDRAND的单个线程可能会看到70到200 MB /秒的吞吐量。

如果多个线程同时调用RDRAND,则RDRAND的总吞吐量(跨所有线程)将与线程数成线性比例,直到不再剩余硬件线程,达到处理器的总线限制或DRNG接口完全饱和为止。超过这一点,最大吞吐量将在活动线程之间平均分配。没有线程饿死。

图5显示了六种不同CPU体系结构的多线程RDRAND吞吐量与单线程吞吐量的比值。虚线表示线性比例。这表明在达到饱和之前,RDRAND的总吞吐量几乎与CPU上活动线程的数量成线性比例关系。

图5.多线程RDRNAD吞吐量缩放

图6显示了单个系统的多线程性能,以及达到饱和及以后的比率。如图5所示,总吞吐量几乎呈线性比例缩放,直到达到饱和为止,此时达到稳定状态。

图6.超出饱和的RDRAND吞吐量

结果是根据内部英特尔®分析估算的,仅供参考。系统硬件或软件设计或配置上的任何差异都可能影响实际性能。

3.5电源要求

DRNG硬件驻留在处理器上,因此不需要专用电源即可运行。相反,它仅使用处理器的本地电源。如3.2.1节所述,该硬件被设计为可在超过处理器正常工作范围的一系列过程电压和温度(PVT)电平范围内工作。

DRNG硬件不会影响与各个内核关联的电源管理机制和算法。例如,基于ACPI的用于基于每个内核调节处理器性能状态(P状态)和处理器空闲状态(C状态)的机制不受影响。

为了节省电量,当队列已满时,DRNG时钟会自行关闭。每当不需要熵计算和后处理时,这种基于空闲的机制都会导致可忽略的功率需求。

4. FIPS和CAVS认证

有两个与数字随机数生成器(DRNG)相关的认证:密码算法验证系统(CAVS)和联邦信息处理标准(FIPS)。FIPS提供了加密模块的规范,并要求FIPS认证的加密模块中的随机数生成器(RNG)解决方案必须具有SP800-90 CAVS认证。DRNG不是FIPS加密模块:它是符合SP800-90的RNG解决方案,可以通过CAVS认证,因此可以作为FIPS认证的加密模块的组件使用。每个产品必须获得符合SP800-90的解决方案的CAVS认证,这意味着处理器世代必须经过单独认证。

CAVS认证DRNG的另一种方法是通过RDSEED指令或seed-from-RDRAND选项,将DRNG用作基于软件的RNG的熵源。

无论采用哪种方法,FIPS-140-2认证过程都需要提供熵证明文件和数据。英特尔将与供应商合作,为DRNG提供必要的熵文档,以支持客户产品的FIPS140-2应用程序。随着2018年SP800-90B标准的发布,熵源有可能获得符合SP800-90B的认证。英特尔的熵源和提取算法设计为符合SP800-90B,并在有认证程序时可进行认证。

当前用于认证使用DRNG的密码解决方案的美国国家标准技术研究院(NIST)模型需要Intel与密码模块提供商之间建立合作伙伴关系,以按产品生成熵证明文件。

5.指令用法

在本节中,我们提供RDRAND和RDSEED的指令参考以及程序员的用法示例。本指南中的所有代码示例均根据新的3条款BSD许可进行了许可,从而使它们几乎可以在任何软件环境中自由使用。

有关RDRAND用法和代码示例的其他详细信息,请参见参考(7)。

5.1确定对RDRAND和RDSEED的处理器支持

在使用RDRAND或RDSEED指令之前,应用程序或库应首先确定基础平台是否支持该指令,并因此包括基础DRNG功能。可以使用CPUID指令完成此操作。通常,CPUID用于返回存储在EAX,EBX,ECX和EDX寄存器中的处理器标识和功能信息。有关CPUID的详细信息,请参阅参考文献(7)和(8)。

具体而言,可以通过检查CPUID返回的ECX寄存器的第30位来确定对RDRAND的支持,而可以通过检查EBX寄存器的第18位来确定对RDSEED的支持。如表1(以下)和参考文献(7)中的2-23所示,值为1表示该指令对处理器的支持,而值为0表示无处理器支持。

表1. ECX寄存器中返回的功能信息

叶子

登记

少量

助记符

描述

1个

ECX

30

罗格朗德

值为1表示处理器支持RDRAND指令

7

EBX

18岁

RDSEED

值为1表示处理器支持RDSEED指令

在高级编程语言(如C或C ++)的上下文中调用CPUID指令的两个选项包括:

  • 内联汇编例程
  • 在独立文件中定义的汇编例程。

内联汇编的优点是它在其源代码上下文中简单易懂。但是,缺点是,经常需要使用条件代码来处理不同底层平台的可能性,这可能会迅速损害可读性。本指南描述了Linux实施方案,该实施方案也应在OS X *上运行。请参阅Windows *示例的DRNG下载。

代码示例1显示了在64位Linux上用于gcc编译的get_drng_support函数的定义。该内容包含在本指南随附的DRNG示例源代码下载中包含的源代码模块drng.c中。

/* These are bits that are OR’d together */

#define DRNG_NO_SUPPORT	0x0	/* For clarity */
#define DRNG_HAS_RDRAND	0x1
#define DRNG_HAS_RDSEED	0x2

int get_drng_support ()
{
	static int drng_features= -1;

	/* So we don't call cpuid multiple times for 
	 * the same information */

	if ( drng_features == -1 ) {
		drng_features= DRNG_NO_SUPPORT;

		if ( _is_intel_cpu() ) {
			cpuid_t info;

			cpuid(&info, 1, 0);

			if ( (info.ecx & 0x40000000) == 0x40000000 ) {
				drng_features|= DRNG_HAS_RDRAND;
			}

			cpuid(&info, 7, 0);

			if ( (info.ebx & 0x40000) == 0x40000 ) {
				drng_features|= DRNG_HAS_RDSEED;
			}
		} 
	}

	return drng_features;
}

代码示例1.在64位Linux *上确定对RDRAND和RDSEED的支持

此函数首先通过调用_is_intel_cpu()函数(在代码示例2中定义)来确定处理器是否为Intel CPU。如果是,则该函数然后使用CPUID指令检查功能位以确定指令支持。

typedef struct cpuid_struct {
	unsigned int eax;
	unsigned int ebx;
	unsigned int ecx;
	unsigned int edx;
} cpuid_t;

int _is_intel_cpu ()
{
	static int intel_cpu= -1;
	cpuid_t info;

	if ( intel_cpu == -1 ) {
		cpuid(&info, 0, 0);

		if (
			memcmp((char *) &info.ebx, "Genu", 4) ||
			memcmp((char *) &info.edx, "ineI", 4) ||
			memcmp((char *) &info.ecx, "ntel", 4)
		) {
			intel_cpu= 0;
		} else {
			intel_cpu= 1;
		}
	}

	return intel_cpu;
}

void cpuid (cpuid_t *info, unsigned int leaf, unsigned int subleaf)
{
	asm volatile("cpuid"
	: "=a" (info->eax), "=b" (info->ebx), "=c" (info->ecx), "=d" (info->edx)
	: "a" (leaf), "c" (subleaf)
	);
}

代码示例2。 在64位Linux上调用CPUID

通过cpuid()函数使用内联汇编运行CPUID指令。作为预防措施,它被声明为“易失性”,以防止编译器应用可能干扰其执行的优化。

5.2使用RDRAND获得随机值

一旦可以使用CPUID验证对RDRAND的支持,便可以调用RDRAND指令以获得16位,32位或64位随机整数值。请注意,该指令在处理器上的所有特权级别上均可用,因此系统软件和应用程序软件均可自由调用RDRAND。

参考文献 (7)提供了一个描述RDRAND指令用法的表,如下所示:

表2. RDRAND指令参考和操作数编码

操作码/
指令

运/

64/32
位模式支持

CPUID功能
标记

描述

0F C7 / 6
RDRAND r16

一个

V / V

罗格朗德

读取一个16位随机数,并将其存储在目标寄存器中。

0F C7 / 6
RDRAND r32

一个

V / V

罗格朗德

读取一个32位随机数,并将其存储在目标寄存器中。

REX.W + 0F C7 / 6
RDRAND r64

一个

V / I

罗格朗德

读取一个64位随机数,并将其存储在目标寄存器中。

 

打开

操作数1

操作数2

操作数3

操作数4

一个

ModRM:r / m(宽)

不适用

不适用

不适用

 

本质上,开发人员使用单个操作数调用该指令:将存储随机值的目标寄存器。请注意,该寄存器必须是通用寄存器,并且寄存器的大小(16位,32位或64位)将确定返回的随机值的大小。

调用RDRAND指令后,调用方必须检查进位标志(CF),以确定在执行RDRAND指令时是否可以使用随机值。如表3所示,值1表示一个随机值可用,并将其放在调用中提供的目标寄存器中。值为0表示随机值不可用。在当前架构中,由于这种情况的副作用,目标寄存器也将被清零。

注意,目标寄存器值零不应用作随机值可用性的指标。该CF是唯一指标的RDRAND指令的成功或失败。

表3.进位标志(CF)结果语义。

进位标志值

结果

CF = 1

目标寄存器有效。执行时可使用非零随机值。结果存入寄存器。

CF = 0

目标寄存器全零。随机值在执行时不可用。可以重试。

5.2.1重试建议

建议应用程序在RDRAND指令不返回随机数的不太可能发生的情况下,尝试在紧密循环中尝试10次重试。该数字基于二项式概率论证:给定DRNG的设计余量,连续十次失败的几率在天文上很小,实际上这表明CPU问题更大。

5.2.2简单的RDRAND调用

RDRAND指令调用时随机值可能不可用的可能性极小,这对系统或应用程序API的定义有重大影响。尽管许多随机函数的形式非常简单:

unsigned int GetRandom()

使用RDRAND要求包装函数根据CF标志值适当地管理可能的结果。

一种处理方法是简单地将指令结果直接传递回调用例程。这种方法的功能签名可以采用以下形式:

int rdrand(无符号int * therand)

在此,函数的返回值充当标志,向调用者指示RDRAND指令调用的结果。如果返回值为1,则由引用传递的变量将填充一个可用的随机值。如果返回值为0,则调用方将了解分配给该变量的值不可用。这种方法的优势在于,它使呼叫者可以根据呼叫的结果来决定如何进行操作。

代码示例3展示了使用内联汇编为RDRAND的16位,32位和64位调用实现的方法。

#define 

int rdrand16_step (uint16_t *rand)
{
	unsigned char ok;

	asm volatile ("rdrand %0; setc %1"
		: "=r" (*rand), "=qm" (ok));

	return (int) ok;
}

int rdrand32_step (uint32_t *rand)
{
	unsigned char ok;

	asm volatile ("rdrand %0; setc %1"
		: "=r" (*rand), "=qm" (ok));

	return (int) ok;
}

int rdrand64_step (uint64_t *rand)
{
	unsigned char ok;

	asm volatile ("rdrand %0; setc %1"
		: "=r" (*rand), "=qm" (ok));

	return (int) ok;
}

代码示例3.对16位,32位和64位值的简单RDRAND调用

5.2.3 RDRAND重试循环

如果在执行RDRAND时随机值不可用,则另一种方法是使用重试循环。在这种方法中,附加参数允许调用方在返回失败值之前指定最大重试次数。再一次,函数的成功或失败由其返回值指示,假设成功,则实际的随机值(通过成功)由参考变量传递给调用方。

代码示例4显示了带重试循环的RDRAND调用的实现。

int rdrand16_retry (unsigned int retries, uint16_t *rand)
{
	unsigned int count= 0;

	while ( count <= retries ) {
		if ( rdrand16_step(rand) ) {
			return 1;
		}

		++count;
	}

	return 0;
}

int rdrand32_retry (unsigned int retries, uint32_t *rand)
{
	unsigned int count= 0;

	while ( count <= retries ) {
		if ( rdrand32_step(rand) ) {
			return 1;
		}

		++count;
	}

	return 0;
}

int rdrand64_retry (unsigned int retries, uint64_t *rand)
{
	unsigned int count= 0;

	while ( count <= retries ) {
		if ( rdrand64_step(rand) ) {
			return 1;
		}

		++count;
	}

	return 0;
}

代码示例4. 带有重试循环的RDRAND调用

5.2.4初始化任意大小的数据对象

RNG库中的常用功能如下所示:

int rdrand_get_bytes(unsigned int n,unsigned char * dest)

在此函数中,使用随机字节初始化任意大小的数据对象。该大小由变量n指定,数据对象作为指向无符号char或void的指针传入。

要实现此功能,需要一个循环控制结构以及对前面显示的rdrand64_step()或rdrand32_step()函数的迭代调用。为简化起见,让我们首先考虑使用rdrand32_step()以这种方式用随机值填充无符号int数组。

unsigned int rdrand_get_n_uints (unsigned int n, unsigned int *dest)
{
	unsigned int i;
	uint32_t *lptr= (uint32_t *) dest;

	for (i= 0; i< n; ++i, ++dest) {
		if ( ! rdrand32_step(dest) ) {
			return i;
		}
	}

	return n;
}

代码示例5.初始化32位整数数组

该函数返回分配的无符号int值的数量。呼叫者将根据请求的号码检查此值,以确定分配是否成功。其他实现也是可能的,例如,使用重试循环来处理随机数不可用的可能性不大。

在下一个示例中,我们使用rdrand64_step()而不是rdrand32_step()将RDRAND调用的数量减少一半。

unsigned int rdrand_get_n_uints (unsigned int n, unsigned int *dest)
{
	unsigned int i;
	uint64_t *qptr= (uint64_t *) dest;
	unsigned int total_uints= 0;
	unsigned int qwords= n/2;

	for (i= 0; i< qwords; ++i, ++qptr) {
		if ( rdrand64_retry(RDRAND_RETRIES, qptr) ) {
			total_uints+= 2;
		} else {
			return total_uints;
		}
	}

	/* Fill the residual */

	if ( n%2 ) {
		unsigned int *uptr= (unsigned int *) qptr;

		if ( rdrand32_step(uptr) ) {
			++total_uints;
		}
	}

	return total_uints;
}

代码示例6. 使用RDRAND初始化任意大小的对象

最后,我们展示了如何使用循环控制结构和rdrand64_step()填充具有随机值的字节数组。

unsigned int rdrand_get_bytes (unsigned int n, unsigned char *dest)
{
	unsigned char *headstart, *tailstart;
	uint64_t *blockstart;
	unsigned int count, ltail, lhead, lblock;
	uint64_t i, temprand;

	/* Get the address of the first 64-bit aligned block in the
	 * destination buffer. */

	headstart= dest;
	if ( ( (uint64_t)headstart % (uint64_t)8 ) == 0 ) {

		blockstart= (uint64_t *)headstart;
		lblock= n;
		lhead= 0;
	} else {
		blockstart= (uint64_t *) 
			( ((uint64_t)headstart & ~(uint64_t)7) + (uint64_t)8 );

		lblock= n - (8 - (unsigned int) ( (uint64_t)headstart & (uint64_t)8 ));

		lhead= (unsigned int) ( (uint64_t)blockstart - (uint64_t)headstart );
	}

	/* Compute the number of 64-bit blocks and the remaining number
	 * of bytes (the tail) */

	ltail= n-lblock-lhead;
	count= lblock/8;	/* The number 64-bit rands needed */

	if ( ltail ) {
		tailstart= (unsigned char *)( (uint64_t) blockstart + (uint64_t) lblock );
	}

	/* Populate the starting, mis-aligned section (the head) */

	if ( lhead ) {
		if ( ! rdrand64_retry(RDRAND_RETRIES, &temprand) ) {
			return 0;
		}

		memcpy(headstart, &temprand, lhead);
	}

	/* Populate the central, aligned block */

	for (i= 0; i< count; ++i, ++blockstart) {
		if ( ! rdrand64_retry(RDRAND_RETRIES, blockstart) ) {
			return i*8+lhead;
		}
	}

	/* Populate the tail */

	if ( ltail ) {
		if ( ! rdrand64_retry(RDRAND_RETRIES, &temprand) ) {
			return count*8+lhead;
		}

		memcpy(tailstart, &temprand, ltail);
	}

	return n;
}

代码示例7. 使用RDRAND初始化任意大小的对象

5.2.5保证DBRG重新播种

作为随机数的高性能来源,DRNG既快速又可扩展。它可以直接用作应用程序或操作系统RNG库基础上的随机值的唯一来源。尽管如此,一些软件供应商仍希望使用DRNG对其当前的软件PRNG进行播种和重新播种。为了符合标准,有些人可能有必要要求绝对保证RDRAND返回的值反映DRNG中的独立熵样本。

如3.2.3节所述,DRNG使用确定性随机位生成器或DRBG将条件熵样本“扩展”为一大组随机值,​​从而增加了硬件模块可用的随机数。DRBG自主决定何时需要重新播种,其行为方式对于RDRAND调用者来说是不可预测的且透明的。在实现中,每个种子有511个样本的上限,其中样本大小为128位,每个样本可以提供两个64位随机数。实际上,DRBG经常被重新播种,并且通常情况是在RDRAND可以请求最大样本数之前很久就发生了重新播种。

有两种方法可以构造RDRAND调用,从而可以保证DRBG重新播种:

  • 通过执行超过1022个64位RDRAND,以迭代方式执行超出DRBG上限的RDRAND
  • 迭代执行32次RDRAND调用,每次迭代等待时间为10 us。

后一种方法具有强制重新播种事件的效果,因为DRBG在空闲期间会主动播种。

5.2.6从RDRAND生成种子

不支持RDSEED指令的处理器可以利用DRBG的重新播种保证从通过RDRAND获得的值生成随机种子。

下面的程序采用保证重播的第一种方法-生成512 128位随机数-并使用AES的CBC-MAC模式将中间值混合在一起。这种将来自DRNG的512个128位样本转换为128位种子值的方法有时被称为“ 512:1数据缩减”,并且会产生一个完全抵抗前向和后向预测的随机值,适用于播种符合NIST SP800-90,FIPS 140-2认证的软件DRBG。

该程序依赖于Gnu Project的libgcrypt进行加密例程。

#include “drng.h”
#include 
#include 
#include 

#define AES_BLOCK_SIZE	16	/* AES uses 128-bit blocks (16 bytes) */
#define AES_KEY_SIZE	16	/* AES with 128-bit key (AES-128) */
#define	RDRAND_SAMPLES	512	/* the DRNG reseeds after generating 511
				 * 128-bit (16-byte) values */
#define BUFFER_SIZE		16*RDRAND_SAMPLES

#define MIN_GCRYPT_VERSION "1.0.0"

int main (int argc, char *argv[])
{
	unsigned char rbuffer[BUFFER_SIZE];
	unsigned char aes_key[AES_KEY_SIZE];
	unsigned char aes_iv[AES_KEY_SIZE];
	unsigned char seed[16];
	static gcry_cipher_hd_t gcry_cipher_hd;
	gcry_error_t gcry_error;

	if ( ! ( get_drng_support() & DRNG_HAS_RDRAND ) ) {
		fprintf(stderr, "No RDRAND supportn");
		return 1;
	}

	/* Generate a random AES key */

	if ( rdrand_get_bytes(AES_KEY_SIZE, aes_key) < AES_KEY_SIZE ) {
		fprintf(stderr, "Random numbers not availablen");
		return 1;
	}

	/* Generate a random IV */

	if ( rdrand_get_bytes(AES_BLOCK_SIZE, aes_iv) < AES_BLOCK_SIZE ) {
		fprintf(stderr, "Random numbers not availablen");
		return 1;
	}

	/*
	 * Fill our buffer with 512 128-bit rdrands. This 
	 * guarantees that /at least/ one reseed takes place.
	 */

	if ( rdrand_get_bytes(BUFFER_SIZE, rbuffer) < BUFFER_SIZE ) {
		fprintf(stderr, "Random numbers not availablen");
		return 1;
	}

	/* Initialize the cryptographic library */

	if (!gcry_check_version(MIN_GCRYPT_VERSION)) {
		fprintf(stderr,
			"gcry_check_version: have version %s, need version %s or newer",
			gcry_check_version(NULL), MIN_GCRYPT_VERSION
		);

		return 1;
	}

	gcry_error= gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_AES128,
		GCRY_CIPHER_MODE_CBC, 0);
	if ( gcry_error ) {
		fprintf(stderr, "gcry_cipher_open: %s", gcry_strerror(gcry_error));
		return 1;
	}

	gcry_error= gcry_cipher_setkey(gcry_cipher_hd, aes_key, AES_KEY_SIZE);
	if ( gcry_error ) { 
		fprintf(stderr, "gcry_cipher_setkey: %s", gcry_strerror(gcry_error));
		gcry_cipher_close(gcry_cipher_hd);
		return 1;
	}

	gcry_error= gcry_cipher_setiv(gcry_cipher_hd, aes_iv, AES_BLOCK_SIZE);
	if ( gcry_error ) { 
		fprintf(stderr, "gcry_cipher_setiv: %s", gcry_strerror(gcry_error));
		gcry_cipher_close(gcry_cipher_hd);
		return 1;
	}

	/* 
	 * Do the encryption in-place. This has the nice side effect of 
	 * erasing the original values.
	 */

	gcry_error= gcry_cipher_encrypt(gcry_cipher_hd, rbuffer, BUFFER_SIZE,
		NULL, 0);
	if ( gcry_error ) {
		fprintf(stderr, "gcry_cipher_encrypt: %sn",
			gcry_strerror(gcry_error));
		return 1;
	}

	gcry_cipher_close(gcry_cipher_hd);

	/* The last block of the cipher text is the MAC, and our seed value. */

	memcpy(seed, &rbuffer[BUFFER_SIZE-16], 16);


代码示例8.从RDRAND生成随机种子

5.3使用RDSEED获取随机种子

一旦使用CPUID验证了对RDSEED的支持,便可以使用RDSEED指令获取16位,32位或64位随机整数值。同样,该指令在处理器上的所有特权级别上都可用,因此系统软件和应用程序软件都可以自由调用RDSEED。

RDSEED指令记录在(9)中。用法如下:

表4. RDSEED指令参考和操作数编码

操作码/
指令

运/

64/32
位模式支持

CPUID功能
标记

描述

0F C7 / 7
RDSEED r16

一个

V / V

RDSEED

读取一个16位随机数,并将其存储在目标寄存器中。

0F C7 / 7
RDSEED r32

一个

V / V

RDSEED

读取一个32位随机数,并将其存储在目标寄存器中。

REX.W + 0F C7 / 7
RDSEED r64

一个

V / I

RDSEED

读取一个64位随机数,并将其存储在目标寄存器中。

 

打开

操作数1

操作数2

操作数3

操作数4

一个

ModRM:r / m(宽)

不适用

不适用

不适用

 

与RDRAND一样,开发人员使用将存储随机种子的目标寄存器调用RDSEED指令。该寄存器必须是通用寄存器,其大小决定了返回的随机种子的大小。

调用RDSEED指令后,调用方必须检查进位标志(CF),以确定在执行RDSEED指令时是否有随机种子可用。如表5所示,值1表示有一个随机种子可用,并将其放入调用中提供的目标寄存器中。值为0表示没有随机种子。在当前架构中,由于这种情况的副作用,目标寄存器也将被清零。

同样,目标寄存器值为零不应用作随机种子可用性的指标。CF是RDSEED指令成功或失败唯一指示。

表5.进位标志(CF)结果的语义

进位标志值

结果

CF = 1

目标寄存器有效。执行时可使用非零的随机种子。结果存入寄存器。

CF = 0

目标寄存器全零。执行时不提供随机种子。可以重试。

5.3.1重试建议

与RDRAND指令不同,种子值直接来自熵调节器,并且调用者调用RDSEED的速度可能比生成这些值的速度快。这意味着必须对应用程序进行健壮的设计,并为调用RDSEED失败做准备,因为种子不可用(CF = 0)。

如果只有一个线程很少调用RDSEED,则随机种子将不可用的可能性很小。仅在需求旺盛的时期(例如,一个线程快速连续地调用RDSEED或多个线程同时调用RDSEED时),才可能发生下溢。但是,由于RDSEED指令没有内置公平机制,因此无法保证线程应多久重试一次该指令,或者需要多少次重试才能获得随机种子。实际上,这取决于CPU上的硬件线程数量以及它们调用RDSEED的积极程度。

由于没有重试指令以获得随机种子的简单过程,因此请遵循这些基本准则。

5.3.1.1同步应用

如果应用程序对延迟不敏感,则尽管建议将PAUSE指令放在重试循环中,但它可以无限期地重试RDSEED指令。在最坏的情况下,当多个线程连续调用RDSEED时,延迟可能会很长,但是延迟时间越长,指令返回结果的可能性就越大(概率呈指数增长)。

如果应用程序对延迟敏感,则应用程序应休眠或后退以从RDRAND生成种子值。

5.3.1.2异步应用

重试几次后,应用程序应该准备放弃RDSEED,其中“小”值介于1到100之间,具体取决于应用程序对延迟的敏感度。与同步应用程序一样,建议将PAUSE指令插入重试循环。

需要更激进方法的应用程序可以在RDSEED和RDRAND之间交替使用,从RDSEED抽取种子(如果有),并填充RDRAND缓冲区,以便将来不使用512:1时将其减少。

5.3.2简单的RDSEED调用

代码示例9显示了16位,32位和64位RDSEED调用的内联汇编实现。

int rdseed16_step (uint16_t *seed)
{
	unsigned char ok;

	asm volatile ("rdseed %0; setc %1"
		: "=r" (*seed), "=qm" (ok));

	return (int) ok;
}

int rdseed32_step (uint32_t *seed)
{
	unsigned char ok;

	asm volatile ("rdseed %0; setc %1"
		: "=r" (*seed), "=qm" (ok));

	return (int) ok;
}

int rdseed64_step (uint64_t *seed)
{
	unsigned char ok;

	asm volatile ("rdseed %0; setc %1"
		: "=r" (*seed), "=qm" (ok));

	return (int) ok;
}

代码示例9.对16位,32位和64位值的简单RDSEED调用

6.总结

带有安全密钥的英特尔数据保护技术代表了新型的随机数生成器。它将高质量的熵源与CSPRNG结合到一个功能强大,功能齐全的硬件模块中,该模块与软件攻击无关。产生的随机数具有出色的统计质量,高度不可预测的随机序列和高性能。通过两个简单的指令RDRAND和RDSEED即可访问,随机数生成器也非常易于使用。随机数适用于在所有特权级别运行的软件,并且不需要特殊的库或操作系统处理。

 

参考

1. Mersenne Twister:一个623维均匀分布的伪随机数生成器。西村,松本诚和高二。1998年1月1日,ACM Transactions on Modeling and Computer Simulation,第1卷。8。

2. Z. Gutterman,B。Pinkas和T. Reinman。Linux随机数生成器分析。[在线] 2006年3月。http://software.intel.com/sites/default/files/m/6/0/9/gpr06.pdf

3. CVE-2008-0166。常见漏洞和披露。[在线] 2008年1月9日。http ://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-0166

4.高级加密标准(AES)的规范。[在线] 2001年11月26日。http://software.intel.com/sites/default/files/m/4/d/d/fips-197.pdf

5.块密码模式操作的建议:CBC模式的三种密文窃取方式。[在线] 2010年10月。http://csrc.nist.gov/publications/nistpubs/800-38a/addendum-to-nist_sp800-38A.pdf

6.关于使用确定性随机位生成器生成随机数的建议(修订版)。[在线] 2012年1月。http ://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf

7.英特尔®64和IA-32体系结构软件开发人员手册,第2卷:指令集参考,AZ。[在线] http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

8.英特尔®处理器标识和CPUID指令。[在线] 2012年4月。http://www.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html

9.英特尔®体系结构指令集扩展编程参考。[在线] https://software.intel.com/zh-cn/intel-isa-extensions

英特尔和英特尔徽标是英特尔公司在美国和其他国家(地区)的商标。
*其他名称和品牌可能归其他所有者所有。
版权所有©2018英特尔公司。版权所有。

其他资源

Windows *,Linux *和OS X *的DRNG库

商业客户讨论论坛

博客:什么是英特尔®安全密钥技术?

推荐阅读