㈠ Hello,密碼學:第三部分,公鑰密碼(非對稱密碼)演算法
在 《Hello,密碼學:第二部分,對稱密碼演算法》 中講述了對稱密碼的概念,以及DES和AES兩種經典的對稱密碼演算法原理。既然有對稱密碼的說法,自然也就有非對稱密碼,也叫做公鑰密碼演算法。 對稱密碼和非對稱密碼兩種演算法的本質區別在於,加密密鑰和解密密鑰是否相同 :
公鑰密碼產生的初衷就是為了解決 密鑰配送 的問題。
Alice 給遠方的 Bob 寫了一封情意慢慢的信,並使用強悍的 AES-256 進行了加密,但她很快就意識到,光加密內容不行,必須要想一個安全的方法將加密密鑰告訴 Bob,如果將密鑰也通過網路發送,很可能被技術高手+偷窺癖的 Eve 竊聽到。
既要發送密鑰,又不能發送密鑰,這就是對稱密碼演算法下的「密鑰配送問題」 。
解決密鑰配送問題可能有這樣幾種方法:
這種方法比較高效,但有局限性:
與方法一不同,密鑰不再由通信個體來保存,而由密鑰分配中心(KDC)負責統一的管理和分配。 雙方需要加密通信時,由 KDC 生成一個用於本次通信的通信密鑰交由雙方,通信雙方只要與 KDC 事先共享密鑰即可 。這樣就大大減少密鑰的存儲和管理問題。
因此,KDC 涉及兩類密鑰:
領略下 KDC 的過程:
KDC 通過中心化的手段,確實能夠有效的解決方法一的密鑰管理和分配問題,安全性也還不錯。但也存在兩個顯著的問題:
使用公鑰密碼,加密密鑰和解密密鑰不同,只要擁有加密密鑰,所有人都能進行加密,但只有擁有解密密鑰的人才能進行解密。於是就出現了這個過程:
密鑰配送的問題天然被解決了。當然,解密密鑰丟失而導致信息泄密,這不屬於密鑰配送的問題。
下面,再詳細看下這個過程。
公鑰密碼流程的核心,可以用如下四句話來概述:
既然加密密鑰是公開的,因此也叫做 「公鑰(Public Key)」 。
既然解密密鑰是私有的,因此也叫做 「私鑰(Private Key) 。
公鑰和私鑰是一一對應的,稱為 「密鑰對」 ,他們好比相互糾纏的量子對, 彼此之間通過嚴密的數學計算關系進行關聯 ,不能分別單獨生成。
在公鑰密碼體系下,再看看 Alice 如何同 Bob 進行通信。
在公鑰密碼體系下,通信過程是由 Bob 開始啟動的:
過程看起來非常簡單,但為什麼即使公鑰被竊取也沒有關系?這就涉及了上文提到的嚴密的數學計算關系了。如果上一篇文章對稱密鑰的 DES 和 AES 演算法進行概述,下面一節也會對公鑰體系的數學原理進行簡要說明。
自從 Diffie 和 Hellman 在1976年提出公鑰密碼的設計思想後,1978年,Ron Rivest、Adi Shamir 和 Reonard Adleman 共同發表了一種公鑰密碼演算法,就是大名鼎鼎的 RSA,這也是當今公鑰密碼演算法事實上的標准。其實,公鑰密碼演算法還包括ElGamal、Rabin、橢圓曲線等多種演算法,這一節主要講述 RSA 演算法的基本數學原理。
一堆符號,解釋下,E 代表 Encryption,D 代表 Decryption,N 代表 Number。
從公式種能夠看出來,RSA的加解密數學公式非常簡單(即非常美妙)。 RSA 最復雜的並非加解密運算,而是如何生成密鑰對 ,這和對稱密鑰演算法是不太一樣的。 而所謂的嚴密的數學計算關系,就是指 E 和 D 不是隨便選擇的 。
密鑰對的生成,是 RSA 最核心的問題,RSA 的美妙與奧秘也藏在這裡面。
1. 求N
求 N 公式:N = p × q
其中, p 和 q 是兩個質數 ,而且應該是很大又不是極大的質數。如果太小的話,密碼就容易被破解;如果極大的話,計算時間就會很長。比如 512 比特的長度(155 位的十進制數字)就比較合適。
這樣的質數是如何找出來的呢? 需要通過 「偽隨機數生成器(PRNG)」 進行生成,然後再判斷其是否為質數 。如果不是,就需要重新生成,重新判斷。
2. 求L
求 L 公式:L = lcm(p-1, q-1)
lcm 代表 「最小公倍數(least common multiple)」 。注意,L 在加解密時都不需要, 僅出現在生成密鑰對的過程中 。
3. 求E
E 要滿足兩個條件:
1)1 < E < L
2)gcd(E,L) = 1
gcd 代表 「最大公約數(greatest common divisor)」 。gcd(E,L) = 1 就代表 「E 和 L 的最大公約數為1,也就是說, E 和 L 互質 」。
L 在第二步已經計算出來,而為了找到滿足條件的 E, 第二次用到 「偽隨機數生成器(PRNG)」 ,在 1 和 L 之間生成 E 的候選,判斷其是否滿足 「gcd(E,L) = 1」 的條件。
經過前三步,已經能夠得到密鑰對種的 「公鑰:{E, N}」 了。
4. 求D
D 要滿足兩個條件:
1)1 < D < L
2)E × D mod L = 1
只要 D 滿足上面的兩個條件,使用 {E, N} 進行加密的報文,就能夠使用 {D, N} 進行解密。
至此,N、L、E、D 都已經計算出來,再整理一下
模擬實踐的過程包括兩部分,第一部分是生成密鑰對,第二部分是對數據進行加解密。為了方便計算,都使用了較小的數字。
第一部分:生成密鑰對
1. 求N
准備兩個質數,p = 5,q = 7,N = 5 × 7 = 35
2. 求L
L = lcm(p-1, q-1) = lcm (4, 6) = 12
3. 求E
gcd(E, L) = 1,即 E 和 L 互質,而且 1 < E < L,滿足條件的 E 有多個備選:5、7、11,選擇最小的 5 即可。於是,公鑰 = {E, N} = {5, 35}
4. 求D
E × D mod L = 1,即 5 × D mod 12 = 1,滿足條件的 D 也有多個備選:5、17、41,選擇 17 作為 D(如果選擇 5 恰好公私鑰一致了,這樣不太直觀),於是,私鑰 = {D, N} = {17, 35}
至此,我們得到了公私鑰對:
第二部分:模擬加解密
明文我們也使用一個比較小的數字 -- 4,利用 RSA 的加密公式:
密文 = 明文 ^ E mod N = 4 ^ 5 mod 35 = 9
明文 = 密文 ^ D mod N = 9 ^ 17 mod 35 = 4
從這個模擬的小例子能夠看出,即使我們用了很小的數字,計算的中間結果也是超級大。如果再加上偽隨機數生成器生成一個數字,判斷其是否為質數等,這個過程想想腦仁兒就疼。還好,現代晶元技術,讓計算機有了足夠的運算速度。然而,相對於普通的邏輯運算,這類數學運算仍然是相當緩慢的。這也是一些非對稱密碼卡/套件中,很關鍵的性能規格就是密鑰對的生成速度
公鑰密碼體系中,用公鑰加密,用私鑰解密,公鑰公開,私鑰隱藏。因此:
加密公式為:密文 = 明文 ^ E mod N
破譯的過程就是對該公式進行逆運算。由於除了對明文進行冪次運算外, 還加上了「模運算」 ,因此在數學上, 該逆運算就不再是簡單的對數問題,而是求離散對數問題,目前已經在數學領域達成共識,尚未發現求離散對數的高效演算法 。
暴力破解的本質就是逐個嘗試。當前主流的 RSA 演算法中,使用的 p 和 q 都是 1024 位以上,這樣 N 的長度就是 2048 位以上。而 E 和 D 的長度和 N 差不多,因此要找出 D,就需要進行 2048 位以上的暴力破解。即使上文那個簡單的例子,算出( 蒙出 ) 「9 ^ D mod 35 = 4」 中的 D 也要好久吧。
因為 E 和 N 是已知的,而 D 和 E 在數學上又緊密相關(通過中間數 L),能否通過一種反向的演算法來求解 D 呢?
從這個地方能夠看出,p 和 q 是極為關鍵的,這兩個數字不泄密,幾乎無法通過公式反向計算出 D。也就是說, 對於 RSA 演算法,質數 p 和 q 絕不能被黑客獲取,否則等價於交出私鑰 。
既然不能靠搶,N = p × q,N是已知的,能不能通過 「質因數分解」 來推導 p 和 q 呢?或者說, 一旦找到一種高效的 「質因數分解」 演算法,就能夠破解 RSA 演算法了 。
幸運的是,這和上述的「離散對數求解」一樣,當下在數學上還沒有找到這種演算法,當然,也無法證明「質因數分解」是否真的是一個困難問題 。因此只能靠硬算,只是當前的算力無法在可現實的時間內完成。 這也是很多人都提到過的,「量子時代來臨,當前的加密體系就會崩潰」,從算力的角度看,或許如此吧 。
既不能搶,也不能算,能不能猜呢?也就是通過 「推測 p 和 q 進行破解」 。
p 和 q 是通過 PRNG(偽隨機數生成器)生成的,於是,又一個關鍵因素,就是採用的 偽隨機數生成器演算法要足夠隨機 。
隨機數對於密碼學極為重要,後面會專門寫一篇筆記 。
前三種攻擊方式,都是基於 「硬碰硬」 的思路,而 「中間人攻擊」 則換了一種迂迴的思路,不去嘗試破解密碼演算法,而是欺騙通信雙方,從而獲取明文。具體來說,就是: 主動攻擊者 Mallory 混入發送者和接收者之間,面對發送者偽裝成接收者,面對接收者偽裝成發送者。
這個過程可以重復多次。需要注意的是,中間人攻擊方式不僅能夠針對 RSA,還可以針對任何公鑰密碼。能夠看到,整個過程中,公鑰密碼並沒有被破譯,密碼體系也在正常運轉,但機密性卻出現了問題,即 Alice 和 Bob 之間失去了機密性,卻在 Alice 和 Mallory 以及 Mallory 和 Bob 之間保持了機密性。即使公鑰密碼強度再強大 N 倍也無濟於事。也就是說,僅僅依靠密碼演算法本身,無法防禦中間人攻擊 。
而能夠抵禦中間人攻擊的,就需要用到密碼工具箱的另一種武器 -- 認證 。在下面一篇筆記中,就將涉及這個話題。
好了,以上就是公鑰密碼的基本知識了。
公鑰密碼體系能夠完美的解決對稱密碼體系中 「密鑰配送」 這個關鍵問題,但是拋開 「中間人攻擊」 問題不談,公鑰密碼自己也有個嚴重的問題:
公鑰密碼處理速度遠遠低於對稱密碼。不僅體現在密鑰對的生成上,也體現在加解密運算處理上。
因此,在實際應用場景下,往往會將對稱密碼和公鑰密碼的優勢相結合,構建一個 「混合密碼體系」 。簡單來說: 首先用相對高效的對稱密碼對消息進行加密,保證消息的機密性;然後用公鑰密碼加密對稱密碼的密鑰,保證密鑰的機密性。
下面是混合密碼體系的加解密流程圖。整個體系分為左右兩個部分:左半部分加密會話密鑰的過程,右半部分是加密原始消息的過程。原始消息一般較長,使用對稱密碼演算法會比較高效;會話密鑰一般比較短(十幾個到幾十個位元組),即使公鑰密碼演算法運算效率較低,對會話密鑰的加解密處理也不會非常耗時。
著名的密碼軟體 PGP、SSL/TLS、視頻監控公共聯網安全建設規范(GB35114) 等應用,都運用了混合密碼系統。
好了,以上就是公鑰密碼演算法的全部內容了,拖更了很久,以後還要更加勤奮一些。
為了避免被傻啦吧唧的審核機器人處理,後面就不再附漂亮姑娘的照片(也是為了你們的健康),改成我的攝影作品,希望不要對收視率產生影響,雖然很多小伙兒就是沖著姑娘來的。
就從喀納斯之旅開始吧。
㈡ OpenSSL之隨機數用法
隨機數是一種無規律的數,但是真正做到完全無規律也較困難,所以一般將它稱之為偽隨機數。隨機數在密碼學用的很多,比如SSL握手中的客戶端hello和服務端hello消息中都有隨機數;SSL握手中的預主密鑰是隨機數;RSA密鑰生成也用到隨機數。如果隨機數有問題,會帶來很大的安全隱患。軟體生成隨機數一般預先設置隨機數種子,再生成隨機數。設置隨機數種子可以說是對生成隨機數過程的一種擾亂,讓產生的隨機數更加無規律可循。生成隨機數有多種方法,可以是某種演算法也可以根據某種或多種隨機事件來生成。比如,滑鼠的位置、系統的當前時間、本進程/線程相關信息以及機器雜訊等。安全性高的應用一般都採用硬體方式(隨機數發生器)來生成隨機數。
本文假設你已經安裝好了OpenSSL,並且持有一份1.1.1的源碼。
隨機數相關的頭文件為rand.h、源文件在crypto/rand目錄中。
這個結構定義了涉及隨機數生成的抽象方法集合。主要欄位含義:
seed —— 隨機數種子函數。
bytes —— 隨機數生成函數。
cleanup —— 狀態清除函數。
add —— 隨機數種子添加函數。
pseudorand —— 可重現的隨機數函數。
status —— 狀態查詢函數。
在1.1.1中,大多數的數據結構已經不再向使用者開放,從封裝的角度來看,這是更合理的。如果你在頭文件中找不到結構定義,不妨去源碼中搜一搜。
int RAND_set_rand_method(const RAND_METHOD *meth);
設置自定義的隨機數抽象方法。
成功返回1,失敗返回0。
const RAND_METHOD *RAND_get_rand_method(void);
獲取當前的隨機數抽象方法集合。
成功返回有效指針,失敗返回NULL。
在我們未調用RAND_set_rand_method()的情況下,該函數返回默認的抽象方法集合。
RAND_METHOD *RAND_OpenSSL(void);
這個函數返回OpenSSL內置的隨機數,通常為RAND_DRBG隨機數。
void RAND_seed(const void *buf, int num);
種子函數,為了讓openssl內部維護的隨機數據更加無序,可使用本函數。buf為用戶輸入的隨機數地址,num為其位元組數。Openssl將用戶提供的buf中的隨機內容與其內部隨機數據進行摘要計算,更新其內部隨機數據。
void RAND_add(const void *buf, int num, double randomness);
與seed類似,也是為了讓openssl內部隨機數據更加無序,其中entropy(信息熵)可以看作用戶本次加入的隨機數的個數。從內部實現來看,RAND_seed()相當於調用RAND_add(buf, num, num),此時傳遞的entropy(信息熵)和緩沖區長度是一樣的。至於num和randomness這兩個參數如何設置,建議randomness不要超過num的長度,最好是兩者相同,或者直接調用RAND_seed(),盡量避免RAND_add()的調用。
int RAND_bytes(unsigned char *buf, int num);
生成隨機數,openssl根據內部維護的隨機數狀態來生成結果。buf用於存放生成的隨機數。num為輸入參數,用來指明生成隨機數的位元組長度。
成功返回1,失敗返回0。
int RAND_status(void);
查看熵值是否達到預定值,如果達到則返回1,否則返回0。
在openssl實現的md_rand中該函數會調用RAND_poll函數來使熵值合格。如果本函數返回0,則說明此時用戶不應生成隨機數,需要調用seed和add函數來添加熵值。
從1.1.1版本的使用情況來看,不需要調用RAND_seed(),RAND_status()總是返回成功的,但是建議使用者從安全考慮,雖然不需要理會RAND_status(),請在調用RAND_bytes()之前,總是使用RAND_seed()先初使化隨機種子。
const char *RAND_file_name(char *file, size_t num);
指定file緩沖區和num長度,生成隨機的文件路徑,如果num設置太小不足以容納完整路徑,則返回NULL,建議file緩沖區通常指定256位元組。
int RAND_load_file(const char *file, long max_bytes);
將file指定的隨機數文件中的數據讀取bytes位元組(如果bytes大於1024,則讀取1024位元組),內部調用RAND_add進行計算,生成內部隨機數。
成功返回載入的位元組數(0表示文件為空),失敗返回-1。
int RAND_write_file(const char *file);
生成一個隨機數文件,返回生成的內容大小,通常為1024位元組。
這個例子演示了隨機數的相關API操作。
輸出:
before RAND_seed() RAND_status() ret:[1]
RAND_status() ret:[1]
RAND_bytes() ret:[1]
p:[0x7ffd028a9070 - /home/test/.rnd] sFile:[0x7ffd028a9070 - /home/test/.rnd]
byteswrite:[1024]
bytesread:[512]
㈢ 什麼是隨機數及隨機數種子,能不能詳細通俗介紹一下
隨機數在科學研究與工程實際中有著極其重要的應用!
簡單來說,隨機數就是一個數列,這個數列可能滿足一定的概率分布,也許其滿足的分布並不為我們所知。
不知道你是否知道一個經典的例子:「使用一根針和兩條線求圓周率」(如果不知到你可以搜一下)。這個實驗我們可以使用數學模擬(蒙特卡羅模擬)的方法來進行,這樣可以最大限度的節約實驗所消耗的時間(使用計算機),也在一定程度上剔除了人為因素的影響。但有一個前提必須考慮,就是模擬的隨機性要好。怎樣體現呢,這時就需要使用「好」的隨機數來替代我們的物理實驗。
據我所知,隨機數在科學預測上有著非常重要的應用!還有密碼學中,隨機數也是基礎之一。
數學方法產生隨機數應該稱之為「偽隨機數」,只有使用物理方法才能得到真正的隨機數!
為了得到數學上的偽隨機數,我們就要研究「為隨機數發生器」!
通常,0-1區間上的均勻隨機數是基礎的基礎,因此,大量的工作是圍繞它展開的!在此基礎之上,又可以得到符合正態分布,beta分布等的偽隨機數。
「種子」是什麼呢?
經典的偽隨機數發生器是這樣的:
X(n+1)=
a
*
X(n)
+
b
顯然通過上式我們能夠得到一個數列,前提是X(0)應該給出,依次我們就可以算出X(1),X(2)...;當然不同的X(0)就會得到不同的數列。
可以說:「X(0)」就是種子。
對於一個應用級的偽隨機數發生器,所有的「偽隨機數」,均勻的分布於一個「軌道」上,幾乎所有的數都可以做為種子。數字「0」,有時是一個特例,不能作為種子,當然它取決於你使用的隨機數發生器!
呵呵,樓上說的言簡意賅,但那個函數並不復雜,你可以搜一下「素數模偽隨機數發生器」
X(n+1)=
a
*
X(n),
只不過這個a的確定不是太簡單,要求隨機性好(期望0.5,標准差1/12);周期長!
當然還有更好的發生器,周期可達2^6xxxx
-
1(具體的忘了)!
㈣ 什麼是隨機數及隨機數種子,能不能詳細通俗介紹一下
隨機數就是就隨機數種子中取出的數。種子就是個序號,這個序號交給一個數列管理器,通過這個序號,你從管理器中取出一個數列,這個數列就是你通過那個序號得到的隨機數。
但這個隨技術並不真正隨機。因為它是通過某個演算法的得到。也就是說你給數列管理器同一個序號將得到同樣一個「隨機」數列。
也就是說種子和隨機數列是一一對應的。{An}=f(x), x 就是種子,F()是演算法,{An}是數列,這個數列看上去是隨機的,這是因為An的通項很復雜。
例如:
從1、2、3、4、5、6、7、8、9、0這十個數中隨機取出一個數,取出的數是6的話,那麼6就叫隨機數。十個數字就叫隨機數種子。
如果是從1到50之間取數字,取出的數字叫隨機數,這1到50那50個數字就叫隨機數種子。
(4)隨機數密碼學擴展閱讀:
根據密碼學原理,隨機數的隨機性檢驗可以分為三個標准:
統計學偽隨機性。統計學偽隨機性指的是在給定的隨機比特流樣本中,1的數量大致等於0的數量,同理,「10」「01」「00」「11」四者數量大致相等。類似的標准被稱為統計學隨機性。滿足這類要求的數字在人類「一眼看上去」是隨機的。
密碼學安全偽隨機性。其定義為,給定隨機樣本的一部分和隨機演算法,不能有效的演算出隨機樣本的剩餘部分。
真隨機性。其定義為隨機樣本不可重現。實際上只要給定邊界條件,真隨機數並不存在,可是如果產生一個真隨機數樣本的邊界條件十分復雜且難以捕捉(比如計算機當地的本底輻射波動值),可以認為用這個方法演算出來了真隨機數。
相應的,隨機數也分為三類:
偽隨機數:滿足第一個條件的隨機數。
密碼學安全的偽隨機數:同時滿足前兩個條件的隨機數。可以通過密碼學安全偽隨機數生成器計算得出。
真隨機數:同時滿足三個條件的隨機數。
㈤ 一到五隨機數是什麼
一到五隨機數是1和4。
產生隨機數有多種不同的方法。隨機數最重要的特性是:它所產生的後面的那個數與前面的那個數毫無關系。一到五隨機數是1和4。
用法:
隨機數在密碼學中非常重要,保密通信中大量運用的會話密鑰的生成即需要真隨機數的參與。如果一個隨機數生成演算法是有缺陷的,那麼會話密鑰可以直接被推算出來。若果真發生這種事故,那麼任何加密演算法都失去了意義。
密碼學中大量利用偽隨機數生成器的應用還有流密碼。流密碼的著名例子是RC4。流密碼的原理是利用一個密碼學安全的偽隨機數生成器根據密鑰產生一串密碼學安全的偽隨機比特列,再將消息與上述隨機比特列按位異或運算。
㈥ 密碼那些事
之前在工作中經常用密鑰,但是不知道其中的原因,現在閑下來就來看下,再看的過程發現這個隨機數概念很模糊,於是就查了下,現總結如下:
0x01 隨機數
概述
隨機數在計算機應用中使用的比較廣泛,最為熟知的便是在密碼學中的應用。本文主要是講解隨機數使用導致的一些Web安全風。
我們先簡單了解一下隨機數
分類
隨機數分為真隨機數和偽隨機數,我們程序使用的基本都是偽隨機數,其中偽隨機又分為強偽隨機數和弱偽隨機數。
真隨機數,通過物理實驗得出,比如擲錢幣、骰子、轉輪、使用電子元件的噪音、核裂變等
偽隨機數,通過一定演算法和種子得出。軟體實現的是偽隨機數
強偽隨機數,難以預測的隨機數
弱偽隨機數,易於預測的隨機數
特性
隨機數有3個特性,具體如下:
隨機性:不存在統計學偏差,是完全雜亂的數列
不可預測性:不能從過去的數列推測出下一個出現的數
不可重現性:除非將數列本身保存下來,否則不能重現相同的數列
隨機數的特性和隨機數的分類有一定的關系,比如,弱偽隨機數只需要滿足隨機性即可,而強位隨機數需要滿足隨機性和不可預測性,真隨機數則需要同時滿足3個特性。
引發安全問題的關鍵點在於不可預測性。
偽隨機數的生成
我們平常軟體和應用實現的都是偽隨機數,所以本文的重點也就是偽隨機數。
偽隨機數的生成實現一般是演算法+種子。
具體的偽隨機數生成器PRNG一般有:
線性同餘法
單向散列函數法
密碼法
ANSI X9.17
比較常用的一般是線性同餘法,比如我們熟知的C語言的rand庫和java的java.util.Random類,都採用了線性同餘法生成隨機數。
應用場景
隨機數的應用場景比較廣泛,以下是隨機數常見的應用場景:
驗證碼生成
抽獎活動
UUID生成
SessionID生成
Token生成
CSRF Token
找回密碼Token
游 戲 (隨機元素的生成)
洗牌
俄羅斯方塊出現特定形狀的序列
游戲爆裝備
密碼應用場景
生成密鑰:對稱密碼,消息認證
生成密鑰對:公鑰密碼,數字簽名
生成IV: 用於分組密碼的CBC,CFB和OFB模式
生成nonce: 用於防禦重放攻擊; 分組密碼的CTR模式
生成鹽:用於基於口令的密碼PBE等
0x02 隨機數的安全性
相比其他密碼技術,隨機數很少受到關注,但隨機數在密碼技術和計算機應用中是非常重要的,不正確的使用隨機數會導致一系列的安全問題。
隨機數的安全風險
隨機數導致的安全問題一般有兩種
應該使用隨機數,開發者並沒有使用隨機數;
應該使用強偽隨機數,開發者使用了弱偽隨機數。
第一種情況,簡單來講,就是我們需要一個隨機數,但是開發者沒有使用隨機數,而是指定了一個常量。當然,很多人會義憤填膺的說,sb才會不用隨機數。但是,請不要忽略我朝還是有很多的。主要有兩個場景:
開發者缺乏基礎常識不知道要用隨機數;
一些應用場景和框架,介面文檔不完善或者開發者沒有仔細閱讀等原因。
比如找回密碼的token,需要一個偽隨機數,很多業務直接根據用戶名生成token;
比如OAuth2.0中需要第三方傳遞一個state參數作為CSRF Token防止CSRF攻擊,很多開發者根本不使用這個參數,或者是傳入一個固定的值。由於認證方無法對這個值進行業務層面有效性的校驗,導致了 OAuth 的CSRF攻擊。
第二種情況,主要區別就在於偽隨機數的強弱了,大部分(所有?)語言的API文檔中的基礎庫(常用庫)中的random庫都是弱偽隨機,很多開發自然就直接使用。但是,最重要也最致命的是,弱偽隨機數是不能用於密碼技術的。
還是第一種情況中的找回密碼場景,關於token的生成, 很多開發使用了時間戳作為隨機數(md5(時間戳),md5(時間戳+用戶名)),但是由於時間戳是可以預測的,很容易就被猜解。不可預測性是區分弱偽隨機數和強偽隨機數的關鍵指標。
當然,除了以上兩種情況,還有一些比較特別的情況,通常情況下比較少見,但是也不排除:
種子的泄露,演算法很多時候是公開的,如果種子泄露了,相當於隨機數已經泄露了;
隨機數池不足。這個嚴格來說也屬於弱偽隨機數,因為隨機數池不足其實也導致了隨機數是可預測的,攻擊者可以直接暴力破解。
漏洞實例
wooyun上有很多漏洞,還蠻有意思的,都是和隨機數有關的。
1.應該使用隨機數而未使用隨機數
Oauth2.0的這個問題特別經典,除了wooyun實例列出來的,其實很多廠商都有這個問題。
Oauth2.0中state參數要求第三方應用的開發者傳入一個CSRF Token(隨機數),如果沒有傳入或者傳入的不是隨機數,會導致CSRF登陸任意帳號:
唯品會賬號相關漏洞可通過csrf登錄任意賬號
人人網 - 網路 OAuth 2.0 redirect_uir CSRF 漏洞
2.使用弱偽隨機數
1) 密碼取回
很多密碼找回的場景,會發 送給 用戶郵件一個url,中間包含一個token,這個token如果猜測,那麼就可以找回其他用戶的密碼。
1. Shopex 4.8.5密碼取回處新生成密碼可預測漏洞
直接使用了時間函數microtime()作為隨機數,然後獲取MD5的前6位。
1. substr(md5(print_r(microtime(),true)),0,6);
PHP 中microtime()的值除了當前 伺服器 的秒數外,還有微秒數,微妙數的變化范圍在0.000000 -- 0.999999 之間,一般來說,伺服器的時間可以通過HTTP返回頭的DATE欄位來獲取,因此我們只需要遍歷這1000000可能值即可。但我們要使用暴力破解的方式發起1000000次請求的話,網路請求數也會非常之大。可是shopex非常貼心的在生成密碼前再次將microtime() 輸出了一次:
1. $messenger = &$this->system->loadModel('system/messenger');echo microtime()."
";
2.奇虎360任意用戶密碼修改
直接是MD5( unix 時間戳)
3.塗鴉王國弱隨機數導致任意用戶劫持漏洞,附測試POC
關於找回密碼隨機數的問題強烈建議大家參考拓哥的11年的文章《利用系統時間可預測破解java隨機數| 空虛浪子心的靈魂》
2) 其他隨機數驗證場景
CmsEasy最新版暴力注入(加解密缺陷/繞過防注入)
弱偽隨機數被繞過
Espcms v5.6 暴力注入
Espcms中一處SQL注入漏洞的利用,利用時發現espcms對傳值有加密並且隨機key,但是這是一個隨機數池固定的弱偽隨機數,可以被攻擊者遍歷繞過
Destoon B2B 2014-05-21最新版繞過全局防禦暴力注入(官方Demo可重現)
使用了microtime()作為隨機數,可以被預測暴力破解
Android 4.4之前版本的Java加密架構(JCA)中使用的Apache Harmony 6.0M3及其之前版本的SecureRandom實現存在安全漏洞,具體位於classlib/moles/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
類的engineNextBytes函數里,當用戶沒有提供用於產生隨機數的種子時,程序不能正確調整偏移量,導致PRNG生成隨機序列的過程可被預測。
Android SecureRandom漏洞詳解
安全建議
上面講的隨機數基礎和漏洞實例更偏重是給攻擊者一些思路,這里更多的是一些防禦和預防的建議。
業務場景需要使用隨機數,一定要使用隨機數,比如Token的生成;
隨機數要足夠長,避免暴力破解;
保證不同用處的隨機數使用不同的種子
對安全性要求高的隨機數(如密碼技術相關)禁止使用的弱偽隨機數:
不要使用時間函數作為隨機數(很多程序員喜歡用時間戳) Java:system.currenttimemillis() php:microtime()
不要使用弱偽隨機數生成器 Java: java.util.Random PHP: rand() 范圍很小,32767 PHP: mt_rand() 存在缺陷
強偽隨機數CSPRNG(安全可靠的偽隨機數生成器(Cryptographically Secure Pseudo-Random Number Generator)的各種參考
6.強偽隨機數生成(不建議開發自己實現)
產生高強度的隨機數,有兩個重要的因素:種子和演算法。演算法是可以有很多的,通常如何選擇種子是非常關鍵的因素。 如Random,它的種子是System.currentTimeMillis(),所以它的隨機數都是可預測的, 是弱偽隨機數。
強偽隨機數的生成思路:收集計算機的各種,鍵盤輸入時間,內存使用狀態,硬碟空閑空間,IO延時,進程數量,線程數量等信息,CPU時鍾,來得到一個近似隨機的種子,主要是達到不可預測性。
暫時先寫到這里
㈦ 你好,隨機數有規律嗎畢竟程序也是人製造出來的!
隨機數分兩種:偽隨機數和密碼學隨機數。偽隨機數(rand)是有一定規律的,這主要和操作系統以及庫函數有關,有人利用這種規律實現過攻擊。密碼學隨機數的規律就很難找了,不過要使用密碼學隨機數往往需要特殊的硬體。
㈧ 我想知道各種產生隨機數的演算法循環周期一次是多長。謝謝大家。
盡管是偽隨機數,但也是沒有規律的,唯一的規律是n=無窮的情況下,近似服從正態分布。
電腦所產生的隨機數規律與程序編程演算法有關,可以根據演算法讓隨機數有規律,也可以是無規律,如何找規律都要取決於演算法和隨機數范圍數據,一個比較大較難的隨機數是無任何規律的。
稱為是隨機數,所以也不存在循環問題,而是在一定數據范圍內數字隨機出現,而不是按排序出現。按排序出現的不能稱為隨機數。
選取足夠大的正整數M和任意自然數n0,a,b,由遞推公式:
ni+1=(af(ni)+b)mod M i=0,1,…,M-1
生成的數值序列稱為是同餘序列。當函數f(n)為線性函數時,即得到線性同餘序列:
ni+1=(a*ni+b)mod M i=0,1,…,M-1
以下是線性同餘法生成偽隨機數的偽代碼:
Random(n,m,seed,a,b)
{
r0 = seed;
for (i = 1;i<=n;i++)
ri = (a*ri-1 + b) mod m
}
其中種子參數seed可以任意選擇,常常將它設為計算機當前的日期或者時間;m是一個較大數,可以把它取為2w,w是計算機的字長;a可以是0.01w和0.99w之間的任何整數。
應用遞推公式產生均勻分布隨機數時,式中參數n0,a,b,M的選取十分重要。
(8)隨機數密碼學擴展閱讀:
隨機數在密碼學中非常重要,保密通信中大量運用的會話密鑰的生成即需要真隨機數的參與。如果一個隨機數生成演算法是有缺陷的,那麼會話密鑰可以直接被推算出來。若果真發生這種事故,那麼任何加密演算法都失去了意義。
密碼學中大量利用偽隨機數生成器的應用還有流密碼。流密碼的著名例子是RC4。流密碼的原理是利用一個密碼學安全的偽隨機數生成器根據密鑰產生一串密碼學安全的偽隨機比特列,再將消息與上述隨機比特列按位異或運算。
㈨ 計算機程序可以產生真正的隨機數嗎不是random偽隨機
光靠程序是無法實現真隨機數的。要實現真正的隨機數,必須有真正隨機的種子。
在計算機中並沒有一個真正的隨機數發生器,但是可以做到使產生的數字重復率很低,這樣看起來好象是真正的隨機數,實現這一功能的程序叫偽隨機數發生器。
有關如何產生隨機數的理論有許多,如果要詳細地討論,需要厚厚的一本書的篇幅。不管用什麼方法實現隨機數發生器,都必須給它提供一個名為「種子」的初始值。而且這個值最好是隨機的,或者至少這個值是偽隨機的。「種子」的值通常是用快速計數寄存器或移位寄存器來生成的。
(9)隨機數密碼學擴展閱讀:
隨機數在密碼學中非常重要,保密通信中大量運用的會話密鑰的生成即需要真隨機數的參與。如果一個隨機數生成演算法是有缺陷的,那麼會話密鑰可以直接被推算出來。若果真發生這種事故,那麼任何加密演算法都失去了意義。
密碼學中大量利用偽隨機數生成器的應用還有流密碼。流密碼的著名例子是RC4。流密碼的原理是利用一個密碼學安全的偽隨機數生成器根據密鑰產生一串密碼學安全的偽隨機比特列,再將消息與上述隨機比特列按位異或運算。