RdRand

**`RDRAND`**（之前被稱為 **Bull Mountain**）是一個電腦指令，用於從晶片上的硬體亂數生成器中取得亂數。所用到的亂數生成器由晶片上的熵池初始化。 `RDRAND` 指令在 Ivy Bridge 架構處理器上可用，該指令也是 X86-64 和 IA-32 指令集的一部分。AMD 在 2015 年 6 月添加了對 `RdRand` 指令的支援。

該亂數生成器要遵守安全標準和加密標準，比如 NIST SP 800-90A， FIPS 140-2 和 ANSI X9.82。 Intel 也在 1999 年和 2012 年請密碼學研究 Cryptography Research 公司來審查這個亂數發生器，並產生了兩篇論文：1999 年的 _The Intel Random Number Generator_ 和 2012 年的 _Analysis of Intel's Ivy Bridge Digital Random Number Generator_。

**`RDSEED`** 和 `RDRAND` 類似，也提供了存取硬體熵池的進階方法。
Intel Broadwell 系列的 CPU 和 AMD Zen 系列的 CPU 都支援 `RDSEED` 生成器和 `rdseed` 指令。

## 概略

在 AMD 和 Intel 的 CPU 上，`CPUID` 指令都可以檢測中央處理器（CPU）是否支援 `RDRAND` 指令。如果支援，呼叫 CPUID 的標準函式 `01H` 之後，ECX 暫存器的第 30 位會被設定成 1。AMD 處理器也可以使用同樣的方式檢測是否支援。在 Intel CPU 上，也可以使用類似的方法檢測 `RDSEED` 是否支援。如果支援 `RDSEED`，在呼叫完 CPUID 的標準函式 `07H` 後，EBX 暫存器的第 18 位元會被設定為 1。

`RDRAND` 的操作碼是 `0x0F 0xC7`，後面跟一個 ModRM 位元組，來指示目標暫存器。在 64 位元模式下，還可以於 REX 字首結合（這是可選的）。

_Intel 安全金鑰_是 Intel 為 `RDRAND` 指令和底層的亂數生成器（RNG）的硬體實現的統稱，它在開發期間的代號是 "Bull Mountain"。Intel 稱自己的 RNG"數字亂數生成器" 或 DRNG。生成器採用有硬體產生的 256 位原始熵樣本對，並將其應用到一個進階加密標準（AES）（在 CBC-MAC 模式下）調節器，將其減少到 256 位條件熵樣本。

NIST SP 800-90A 中定義了一個名叫 CTR\_DRBG 的確定性亂數生成器。它由調節器的輸出來初始化，為使用 `RDRAND` 指令的應用程式提供了密碼學安全的亂數。 在重新初始化之前，硬體將發出最多 511 個 128 位元的樣本。使用 `RDSEED` 可以存取來自 AES-CBC-MAC 的、條件化後的 256 位樣本。

 
為了初始化另一個為亂數生成器，`RDSEED` 指令被添加到了 Intel 安全金鑰，在 Broadwell 微架構的 CPU 上開始支援。`RDSEED` 指令的熵來源自時序線路，並且使用矽片上的熱噪聲來以 3GHz 的速度輸出隨機位元流。這比從 `RDRAND` 獲得的 6.4Gbit/s 速率要慢（這兩個速率都是所有核心、所有執行緒共享）。`RDSEED` 用來初始化任意寬度的軟體 PRNG，而 `RDRAND` 指令適用於需要高品質亂數的應用程式。如果不要求密碼學安全，軟體亂數生成器比如 Xorshift 一般會比較快。

### 效能

在 Intel 酷睿 i7-7700K，4500MHz（45 x 100MHz）的處理器（Kaby Lake-S 架構）上，單個 `RDRAND` 或 `RDSEED` 指令花費 110 奈秒或 463 個時鐘周期，不論運算元大小（16 位元、32 位元、64 位元）。這個時鐘周期數適用於所有 Skylake 和 Kaby Lake 架構的處理器。在 Silvermont 架構的處理器上，每個指令花費 1472 時鐘周期，不論運算元大小；在 Ivy Bridge 架構的處理器上，花費 117 時鐘周期。

在 AMD Ryzen 處理器上，對於 16 位元或 32 位元運算元，每個指令約花費 1200 個時鐘周期；對於 64 位元運算元，約花費 2500 個時鐘周期。

### 編譯器支援

GCC 4.6 + 和 Clang 3.2 + 提供了 RdRand 的內建支援 —— 當在編譯參數中指定了 `-mrdrnd` 命令列參數、並且在條件編譯時設定 `__RDRND__` 巨集的情況下。更新的版本額外提供了 `immintrin.h` 將這些內建函式封裝成與英特爾 C 編譯器版本 12.1 + 相容的功能中。這些函式將亂數據寫入參數指定的位置，並在成功時返回 1 。

### 用來檢測 RDRAND 指令的 x86 組合語言例子

## Reception

在 2013 年 9 月，曹子德（Theodore Ts'o）為回應_紐約時報_的文章 Global surveillance disclosures (2013–present)，公開發文表達對 Linux 核心的 /dev/random 中使用 RdRand 的擔憂：

> I am so glad I resisted pressure from Intel engineers to let /dev/random rely only on the RDRAND instruction. To quote from the article below: 'By this year, the Sigint Enabling Project had found ways inside some of the encryption chips that scramble information for businesses and governments, either by working with chipmakers to insert back doors....' Relying solely on the hardware random number generator which is using an implementation sealed inside a chip which is impossible to audit is a BAD idea.
> 
> 

林納斯・托瓦茲駁斥了在 Linux 核心中使用 RdRand 的擔憂，並指出 RdRand 不是 /dev/random 的唯一熵來源；從 RdRand 接受資料並和其他亂數來源結合來改善熵。 然而，Defuse Security 的 Taylor Hornby 表明，如果將後門引入到專門針對使用代碼的 RdRand 指令中，Linux 亂數生成器可能會變得不安全。 泰勒的概念驗證實現在版本 3.13 之前的未修改的 Linux 核心上工作。

開發者注釋掉了 FreeBSD 核心中直接使用 RdRand 和威盛電子的代碼，並添加說明 "對於 FreeBSD 10，我們將回溯並刪除 RDRAND 和 Padlock 後端，並將它們提供給 Yarrow，而不是將其輸出直接傳遞到 /dev/random 。如果需要，還可以通過行內組譯或使用 OpenSSL 直接存取硬體亂數生成器，即 RDRAND，Padlock 等，但是我們不能再信任他們。"

## 參見

* AES 指令集
* Bullrun (NSA 計畫)
* OpenSSL
* wolfSSL

## 註腳

## 參考資料