1. 程式人生 > 實用技巧 >/dev/random 和 /dev/urandom的一點備忘

/dev/random 和 /dev/urandom的一點備忘

摘自:https://www.cnblogs.com/ohmygirl/p/random.html

1. 基本介紹  

  /dev/random和/dev/urandom是Linux系統中提供的隨機偽裝置,這兩個裝置的任務,是提供永不為空的隨機位元組資料流。很多解密程式與安全應用程式(如SSH Keys,SSL Keys等)需要它們提供的隨機資料流。

  這兩個裝置的差異在於:/dev/random的random pool依賴於系統中斷,因此在系統的中斷數不足時,/dev/random裝置會一直封鎖,嘗試讀取的程序就會進入等待狀態,直到系統的中斷數充分夠用, /dev/random裝置可以保證資料的隨機性。/dev/urandom不依賴系統的中斷,也就不會造成程序忙等待,但是資料的隨機性也不高。

  使用cat命令可以讀取/dev/random 和/dev/urandom的資料流(二進位制資料流,很難閱讀),可以用od命令轉換為十六進位制後檢視:

  

  

在cat的過程中發現,/dev/random產生的速度比較慢,有時候還會出現較大的停頓,而/dev/urandom的產生速度很快,基本沒有任何停頓。

而使用dd命令從這些裝置中copy資料流,發現速度差異很大:

從/dev/random中讀取1KB的位元組流:

  

從/dev/urandom 中讀取1KB的位元組流:

  

通過程式測試也發現:/dev/random裝置被讀取的越多,它的響應越慢.

使用PHP的加密擴充套件mcrypt時,mcrypt_create_iv()函式用於從隨機源建立初始向量(initialization vector),該函式的簽名為:

string mcrypt_create_iv ( int $size [, int $source = MCRYPT_DEV_URANDOM ] )

注意函式的第二個引數$source,在PHP 5.6.0以下的版本中,該引數預設是MCRYPT_DEV_RANDOM,也就是說,mcrypt_create_iv預設從/dev/random裝置獲取隨機資料來源的。這在系統併發數較高時,系統無法提供足夠的中斷數,會導致訪問程序掛起(鎖住),從而無法正常響應。

一個簡單的測試指令碼如下:

1 <?php
2 define("MCRYPT_KEY","x90!-=zo2s");
3 $src = "test";
4 
5 $size = mcrypt_get_iv_size(MCRYPT_BLOWFISH,MCRYPT_MODE_ECB);
6 $iv = mcrypt_create_iv($size);
7 $encrypted = mcrypt_ecb(MCRYPT_BLOWFISH, MCRYPT_KEY, $src, MCRYPT_DECRYPT, $iv);//5.5+已廢棄,請使用最新的API測試

我們之前在cat /dev/random的輸出時已經發現,輸出的隨機資料流會出現較大的停頓。在併發數較大時,會造成讀取程序的等待甚至無法響應。

幸好,我們可以指定第二個引數為MCRYPT_DEV_URANDOM使其強制使用/dev/urandom裝置的隨機資料流(PHP 5.6.0+版本中,已經預設使用/dev/urandom作為隨機資料來源)。

2. /dev/random和/dev/random的其他用途

  1.  這兩個偽裝置可用於代替mktemp產生隨機臨時檔名:

cat /dev/urandom |od –x | tr –d  ' '| head –n 1

  可以產生128位(bit)的臨時檔名,具有較高的隨機性和安全性。

  2.  可以模擬生成SSH-keygen生成的footprint,指令碼如下:

 1 #/bin/sh -
 2 cat /dev/urandom |
 3 od -x |
 4 head -n 1|
 5 cut -d ' ' -f 2- |
 6 awk -v ORS=":" 
 7 '{
 8     for(i=1; i<=NF; i++){
 9         if(i == NF){
10             ORS = "\n";
11         }
12         print substr($i,1,2) ":" substr($i,3,2);
13     }
14 }'

對該指令碼的簡單解釋:

  (1).  cat /dev/urandom | od -x | head -n 1 用於從隨機裝置中讀取一行資料流並轉換為16進位制。該段的輸出類似於:

    

  (2).  由於第一列實際上是資料的偏移量,並不是隨機資料流,再次用cut取出後面的幾個欄位:cut -d'' -f2-

  (3).  利用awk程式輸出。ORS是awk的內建變數,指輸出記錄分割符,預設為\n。

  指令碼的輸出結果:

  

  對比用ssh-keygen生成的footprint,是不是挺像的? :D