關於 GnuPG 的 RNG 漏洞(08/17) — CVE-2016-6313

Home » Debian » 關於 GnuPG 的 RNG 漏洞(08/17) — CVE-2016-6313
2016-08-28 Debian, GNU, gnupg, RNG, 亂數 尚無留言

以下是 OLS3  個人的理解,若有錯誤,還請海涵。 😉

德國卡爾斯魯厄理工學院的二位研究人員日前發現了 GnuPG 中的亂數產生器(RNG:random number generator)有一個漏洞,攻擊者只要由 RNG 取得 4640 個位元的資料,即可輕易地預測接下來的 160 個位元的資料會是什麼,或者說每 580 個位元,即可預測接下來的 20 個位元。這是自 1998 年以來,長期隱藏在 libgcrypt 和 GunPG 中的臭虫哩!

該項漏洞,對現有已產生的 RSA 密鑰不會有任何威脅,DSA 和 Elgamal 密鑰也不像可以由公開的資訊來推測得到,理由如下:

  1. gpg 在建立密鑰時,只使用二次 RNG。
  2. 對  4096 位元長度的 RSA 密鑰而言,只需由 RNG 隨機產生 512 位元的資料。
  3. RNG 第二次產生的資料,只有 20 位元可以由前一次推測得到,因此,就可預測的長度而言,沒有任何危險。
  4. 如果 RSA 密鑰只取  2048 個位元長度的話,由於 RNG 只需負責隨機產出 256 個位元,那就無法預測了,所以,也不會有任何問題。

這個漏洞目前已經修正了,Debian Linux 穩定版(Jessie)已推出修正套件 gnupg 1.4.18-7+deb8u2。

我們來看一下,這個 RNG 漏洞是怎麼修補的:

CVE-id: CVE-2016-6313
Signed-off-by: Werner Koch <wk@gnupg.org>
---
 cipher/random.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/cipher/random.c b/cipher/random.c
index be2f51a..5f7de51 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -360,23 +360,21 @@ mix_pool(byte *pool)
 #if DIGESTLEN != 20
 #error must have a digest length of 20 for ripe-md-160
 #endif
-    /* loop over the pool */
+    /* pool -> pool' */
     pend = pool + POOLSIZE;
     memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
     memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
     rmd160_mixblock( &md, hashbuf);
     memcpy(pool, hashbuf, DIGESTLEN);
 
+    /* Loop for the remaining iterations.  */
     p = pool;
     for( n=1; n < POOLBLOCKS; n++ ) {
-	memcpy(hashbuf, p, DIGESTLEN );
-
-	p += DIGESTLEN;
-	if( p+DIGESTLEN+BLOCKLEN < pend )
-	    memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
+	if( p + BLOCKLEN < pend )
+	    memcpy(hashbuf, p, BLOCKLEN);
 	else {
-	    char *pp = p+DIGESTLEN;
-	    for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
+	    char *pp = p;
+	    for(i=0; i < BLOCKLEN; i++ ) {
 		if( pp >= pend )
 		    pp = pool;
 		hashbuf[i] = *pp++;
@@ -384,6 +382,7 @@ mix_pool(byte *pool)
 	}
 
 	rmd160_mixblock( &md, hashbuf);
+        p += DIGESTLEN;
 	memcpy(p, hashbuf, DIGESTLEN);
     }
     burn_stack (384); /* for the rmd160_mixblock() */
-- 
2.1.4

由上述 patch 中,我們可以發現,問題出在兩點:

  1. 密鑰區塊的長度(DIGESTLEN)一開始就固定在 20 位元的長度,
  2.  並且,memcpy(hashbuf, p, DIGESTLEN ) 以每 20 位元一個區塊的方式拷貝到記憶體暫存區,這就讓攻擊者有機可乘了!

因此,只要變更這種固定長度拷貝密鑰區塊到暫存區的做法,那麼,問題自然就消失啦!

奇怪的是,自 1998 年以來,從來沒有人認為上述做法會有什麼問題。

這讓我想起高德納教授(Donald Ervin Knuth)在其巨著 The Art of Computer Programming 第二冊中有一章,專門在講亂數(RANDOM NUMBERS),大三那一年,當我讀到這一章時,大為震驚,原來如果不講究方法的話,亂數不是真的夠亂!人們總是認為亂數的程序做法應該不會有什麼問題因為它已經試著去以亂取亂了!事實上不然,並不是只要方法隨機,就可做到足夠亂而無法預測的亂數機制!

今日,以高德納教授的觀點來看,這個漏洞為何會從 1998 年就持續到現在,其根本的原因,真是不謀而合!

我們這個世界,表面上總是在追求各種「秩序」,「亂」總是礙人眼,但是,你知道嗎?「亂」只要能夠做到「夠亂」,那對人類而言,亂數可說是非常有用的!

其應用範圍至少包括:

  • 密碼學
  • 資訊安全
  • 仿真
  • 抽樣
  • 數值分析
  • 計算機程序
  • 決策
  • 圖型美學、音樂
  • 娛樂(賭博、彩劵)

至於其他細項,敝人就不再分說了。

但是,相對的,如果亂數做得不夠亂的話,那麼,也很有可能會引起各種大大小小的災難!這對即將到來的機器人世代和物連網而言,人們對此真的要非常小心謹慎才行!

亂數怎麼樣才算夠亂怎麼樣才可以夠亂?這些題目,真的很有研究價值,有興趣的人,可以參考高德納教授的巨著或者其他論文,相信一定會有許多非常有趣的收穫。

 

LEAVE A COMMENT

  ×  5  =  fifteen

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料