以下是 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 年就持續到現在,其根本的原因,真是不謀而合!
我們這個世界,表面上總是在追求各種「秩序」,「亂」總是礙人眼,但是,你知道嗎?「亂」只要能夠做到「夠亂」,那對人類而言,亂數可說是非常有用的!
其應用範圍至少包括:
- 密碼學
- 資訊安全
- 仿真
- 抽樣
- 數值分析
- 計算機程序
- 決策
- 圖型美學、音樂
- 娛樂(賭博、彩劵)
至於其他細項,敝人就不再分說了。
但是,相對的,如果亂數做得不夠亂的話,那麼,也很有可能會引起各種大大小小的災難!這對即將到來的機器人世代和物連網而言,人們對此真的要非常小心謹慎才行!
亂數怎麼樣才算夠亂?怎麼樣才可以夠亂?這些題目,真的很有研究價值,有興趣的人,可以參考高德納教授的巨著或者其他論文,相信一定會有許多非常有趣的收穫。