A. HashMap為什麼不安全
我們都知道HashMap是線程不安全的,在多線程環境中不建議使用,但是其線程不安全主要體現在什麼地方呢,本文將對該問題進行解密。
1.jdk1.7中的HashMap
在jdk1.8中對HashMap做了很多優化,這里先分析在jdk1.7中的問題,相信大家都知道在jdk1.7多線程環境下HashMap容易出現死循環,這里我們先用代碼來模擬出現死循環的情況:
publicclassHashMapTest{publicstaticvoidmain(String[]args){HashMapThreadthread0=newHashMapThread();HashMapThreadthread1=newHashMapThread();HashMapThreadthread2=newHashMapThread();HashMapThreadthread3=newHashMapThread();HashMapThreadthread4=newHashMapThread();thread0.start();thread1.start();thread2.start();thread3.start();thread4.start();}}{privatestaticAtomicIntegerai=newAtomicInteger();privatestaticMapmap=newHashMap<>();@Overridepublicvoidrun(){while(ai.get()<1000000){map.put(ai.get(),ai.get());ai.incrementAndGet();}}}
上述代碼比較簡單,就是開多個線程不斷進行put操作,並且HashMap與AtomicInteger都是全局共享的。
在多運行幾次該代碼後,出現如下死循環情形:
2.jdk1.8中HashMap
在jdk1.8中對HashMap進行了優化,在發生hash碰撞,不再採用頭插法方式,而是直接插入鏈表尾部,因此不會出現環形鏈表的情況,但是在多線程的情況下仍然不安全,這里我們看jdk1.8中HashMap的put操作源碼:
這是jdk1.8中HashMap中put操作的主函數, 注意第6行代碼,如果沒有hash碰撞則會直接插入元素。
如果線程A和線程B同時進行put操作,剛好這兩條不同的數據hash值一樣,並且該位置數據為null,所以這線程A、B都會進入第6行代碼中。
假設一種情況,線程A進入後還未進行數據插入時掛起,而線程B正常執行,從而正常插入數據,然後線程A獲取CPU時間片,此時線程A不用再進行hash判斷了,問題出現:線程A會把線程B插入的數據給覆蓋,發生線程不安全。
總結
首先HashMap是線程不安全的,其主要體現:
在jdk1.7中,在多線程環境下,擴容時會造成環形鏈或數據丟失。
在jdk1.8中,在多線程環境下,會發生數據覆蓋的情況。
B. 哈希演算法 怎麼解
13112345670,13501230345,2006/10/15 07:49:04 這3段數據作為3元組來建立hash表。 演算法倒是很多,千行,萬行的數據量比較小,所以我一般是用3元累加,作為源,然後對預留行求余。 舉個簡單的例子。 a=13112345670,b=13501230345,char c[30]="2006/10/15 07:49:04 "; 則可以這樣映射: int cc=0; for(i=0;i <strlen(c);i++) cc+=i*c[i]; res=(a*1+b*2+cc)%20000; //假設你的hash表是2萬行 這樣res就是你的3元組hash映射的行數。 當然,沖突肯定有的,所以,你映射到res行時,先檢查該行標志位是否被佔用,未被佔用就是用該行,被佔用了就要防沖突,對你的res進行 res2=chongtu(res); //chongtu函數是你沖突時候的備用演算法 循環檢查res2,直到res2可用。 這樣,表就建好了。 查找的時候也是一樣的演算法,挨個檢查res,res沒有該數據,則循環檢查res2,直到映射到未被佔用的數據,說明全查完,也沒有找到你的數據,說明不存在。
C. 在公開密鑰密碼體制中,HASH演算法的作用是
Hash,一般翻譯做"散列",也有直接音譯為"哈希"的,就是把任意長度的輸入(又叫做預映射, pre-image),通過散列演算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出,而不可能從散列值來唯一的確定輸入值。
數學表述為:h = H(M) ,其中H( )--單向散列函數,M--任意長度明文,h--固定長度散列值。
在信息安全領域中應用的Hash演算法,還需要滿足其他關鍵特性:
第一當然是單向性(one-way),從預映射,能夠簡單迅速的得到散列值,而在計算上不可能構造一個預映射,使其散列結果等於某個特定的散列值,即構造相應的M=H-1(h)不可行。這樣,散列值就能在統計上唯一的表徵輸入值,因此,密碼學上的 Hash 又被稱為"消息摘要(message digest)",就是要求能方便的將"消息"進行"摘要",但在"摘要"中無法得到比"摘要"本身更多的關於"消息"的信息。
第二是抗沖突性(collision-resistant),即在統計上無法產生2個散列值相同的預映射。給定M,計算上無法找到M',滿足H(M)=H(M') ,此謂弱抗沖突性;計算上也難以尋找一對任意的M和M',使滿足H(M)=H(M') ,此謂強抗沖突性。要求"強抗沖突性"主要是為了防範所謂"生日攻擊(birthday attack)",在一個10人的團體中,你能找到和你生日相同的人的概率是2.4%,而在同一團體中,有2人生日相同的概率是11.7%。類似的,當預映射的空間很大的情況下,演算法必須有足夠的強度來保證不能輕易找到"相同生日"的人。
第三是映射分布均勻性和差分分布均勻性,散列結果中,為 0 的 bit 和為 1 的 bit ,其總數應該大致相等;輸入中一個 bit 的變化,散列結果中將有一半以上的 bit 改變,這又叫做"雪崩效應(avalanche effect)";要實現使散列結果中出現 1bit 的變化,則輸入中至少有一半以上的 bit 必須發生變化。其實質是必須使輸入中每一個 bit 的信息,盡量均勻的反映到輸出的每一個 bit 上去;輸出中的每一個 bit,都是輸入中盡可能多 bit 的信息一起作用的結果。
Damgard 和 Merkle 定義了所謂"壓縮函數(compression function)",就是將一個固定長度輸入,變換成較短的固定長度的輸出,這對密碼學實踐上 Hash 函數的設計產生了很大的影響。Hash函數就是被設計為基於通過特定壓縮函數的不斷重復"壓縮"輸入的分組和前一次壓縮處理的結果的過程,直到整個消息都被壓縮完畢,最後的輸出作為整個消息的散列值。盡管還缺乏嚴格的證明,但絕大多數業界的研究者都同意,如果壓縮函數是安全的,那麼以上述形式散列任意長度的消息也將是安全的。這就是所謂 Damgard/Merkle 結構:
在下圖中,任意長度的消息被分拆成符合壓縮函數輸入要求的分組,最後一個分組可能需要在末尾添上特定的填充位元組,這些分組將被順序處理,除了第一個消息分組將與散列初始化值一起作為壓縮函數的輸入外,當前分組將和前一個分組的壓縮函數輸出一起被作為這一次壓縮的輸入,而其輸出又將被作為下一個分組壓縮函數輸入的一部分,直到最後一個壓縮函數的輸出,將被作為整個消息散列的結果。
MD5 和 SHA1 可以說是目前應用最廣泛的Hash演算法,而它們都是以 MD4 為基礎設計的。
1) MD4
MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年設計的,MD 是 Message Digest 的縮寫。它適用在32位字長的處理器上用高速軟體實現--它是基於 32 位操作數的位操作來實現的。它的安全性不像RSA那樣基於數學假設,盡管 Den Boer、Bosselaers 和 Dobbertin 很快就用分析和差分成功的攻擊了它3輪變換中的 2 輪,證明了它並不像期望的那樣安全,但它的整個演算法並沒有真正被破解過,Rivest 也很快進行了改進。
下面是一些MD4散列結果的例子:
MD4 ("") =
MD4 ("a") =
MD4 ("abc") =
MD4 ("message digest") =
MD4 ("abcdefghijklmnopqrstuvwxyz") =
MD4 ("") =
MD4 ("1234567890") =
2) MD5
MD5(RFC 1321)是 Rivest 於1991年對MD4的改進版本。它對輸入仍以512位分組,其輸出是4個32位字的級聯,與 MD4 相同。它較MD4所做的改進是:
1) 加入了第四輪
2) 每一步都有唯一的加法常數;
3) 第二輪中的G函數從((X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ Z)) 變為 ((X ∧ Z) ∨ (Y ∧ ~Z))以減小其對稱性;
4) 每一步都加入了前一步的結果,以加快"雪崩效應";
5) 改變了第2輪和第3輪中訪問輸入子分組的順序,減小了形式的相似程度;
6) 近似優化了每輪的循環左移位移量,以期加快"雪崩效應",各輪的循環左移都不同。
盡管MD5比MD4來得復雜,並且速度較之要慢一點,但更安全,在抗分析和抗差分方面表現更好。
消息首先被拆成若干個512位的分組,其中最後512位一個分組是"消息尾+填充位元組(100...0)+64 位消息長度",以確保對於不同長度的消息,該分組不相同。64位消息長度的限制導致了MD5安全的輸入長度必須小於264bit,因為大於64位的長度信息將被忽略。而4個32位寄存器字初始化為A=0x01234567,B=0x89abcdef,C=0xfedcba98,D=0x76543210,它們將始終參與運算並形成最終的散列結果。
接著各個512位消息分組以16個32位字的形式進入演算法的主循環,512位消息分組的個數據決定了循環的次數。主循環有4輪,每輪分別用到了非線性函數
F(X, Y, Z) = (X ∧ Y) ∨ (~X ∧ Z)
G(X, Y, Z) = (X ∧ Z) ∨ (Y ∧ ~Z)
H(X, Y, Z) =X ⊕ Y ⊕ Z
I(X, Y, Z) = X ⊕ (Y ∨ ~Z)
這4輪變換是對進入主循環的512位消息分組的16個32位字分別進行如下操作:將A、B、C、D的副本a、b、c、d中的3個經F、G、H、I運算後的結果與第4個相加,再加上32位字和一個32位字的加法常數,並將所得之值循環左移若干位,最後將所得結果加上a、b、c、d之一,並回送至ABCD,由此完成一次循環。
所用的加法常數由這樣一張表T[i]來定義,其中i為1...64,T[i]是i的正弦絕對值之4294967296次方的整數部分,這樣做是為了通過正弦函數和冪函數來進一步消除變換中的線性性。
當所有512位分組都運算完畢後,ABCD的級聯將被輸出為MD5散列的結果。下面是一些MD5散列結果的例子:
MD5 ("") =
MD5 ("a") =
MD5 ("abc") =
MD5 ("message digest") =
MD5 ("abcdefghijklmnopqrstuvwxyz") =
MD5 ("") =
MD5 ("1234567890") =
參考相應RFC文檔可以得到MD4、MD5演算法的詳細描述和演算法的C源代碼。
3) SHA1 及其他
SHA1是由NIST NSA設計為同DSA一起使用的,訪問http://www.itl.nist.gov/fipspubs可以得到它的詳細規范--[/url]"FIPS PUB 180-1 SECURE HASH STANDARD"。它對長度小於264的輸入,產生長度為160bit的散列值,因此抗窮舉(brute-force)性更好。SHA-1 設計時基於和MD4相同原理,並且模仿了該演算法。因為它將產生160bit的散列值,因此它有5個參與運算的32位寄存器字,消息分組和填充方式與MD5相同,主循環也同樣是4輪,但每輪進行20次操作,非線性運算、移位和加法運算也與MD5類似,但非線性函數、加法常數和循環左移操作的設計有一些區別,可以參考上面提到的規范來了解這些細節。下面是一些SHA1散列結果的例子:
SHA1 ("abc") = a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
SHA1 ("") = 84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1
其他一些知名的Hash演算法還有MD2、N-Hash、RIPE-MD、HAVAL等等。上面提到的這些都屬於"純"Hash演算法。還有另2類Hash演算法,一類就是基於對稱分組演算法的單向散列演算法,典型的例子是基於DES的所謂Davies-Meyer演算法,另外還有經IDEA改進的Davies-Meyer演算法,它們兩者目前都被認為是安全的演算法。另一類是基於模運算/離散對數的,也就是基於公開密鑰演算法的,但因為其運算開銷太大,而缺乏很好的應用前景。
沒有通過分析和差分攻擊考驗的演算法,大多都已經夭折在實驗室里了,因此,如果目前流行的Hash演算法能完全符合密碼學意義上的單向性和抗沖突性,就保證了只有窮舉,才是破壞Hash運算安全特性的唯一方法。為了對抗弱抗沖突性,我們可能要窮舉個數和散列值空間長度一樣大的輸入,即嘗試2^128或2^160個不同的輸入,目前一台高檔個人電腦可能需要10^25年才能完成這一艱巨的工作,即使是最高端的並行系統,這也不是在幾千年裡的幹得完的事。而因為"生日攻擊"有效的降低了需要窮舉的空間,將其降低為大約1.2*2^64或1.2*2^80,所以,強抗沖突性是決定Hash演算法安全性的關鍵。
在NIST新的 Advanced Encryption Standard (AES)中,使用了長度為128、192、256bit 的密鑰,因此相應的設計了 SHA256、SHA384、SHA512,它們將提供更好的安全性。
Hash演算法在信息安全方面的應用主要體現在以下的3個方面:
1) 文件校驗
我們比較熟悉的校驗演算法有奇偶校驗和CRC校驗,這2種校驗並沒有抗數據篡改的能力,它們一定程度上能檢測並糾正數據傳輸中的信道誤碼,但卻不能防止對數據的惡意破壞。
MD5 Hash演算法的"數字指紋"特性,使它成為目前應用最廣泛的一種文件完整性校驗和(Checksum)演算法,不少Unix系統有提供計算md5 checksum的命令。它常被用在下面的2種情況下:
第一是文件傳送後的校驗,將得到的目標文件計算 md5 checksum,與源文件的md5 checksum 比對,由兩者 md5 checksum 的一致性,可以從統計上保證2個文件的每一個碼元也是完全相同的。這可以檢驗文件傳輸過程中是否出現錯誤,更重要的是可以保證文件在傳輸過程中未被惡意篡改。一個很典型的應用是ftp服務,用戶可以用來保證多次斷點續傳,特別是從鏡像站點下載的文件的正確性。
更出色的解決方法是所謂的代碼簽名,文件的提供者在提供文件的同時,提供對文件Hash值用自己的代碼簽名密鑰進行數字簽名的值,及自己的代碼簽名證書。文件的接受者不僅能驗證文件的完整性,還可以依據自己對證書簽發者和證書擁有者的信任程度,決定是否接受該文件。瀏覽器在下載運行插件和java小程序時,使用的就是這樣的模式。
第二是用作保存二進制文件系統的數字指紋,以便檢測文件系統是否未經允許的被修改。不少系統管理/系統安全軟體都提供這一文件系統完整性評估的功能,在系統初始安裝完畢後,建立對文件系統的基礎校驗和資料庫,因為散列校驗和的長度很小,它們可以方便的被存放在容量很小的存儲介質上。此後,可以定期或根據需要,再次計算文件系統的校驗和,一旦發現與原來保存的值有不匹配,說明該文件已經被非法修改,或者是被病毒感染,或者被木馬程序替代。TripWire就提供了一個此類應用的典型例子。
更完美的方法是使用"MAC"。"MAC" 是一個與Hash密切相關的名詞,即信息鑒權碼(Message Authority Code)。它是與密鑰相關的Hash值,必須擁有該密鑰才能檢驗該Hash值。文件系統的數字指紋也許會被保存在不可信任的介質上,只對擁有該密鑰者提供可鑒別性。並且在文件的數字指紋有可能需要被修改的情況下,只有密鑰的擁有者可以計算出新的散列值,而企圖破壞文件完整性者卻不能得逞。
2) 數字簽名
Hash 演算法也是現代密碼體系中的一個重要組成部分。由於非對稱演算法的運算速度較慢,所以在數字簽名協議中,單向散列函數扮演了一個重要的角色。
在這種簽名協議中,雙方必須事先協商好雙方都支持的Hash函數和簽名演算法。
簽名方先對該數據文件進行計算其散列值,然後再對很短的散列值結果--如Md5是16個位元組,SHA1是20位元組,用非對稱演算法進行數字簽名操作。對方在驗證簽名時,也是先對該數據文件進行計算其散列值,然後再用非對稱演算法驗證數字簽名。
對 Hash 值,又稱"數字摘要"進行數字簽名,在統計上可以認為與對文件本身進行數字簽名是等效的。而且這樣的協議還有其他的優點:
首先,數據文件本身可以同它的散列值分開保存,簽名驗證也可以脫離數據文件本身的存在而進行。
再者,有些情況下簽名密鑰可能與解密密鑰是同一個,也就是說,如果對一個數據文件簽名,與對其進行非對稱的解密操作是相同的操作,這是相當危險的,惡意的破壞者可能將一個試圖騙你將其解密的文件,充當一個要求你簽名的文件發送給你。因此,在對任何數據文件進行數字簽名時,只有對其Hash值進行簽名才是安全的。
3) 鑒權協議
如下的鑒權協議又被稱作"挑戰--認證模式:在傳輸信道是可被偵聽,但不可被篡改的情況下,這是一種簡單而安全的方法。
需要鑒權的一方,向將被鑒權的一方發送隨機串("挑戰"),被鑒權方將該隨機串和自己的鑒權口令字一起進行 Hash 運算後,返還鑒權方,鑒權方將收到的Hash值與在己端用該隨機串和對方的鑒權口令字進行 Hash 運算的結果相比較("認證"),如相同,則可在統計上認為對方擁有該口令字,即通過鑒權。
POP3協議中就有這一應用的典型例子:
S: +OK POP3 server ready <[email protected]>
C: APOP mrose
S: +OK maildrop has 1 message (369 octets)
在上面的一段POP3協議會話中,雙方都共享的對稱密鑰(鑒權口令字)是tanstaaf,伺服器發出的挑戰是<[email protected]>,客戶端對挑戰的應答是MD5("<[email protected]>tanstaaf") = ,這個正確的應答使其通過了認證。
散列演算法長期以來一直在計算機科學中大量應用,隨著現代密碼學的發展,單向散列函數已經成為信息安全領域中一個重要的結構模塊,我們有理由深入研究其設計理論和應用方法。
D. HASH加密使用復雜的數字演算法來實現有效的加密,其演算法包括
Java中使用Hash演算法:
import java.security.*;
public static String HashBase64(String str)
{
String ret="";
try {
//Hash演算法
MessageDigest sha = MessageDigest.getInstance("SHA-1");
sha.update(str.getBytes());
ret=new sun.misc.BASE64Encoder().encode(sha.digest());
}
catch (Exception e) {
System.out.print(e.getMessage());
}
return ret;
}
E. Hash演算法原理
哈希演算法將任意長度的二進制值映射為較短的固定長度的二進制值,這個小的二進制值稱為哈希值。
F. A*演算法應用,大家給點介紹,做課程設計
維基網路有很多的,大陸訪問不了,可以設置個香港代理。
SHA 家族
[編輯首段]維基網路,自由的網路全書
跳轉到: 導航, 搜尋
安全散列演演演算法能計算出一個數位訊息所對應到的,長度固定的字串(又稱訊息摘要)。且若輸入的訊息不同,它們對應到不同字串的機率很高;而 SHA 是FIPS所認證的五種安全雜湊演演演算法。這些演演演算法之所以稱作「安全」是基於以下兩點(根據官方標準的描述):「1)由訊息摘要反推原輸入訊息,從計算理論上來說是很困難的。2)想要找到兩組不同的訊息對應到相同的訊息摘要,從計算理論上來說也是很困難的。任何對輸入訊息的變動,都有很高的機率導致其產生的訊息摘要迥異。」
SHA 家族的五個演演演算法,分別是SHA-1, SHA-224, SHA-256, SHA-384, 和 SHA-512,由美國國家安全局 (NSA) 所設計,並由美國國家標准與技術研究院(NIST) 發布;是美國的政府標准。後四者有時並稱為SHA-2。SHA-1 在許多安全協定中廣為使用,包括 TLS 和 SSL、 PGP、SSH、S/MIME 和 IPsec,曾被視為是 MD5(更早之前被廣為使用的雜湊函數)的後繼者。但 SHA-1 的安全性如今被密碼學家嚴重質疑;雖然至今尚未出現對 SHA-2 有效的攻擊,它的演演演算法跟 SHA-1 基本上仍然相似;因此有些人開始發展其他替代的雜湊演演演算法。緣於最近對 SHA-1 的種種攻擊發表,「美國國家標准與技術研究院(NIST)開始設法經由公開競爭管道(類似高級加密標准AES的發展經過),發展一個或多個新的雜湊演演演算法。」
目錄 [隱藏]
1 SHA-0 和 SHA-1
1.1 SHA-0 的破解
1.2 SHA-1 的破解
2 SHA-2
3 SHA 所定義的長度
4 SHAd
5 應用
6 SHA-1 演演演算法
7 SHA-2 演演演算法
8 參見
9 參考資料
10 外部鏈結
[編輯] SHA-0 和 SHA-1
SHA-1 壓縮演演演算法中的一個迴圈。A, B, C, D 和 E 是這個state中的 32 位元文字;F 是會變化的非線性函數;<<<n 代表bit向左循環移動n個位置。n因操作而異。田代表molo 232之下的加法,Kt 是一個常數。最初載明的演演演算法於 1993年發布,稱做安全雜湊標准 (Secure Hash Standard),FIPS PUB 180。這個版本現在常被稱為 SHA-0。它在發布之後很快就被 NSA 撤回,並且由 1995年發布的修訂版本 FIPS PUB 180-1 (通常稱為 SHA-1) 取代。SHA-1 和 SHA-0 的演演演算法只在壓縮函數的訊息轉換部份差了一個位元的循環位移。根據 NSA 的說法,它修正了一個在原始演演演算法中會降低密碼安全性的錯誤。然而 NSA 並沒有提供任何進一步的解釋或證明該錯誤已被修正。而後 SHA-0 和 SHA-1 的弱點相繼被攻破,SHA-1 似乎是顯得比 SHA-0 有抵抗性,這多少證實了 NSA 當初修正演演演算法以增進安全性的聲明。
SHA-0 和 SHA-1 可將一個最大 264 位元的訊息,轉換成一串 160 位元的訊息摘要;其設計原理相似於 MIT 教授 Ronald L. Rivest 所設計的密碼學雜湊演演演算法 MD4 和 MD5。
[編輯] SHA-0 的破解
在 CRYPTO 98 上,兩位法國研究者提出一種對 SHA-0 的攻擊方式 (Chabaud and Joux, 1998): 在 261的計算復雜度之內,就可以發現一次碰撞(即兩個不同的訊息對應到相同的訊息摘要);這個數字小於 280 ,也就是說,其安全性不到一個理想的雜湊函數抵抗攻擊所應具備的計算復雜度。
2004年時,Biham 和 Chen 也發現了 SHA-0 的近似碰撞 — 兩個訊息可以雜湊出幾乎相同的數值;其中 162 位元中有 142 位元相同。他們也發現了 SHA-0 的完整碰撞(相對於近似碰撞),將本來需要 80 次方的復雜度降低到 62 次方。
2004年8月12日,Joux, Carribault, Lemuet 和 Jalby 宣布找到 SHA-0 演演演算法的完整碰撞的方法,這是歸納 Chabaud 和 Joux 的攻擊所完成的結果。發現一個完整碰撞只需要 251的計算復雜度。他們使用的是一台有 256 顆 Itanium2 處理器的超級電腦,約耗 80,000 CPU 工時 [1]。
2004年8月17日,在 CRYPTO 2004 的 Rump 會議上,王小雲, 馮登國 (Feng), 來學嘉 (Lai), 和於紅波 (Yu) 宣布了攻擊 MD5、SHA-0 和其他雜湊函數的初步結果。他們攻擊 SHA-0 的計算復雜度是 240,這意謂的他們的攻擊成果比 Joux 還有其他人所做的更好。請參見 MD5 安全性。2005 年二月,王小雲和殷益群、於紅波再度發表了對 SHA-0 破密的演演演算法,可在 239 的計算復雜度內就找到碰撞。
[編輯] SHA-1 的破解
鑒於 SHA-0 的破密成果,專家們建議那些計畫利用 SHA-1 實作密碼系統的人們也應重新考慮。2004 年 CRYPTO 會議結果公布之後,NIST 即宣布他們將逐漸減少使用 SHA-1,改以 SHA-2 取而代之。
2005年,Rijmen 和 Oswald 發表了對 SHA-1 較弱版本(53次的加密迴圈而非80次)的攻擊:在 280 的計算復雜度之內找到碰撞。
2005年二月,王小雲、殷益群及於紅波發表了對完整版 SHA-1 的攻擊,只需少於 269 的計算復雜度,就能找到一組碰撞。(利用暴力搜尋法找到碰撞需要 280 的計算復雜度。)
這篇論文的作者們寫道;「我們的破密分析是以對付 SHA-0 的差分攻擊、近似碰撞、多區塊碰撞技術、以及從 MD5 演演演算法中尋找碰撞的訊息更改技術為基礎。沒有這些強力的分析工具,SHA-1 就無法破解。」此外,作者還展示了一次對 58 次加密迴圈 SHA-1 的破密,在 233 個單位操作內就找到一組碰撞。完整攻擊方法的論文發表在 2005 年八月的 CRYPTO 會議中。
殷益群在一次面談中如此陳述:「大致上來說,我們找到了兩個弱點:其一是前置處理不夠復雜;其二是前 20 個迴圈中的某些數學運算會造成不可預期的安全性問題。」
2005 年八月 17 的 CRYPTO 會議尾聲中王小雲、姚期智、姚儲楓再度發表更有效率的 SHA-1 攻擊法,能在 263 個計算復雜度內找到碰撞。
在密碼學的學術理論中,任何攻擊方式,其計算復雜度若少於暴力搜尋法所需要的計算復雜度,就能被視為針對該密碼系統的一種破密法;這並不表示該破密法已經可以進入實際應用的階段。
就應用層面的考量而言,一種新的破密法出現,暗示著將來可能會出現更有效率、足以實用的改良版本。雖然這些實用的破密法版本根本還沒誕生,但確有必要發展更強的雜湊演演演算法來取代舊的演演演算法。在「碰撞」攻擊法之外,另有一種反譯攻擊法,就是由雜湊出的字串反推原本的訊息;反譯攻擊的嚴重性更在碰撞攻擊之上。 在許多會應用到密碼雜湊的情境(如用戶密碼的存放、文件的數位簽章等)中,碰撞攻擊的影響並不是很大。舉例來說,一個攻擊者可能不會只想要偽造一份一模一樣的文件,而會想改造原來的文件,再附上合法的簽章,來愚弄持有私密金鑰的驗證者。另一方面,如果可以從密文中反推未加密前的使用者密碼,攻擊者就能利用得到的密碼登入其他使用者的帳戶,而這種事在密碼系統中是不能被允許的。但若存在反譯攻擊,只要能得到指定使用者密碼雜湊過後的字串(通常存在影檔中,而且可能不會透露原密碼資訊),就有可能得到該使用者的密碼。
2006 年的 CRYPTO 會議上,Christian Rechberger 和 Christophe De Cannière 宣布他們能在容許攻擊者決定部分原訊息的條件之下,找到 SHA-1 的一個碰撞。
[編輯] SHA-2
SHA-2 的第t個加密迴圈。圖中的深藍色方塊是事先定義好的非線性函數。ABCDEFGH一開始分別是八個初始值,Kt是第t個金鑰,Wt是本區塊產生第t個word。原訊息被切成固定長度的區塊,對每一個區塊,產生n個word(n視演演演算法而定),透過重復運作迴圈n次對ABCDEFGH這八個工作區段循環加密。最後一次迴圈所產生的八段字串合起來即是此區塊對應到的雜湊字串。若原訊息包含數個區塊,則最後還要將這些區塊產生的雜湊字串加以混合才能產生最後的雜湊字串。NIST 發布了三個額外的 SHA 變體,這三個函數都將訊息對應到更長的訊息摘要。以它們的摘要長度 (以位元計算) 加在原名後面來命名:SHA-256,SHA-384 和 SHA-512。它們發布於 2001年的 FIPS PUB 180-2 草稿中,隨即通過審查和評論。包含 SHA-1 的 FIPS PUB 180-2,於 2002年以官方標准發布。2004年2月,發布了一次 FIPS PUB 180-2 的變更通知,加入了一個額外的變種 "SHA-224",這是為了符合雙金鑰 3DES 所需的金鑰長度而定義。
SHA-256 和 SHA-512 是很新的雜湊函數,前者以定義一個word為32位元,後者則定義一個word為64位元。它們分別使用了不同的偏移量,或用不同的常數,然而,實際上二者結構是相同的,只在迴圈執行的次數上有所差異。 SHA-224 以及 SHA-384 則是前述二種雜湊函數的截短版,利用不同的初始值做計算。
這些新的雜湊函數並沒有接受像 SHA-1 一樣的公眾密碼社群做詳細的檢驗,所以它們的密碼安全性還不被大家廣泛的信任。Gilbert 和 Handschuh (2003) 曾對這些新變種作過一些研究,聲稱他們沒有弱點。
[編輯] SHA 所定義的長度
下表中的中繼雜湊值(internal state)表示對每個資料區塊壓縮雜湊過後的中繼值(internal hash sum)。詳情請參見Merkle-Damgård construction。
演演演算法 輸出雜湊值長度 (bits) 中繼雜湊值長度 (bits) 資料區塊長度 (bits) 最大輸入訊息長度 (bits) 一個Word長度 (bits) 迴圈次數 使用到的運運算元 碰撞攻擊
SHA-0 160 160 512 264 − 1 32 80 +,and,or,xor,rotl 是
SHA-1 160 160 512 264 − 1 32 80 +,and,or,xor,rotl 存在263 的攻擊
SHA-256/224 256/224 256 512 264 − 1 32 64 +,and,or,xor,shr,rotr 尚未出現
SHA-512/384 512/384 512 1024 2128 − 1 64 80 +,and,or,xor,shr,rotr 尚未出現
[編輯] SHAd
SHAd 函數是一個簡單的相同 SHA 函數的重述:
SHAd-256(m)=SHA-256(SHA-256(m))。它會克服有關延伸長度攻擊的問題。
[編輯] 應用
SHA-1, SHA-224, SHA-256, SHA-384 和 SHA-512 都被需要安全雜湊演演演算法的美國聯邦政府所應用,他們也使用其他的密碼演演演算法和協定來保護敏感的未保密資料。FIPS PUB 180-1 也鼓勵私人或商業組織使用 SHA-1 加密。Fritz-chip 將很可能使用 SHA-1 雜湊函數來實現個人電腦上的數位版權管理。
首先推動安全雜湊演演演算法出版的是已合並的數位簽章標准。
SHA 雜湊函數已被做為 SHACAL 分組密碼演演演算法的基礎。
[編輯] SHA-1 演演演算法
以下是 SHA-1 演演演算法的虛擬碼:
Note: All variables are unsigned 32 bits and wrap molo 232 when calculating
Initialize variables:
h0 := 0x67452301
h1 := 0xEFCDAB89
h2 := 0x98BADCFE
h3 := 0x10325476
h4 := 0xC3D2E1F0
Pre-processing:
append the bit '1' to the message
append k bits '0', where k is the minimum number >= 0 such that the resulting message
length (in bits) is congruent to 448 (mod 512)
append length of message (before pre-processing), in bits, as 64-bit big-endian integer
Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
Extend the sixteen 32-bit words into eighty 32-bit words:
for i from 16 to 79
w[i] := (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
Initialize hash value for this chunk:
a := h0
b := h1
c := h2
d := h3
e := h4
Main loop:
for i from 0 to 79
if 0 ≤ i ≤ 19 then
f := (b and c) or ((not b) and d)
k := 0x5A827999
else if 20 ≤ i ≤ 39
f := b xor c xor d
k := 0x6ED9EBA1
else if 40 ≤ i ≤ 59
f := (b and c) or (b and d) or (c and d)
k := 0x8F1BBCDC
else if 60 ≤ i ≤ 79
f := b xor c xor d
k := 0xCA62C1D6
temp := (a leftrotate 5) + f + e + k + w[i]
e := d
d := c
c := b leftrotate 30
b := a
a := temp
Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
Proce the final hash value (big-endian):
digest = hash = h0 append h1 append h2 append h3 append h4
上述關於 f 運算式列於 FIPS PUB 180-1 中 , 以下替代運算式也許也能在主要迴圈裡計算 f :
(0 ≤ i ≤ 19): f := d xor (b and (c xor d)) (alternative)
(40 ≤ i ≤ 59): f := (b and c) or (d and (b or c)) (alternative 1)
(40 ≤ i ≤ 59): f := (b and c) or (d and (b xor c)) (alternative 2)
(40 ≤ i ≤ 59): f := (b and c) + (d and (b xor c)) (alternative 3)
[編輯] SHA-2 演演演算法
以下是SHA-256 演演演算法的虛擬碼。注意,64個word w[16..63]中的位元比起 SHA-1 演演演算法,混合的程度大幅提升。
Note: All variables are unsigned 32 bits and wrap molo 232 when calculating
Initialize variables
(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
Initialize table of round constants
(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
k[0..63] :=
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
Pre-processing:
append the bit '1' to the message
append k bits '0', where k is the minimum number >= 0 such that the resulting message
length (in bits) is congruent to 448 (mod 512)
append length of message (before pre-processing), in bits, as 64-bit big-endian integer
Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
break chunk into sixteen 32-bit big-endian words w[0..15]
Extend the sixteen 32-bit words into sixty-four 32-bit words:
for i from 16 to 63
s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
w[i] := w[i-16] + s0 + w[i-7] + s1
Initialize hash value for this chunk:
a := h0
b := h1
c := h2
d := h3
e := h4
f := h5
g := h6
h := h7
Main loop:
for i from 0 to 63
s0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
maj := (a and b) xor (a and c) xor (b and c)
t2 := s0 + maj
s1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
ch := (e and f) xor ((not e) and g)
t1 := h + s1 + ch + k[i] + w[i]
h := g
g := f
f := e
e := d + t1
d := c
c := b
b := a
a := t1 + t2
Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
h5 := h5 + f
h6 := h6 + g
h7 := h7 + h
Proce the final hash value (big-endian):
digest = hash = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
其中 ch 函數及 maj 函數可利用前述 SHA-1 的優化方式改寫。
SHA-224 和 SHA-256 基本上是相同的, 除了:
h0 到 h7 的初始值不同,以及
SHA-224 輸出時截掉 h7 的函數值。
SHA-512 和 SHA-256 的結構相同,但:
SHA-512 所有的數字都是64位元,
SHA-512 執行80次加密迴圈而非64次,
SHA-512 初始值和常數拉長成64位元,以及
二者位元的偏移量和循環位移量不同。
SHA-384 和 SHA-512 基本上是相同的,除了:
h0 到 h7 的初始值不同,以及
SHA-384 輸出時截掉 h6 和 h7 的函數值。