以下是 OLS3 個人的理解,若有錯誤,還請海涵。 😉
德國卡爾斯魯厄理工學院的二位研究人員日前發現了 GnuPG 中的亂數產生器(RNG:random number generator)有一個漏洞,攻擊者只要由 RNG 取得 4640 個位元的資料,即可輕易地預測接下來的 160 個位元的資料會是什麼,或者說每 580 個位元,即可預測接下來的 20 個位元。這是自 1998 年以來,長期隱藏在 libgcrypt 和 GunPG 中的臭虫哩!
該項漏洞,對現有已產生的 RSA 密鑰不會有任何威脅,DSA 和 Elgamal 密鑰也不像可以由公開的資訊來推測得到,理由如下:
- gpg 在建立密鑰時,只使用二次 RNG。
- 對 4096 位元長度的 RSA 密鑰而言,只需由 RNG 隨機產生 512 位元的資料。
- RNG 第二次產生的資料,只有 20 位元可以由前一次推測得到,因此,就可預測的長度而言,沒有任何危險。
- 如果 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 中,我們可以發現,問題出在兩點:
- 密鑰區塊的長度(DIGESTLEN)一開始就固定在 20 位元的長度,
- 並且,memcpy(hashbuf, p, DIGESTLEN ) 以每 20 位元一個區塊的方式拷貝到記憶體暫存區,這就讓攻擊者有機可乘了!
因此,只要變更這種固定長度拷貝密鑰區塊到暫存區的做法,那麼,問題自然就消失啦!
奇怪的是,自 1998 年以來,從來沒有人認為上述做法會有什麼問題。
這讓我想起高德納教授(Donald Ervin Knuth)在其巨著 The Art of Computer Programming 第二冊中有一章,專門在講亂數(RANDOM NUMBERS),大三那一年,當我讀到這一章時,大為震驚,原來「如果不講究方法的話,亂數不是真的夠亂!」,人們總是認為亂數的程序做法應該不會有什麼問題,因為它已經試著去以亂取亂了!事實上不然,並不是只要方法隨機,就可做到足夠亂而無法預測的亂數機制!
今日,以高德納教授的觀點來看,這個漏洞為何會從 1998 年就持續到現在,其根本的原因,真是不謀而合!
我們這個世界,表面上總是在追求各種「秩序」,「亂」總是礙人眼,但是,你知道嗎?「亂」只要能夠做到「夠亂」,那對人類而言,亂數可說是非常有用的!
其應用範圍至少包括:
- 密碼學
- 資訊安全
- 仿真
- 抽樣
- 數值分析
- 計算機程序
- 決策
- 圖型美學、音樂
- 娛樂(賭博、彩劵)
至於其他細項,敝人就不再分說了。
但是,相對的,如果亂數做得不夠亂的話,那麼,也很有可能會引起各種大大小小的災難!這對即將到來的機器人世代和物連網而言,人們對此真的要非常小心謹慎才行!
亂數怎麼樣才算夠亂?怎麼樣才可以夠亂?這些題目,真的很有研究價值,有興趣的人,可以參考高德納教授的巨著或者其他論文,相信一定會有許多非常有趣的收穫。
