1 加密技術概述
一個密碼系統的安全性只在于密鑰的保密性,而不在算法的保密性。
對純數據的加密的確是這樣。對于你不愿意讓他看到這些數據(數據的明文)的人,用可靠的加密算法,只要破解者不知道被加密數據的密碼,他就不可解讀這些數據。
但是,軟件的加密不同于數據的加密,它只能是“隱藏”。不管你愿意不愿意讓他(合法用戶,或 Cracker)看見這些數據(軟件的明文),軟件最終總要在機器上運行,對機器,它就必須是明文。既然機器可以“看見”這些明文,那么 Cracker,通過一些技術,也可以看到這些明文。
于是,從理論上,任何軟件加密技術都可以破解。只是破解的難度不同而已。有的要讓最高明的 Cracker 忙上幾個月,有的可能不費吹灰之力,就被破解了。
所以,反盜版的任務(技術上的反盜版,而非行政上的反盜版)就是增加 Cracker 的破解難度。讓他們花費在破解軟件上的成本,比他破解這個軟件的獲利還要高。這樣 Cracker 的破解變得毫無意義——誰會花比正版軟件更多的錢去買盜版軟件 ?
2 密碼學簡介
2.1 概念
(1) 發送者和接收者 假設發送者想發送消息給接收者,且想安全地發送信息:她想確信偷聽者不能閱讀發送的消息。
(2) 消息和加密
消息被稱為明文。用某種方法偽裝消息以隱藏它的內容的過程稱為加密,加了密的消息稱為密文,而把密文轉變為明文的過程稱為解密。 明文用M(消息)或P(明文)表示,它可能是比特流(文本文件、位圖、數字化的語音流或數字化的視頻圖像)。至于涉及到計算機,P是簡單的二進制數據。明文可被傳送或存儲,無論在哪種情況,M指待加密的消息。
密文用C表示,它也是二進制數據,有時和M一樣大,有時稍大(通過壓縮和加密的結合,C有可能比P小些。然而,單單加密通常達不到這一點)。加密函數E作用于M得到密文C,用數學表示為:
E(M)=C.
相反地,解密函數D作用于C產生M
D(C)=M.
先加密后再解密消息,原始的明文將恢復出來,下面的等式必須成立:
D(E(M))=M
(3) 鑒別、完整性和抗抵賴
除了提供機密性外,密碼學通常有其它的作用:.
(a) 鑒別 消息的接收者應該能夠確認消息的來源;入侵者不可能偽裝成他人。
(b) 完整性檢驗 消息的接收者應該能夠驗證在傳送過程中消息沒有被修改;入侵者不可能用假消息代替合法消息。
(c) 抗抵賴 發送者事后不可能虛假地否認他發送的消息。
(4) 算法和密鑰
密碼算法也叫密碼,是用于加密和解密的數學函數。(通常情況下,有兩個相關的函數:一個用作加密,另一個用作解密)
如果算法的保密性是基于保持算法的秘密,這種算法稱為受限制的算法。受限制的算法具有歷史意義,但按現在的標準,它們的保密性已遠遠不夠。大的或經常變換的用戶組織不能使用它們,因為每有一個用戶離開這個組織,其它的用戶就必須改換另外不同的算法。如果有人無意暴露了這個秘密,所有人都必須改變他們的算法
。 更糟的是,受限制的密碼算法不可能進行質量控制或標準化。每個用戶組織必須有他們自己的唯一算法。這樣的組織不可能采用流行的硬件或軟件產品。但竊聽者卻可以買到這些流行產品并學習算法,于是用戶不得不自己編寫算法并予以實現,如果這個組織中沒有好的密碼學家,那么他們就無法知道他們是否擁有安全的算法。
盡管有這些主要缺陷,受限制的算法對低密級的應用來說還是很流行的,用戶或者沒有認識到或者不在乎他們系統中內在的問題。
現代密碼學用密鑰解決了這個問題,密鑰用K表示。K可以是很多數值里的任意值。密鑰K的可能值的范圍叫做密鑰空間。加密和解密運算都使用這個密鑰(即運算都依賴于密鑰,并用K作為下標表示),這樣,加/解密函數現在變成:
EK(M)=C
DK(C)=M.
這些函數具有下面的特性:
DK(EK(M))=M.
有些算法使用不同的加密密鑰和解密密鑰,也就是說加密密鑰K1與相應的解密密鑰K2不同,在這種情況下:
EK1(M)=C
DK2(C)=M
DK2 (EK1(M))=M
所有這些算法的安全性都基于密鑰的安全性;而不是基于算法的細節的安全性。這就意味著算法可以公開,也可以被分析,可以大量生產使用算法的產品,即使偷聽者知道你的算法也沒有關系;如果他不知道你使用的具體密鑰,他就不可能閱讀你的消息。
密碼系統由算法、以及所有可能的明文、密文和密鑰組成的。
基于密鑰的算法通常有兩類:對稱算法和公開密鑰算法。下面將分別介紹:
2.2 對稱密碼算法
對稱算法有時又叫傳統密碼算法,就是加密密鑰能夠從解密密鑰中推算出來,反過來也成立。在大多數對稱算法中,加/解密密鑰是相同的。這些算法也叫秘密密鑰算法或單密鑰算法,它要求發送者和接收者在安全通信之前,商定一個密鑰。對稱算法的安全性依賴于密鑰,泄漏密鑰就意味著任何人都能對消息進行加/解密。只要通信需要保密,密鑰就必須保密。
對稱算法的加密和解密表示為:
EK(M)=C
DK(C)=M
對稱算法可分為兩類。一次只對明文中的單個比特(有時對字節)運算的算法稱為序列算法或序列密碼。另一類算法是對明文的一組比特亞行運算,這些比特組稱為分組,相應的算法稱為分組算法或分組密碼。現代計算機密碼算法的典型分組長度為64比特——這個長度大到足以防止分析破譯,但又小到足以方便使用(在計算機出現前,算法普遍地每次只對明文的一個字符運算,可認為是序列密碼對字符序列的運算)。
2.3 公開密碼算法
公開密鑰算法(也叫非對稱算法)是這樣設計的:用作加密的密鑰不同于用作解密的密鑰,而且解密密鑰不能根據加密密鑰計算出來(至少在合理假定的長時間內)。之所以叫做公開密鑰算法,是因為加密密鑰能夠公開,即陌生者能用加密密鑰加密信息,但只有用相應的解密密鑰才能解密信息。在這些系統中,加密密鑰叫做公開密鑰(簡稱公鑰),解密密鑰叫做私人密鑰(簡稱私鑰)。私人密鑰有時也叫秘密密鑰。為了避免與對稱算法混淆,此處不用秘密密鑰這個名字。
用公開密鑰K加密表示為
EK(M)=C.
雖然公開密鑰和私人密鑰是不同的,但用相應的私人密鑰解密可表示為:
DK(C)=M
有時消息用私人密鑰加密而用公開密鑰解密,這用于數字簽名(后面將詳細介紹),盡管可能產生混淆,但這些運算可分別表示為:
EK(M)=C
DK(C)=M
當前的公開密碼算法的速度,比起對稱密碼算法,要慢的多,這使得公開密碼算法在大數據量的加密中應用有限。
2.4 單向散列函數
單向散列函數 H(M) 作用于一個任意長度的消息 M,它返回一個固定長度的散列值 h,其中 h 的長度為 m 。
輸入為任意長度且輸出為固定長度的函數有很多種,但單向散列函數還有使其單向的其它特性: (1) 給定 M ,很容易計算 h ;
(2) 給定 h ,根據 H(M) = h 計算 M 很難 ;
(3) 給定 M ,要找到另一個消息 M‘ 并滿足 H(M) = H(M’) 很難。
在許多應用中,僅有單向性是不夠的,還需要稱之為“抗碰撞”的條件:
要找出兩個隨機的消息 M 和 M‘,使 H(M) = H(M’) 滿足很難。
由于散列函數的這些特性,由于公開密碼算法的計算速度往往很慢,所以,在一些密碼協議中,它可以作為一個消息 M 的摘要,代替原始消息 M,讓發送者為 H(M) 簽名而不是對 M 簽名 。
如 SHA 散列算法用于數字簽名協議 DSA中。
2.5 數字簽名
提到數字簽名就離不開公開密碼系統和散列技術。
有幾種公鑰算法能用作數字簽名。在一些算法中,例如RSA,公鑰或者私鑰都可用作加密。用你的私鑰加密文件,你就擁有安全的數字簽名。在其它情況下,如DSA,算法便區分開來了??數字簽名算法不能用于加密。這種思想首先由Diffie和Hellman提出 。
基本協議是簡單的 :
(1) A 用她的私鑰對文件加密,從而對文件簽名。
(2) A 將簽名的文件傳給B。
(3) B用A的公鑰解密文件,從而驗證簽名。
這個協議中,只需要證明A的公鑰的確是她的。如果B不能完成第(3)步,那么他知道簽名是無效的。
這個協議也滿足以下特征:
(1) 簽名是可信的。當B用A的公鑰驗證信息時,他知道是由A簽名的。
(2) 簽名是不可偽造的。只有A知道她的私鑰。
(3) 簽名是不可重用的。簽名是文件的函數,并且不可能轉換成另外的文件。
(4) 被簽名的文件是不可改變的。如果文件有任何改變,文件就不可能用A的公鑰驗證。 (5) 簽名是不可抵賴的。B不用A的幫助就能驗證A的簽名。
在實際應用中,因為公共密碼算法的速度太慢,簽名者往往是對消息的散列簽名而不是對消息本身簽名。這樣做并不會降低簽名的可信性。
注:本文由計算機專業相關教材整理
----------------------------------------------------------------------------------------------------------------------------------
哈希(Hash)與加密(Encrypt)的基本原理、區別及工程應用
本文轉自 http://www.cnblogs.com/leoo2sk/archive/2010/10/01/hash-and-encrypt.html
0、摘要
今天看到吉日嘎拉的一篇關于管理軟件中信息加密和安全的文章,感覺非常有實際意義。文中作者從實踐經驗出發,討論了信息管理軟件中如何通過哈希和加密進行數據保護。但是從文章評論中也可以看出很多朋友對這個方面一些基本概念比較模糊,這樣就容易“照葫蘆畫瓢”,不能根據自身具體情況靈活選擇和使用各種哈希和加密方式。本文不對哈希和加密做過于深入的討論,而是對哈希和加密的基本概念和原理進行闡述、比較,并結合具體實踐說明如何選擇哈希和加密算法、如何提高安全性等問題,使朋友們做到“知其然,知其所以然”,這樣就能通過分析具體情況,靈活運用哈希和加密保護數據。
1、哈希(Hash)與加密(Encrypt)的區別
在本文開始,我需要首先從直觀層面闡述哈希(Hash)和加密(Encrypt)的區別,因為我見過很多朋友對這兩個概念不是很清晰,容易混淆兩者。而正確區別兩者是正確選擇和使用哈希與加密的基礎。
概括來說,哈希(Hash)是將目標文本轉換成具有相同長度的、不可逆的雜湊字符串(或叫做消息摘要),而加密(Encrypt)是將目標文本轉換成具有不同長度的、可逆的密文。
具體來說,兩者有如下重要區別:
1、哈希算法往往被設計成生成具有相同長度的文本,而加密算法生成的文本長度與明文本身的長度有關。
例如,設我們有兩段文本:“Microsoft”和“Google”。兩者使用某種哈希算法得到的結果分別為:“140864078AECA1C7C35B4BEB33C53C34”和“8B36E9207C24C76E6719268E49201D94”,而使用某種加密算法的到的結果分別為“Njdsptpgu”和“Hpphmf”。可以看到,哈希的結果具有相同的長度,而加密的結果則長度不同。實際上,如果使用相同的哈希算法,不論你的輸入有多么長,得到的結果長度是一個常數,而加密算法往往與明文的長度成正比。
2、哈希算法是不可逆的,而加密算法是可逆的。
這里的不可逆有兩層含義,一是“給定一個哈希結果R,沒有方法將E轉換成原目標文本S”,二是“給定哈希結果R,即使知道一段文本S的哈希結果為R,也不能斷言當初的目標文本就是S”。其實稍微想想就知道,哈希是不可能可逆的,因為如果可逆,那么哈希就是世界上最強悍的壓縮方式了——能將任意大小的文件壓縮成固定大小。
加密則不同,給定加密后的密文R,存在一種方法可以將R確定的轉換為加密前的明文S。
這里先從直觀層面簡單介紹兩者的區別,等下文從數學角度對兩者做嚴謹描述后,讀者朋友就知道為什么會有這兩個區別了。
2、哈希(Hash)與加密(Encrypt)的數學基礎
從數學角度講,哈希和加密都是一個映射。下面正式定義兩者:
一個哈希算法是一個多對一映射,給定目標文本S,H可以將其唯一映射為R,并且對于所有S,R具有相同的長度。由于是多對一映射,所以H不存在逆映射
使得R轉換為唯一的S。
一個加密算法是一個一一映射,其中第二個參數叫做加密密鑰,E可以將給定的明文S結合加密密鑰Ke唯一映射為密文R,并且存在另一個一一映射
,可以結合Kd將密文R唯一映射為對應明文S,其中Kd叫做解密密鑰。
下圖是哈希和加密過程的圖示:
有了以上定義,就很清楚為什么會存在上文提到的兩個區別了。由于哈希算法的定義域是一個無限集合,而值域是一個有限集合,將無限集合映射到有限集合,根據“鴿籠原理(Pigeonhole principle)”,每個哈希結果都存在無數個可能的目標文本,因此哈希不是一一映射,是不可逆的。
而加密算法是一一映射,因此理論上來說是可逆的。
但是,符合上面兩個定義的映射僅僅可以被叫做哈希算法和加密算法,但未必是好的哈希和加密,好的哈希和加密往往需要一些附加條件,下面介紹這些內容。
一個設計良好的哈希算法應該很難從哈希結果找到哈希目標文本的碰撞(Collision)。那么什么是碰撞呢?對于一個哈希算法H,如果,則S1和S2互為碰撞。關于為什么好的哈希需要難以尋找碰撞,在下面講應用的時候會詳解。另外,好的哈希算法應該對于輸入的改變極其敏感,即使輸入有很小的改動,如一億個字符變了一個字符,那么結果應該截然不同。這就是為什么哈希可以用來檢測軟件的完整性。
一個設計良好的加密算法應該是一個“單向陷門函數(Trapdoor one-way function)”,單向陷門函數的特點是一般情況下即使知道函數本身也很難將函數的值轉換回函數的自變量,具體到加密也就是說很難從密文得到明文,雖然從理論上這是可行的,而“陷門”是一個特殊的元素,一旦知道了陷門,則這種逆轉換則非常容易進行,具體到加密算法,陷門就是密鑰。
順便提一句,在加密中,應該保密的僅僅是明文和密鑰。也就是說我們通常假設攻擊者對加密算法和密文了如指掌,因此加密的安全性應該僅僅依賴于密鑰而不是依賴于假設攻擊者不知道加密算法。
3、哈希(Hash)與加密(Encrypt)在軟件開發中的應用
哈希與加密在現代工程領域應用非常廣泛,在計算機領域也發揮了很大作用,這里我們僅僅討論在平常的軟件開發中最常見的應用——數據保護。
所謂數據保護,是指在數據庫被非法訪問的情況下,保護敏感數據不被非法訪問者直接獲取。這是非常有現實意義的,試想一個公司的安保系統數據庫服務器被入侵,入侵者獲得了所有數據庫數據的查看權限,如果管理員的口令(Password)被明文保存在數據庫中,則入侵者可以進入安保系統,將整個公司的安保設施關閉,或者刪除安保系統中所有的信息,這是非常嚴重的后果。但是,如果口令經過良好的哈希或加密,使得入侵者無法獲得口令明文,那么最多的損失只是被入侵者看到了數據庫中的數據,而入侵者無法使用管理員身份進入安保系統作惡。
3.1、哈希(Hash)與加密(Encrypt)的選擇
要實現上述的數據保護,可以選擇使用哈希或加密兩種方式。那么在什么時候該選擇哈希、什么時候該選擇加密呢?
基本原則是:如果被保護數據僅僅用作比較驗證,在以后不需要還原成明文形式,則使用哈希;如果被保護數據在以后需要被還原成明文,則需要使用加密。
例如,你正在做一個系統,你打算當用戶忘記自己的登錄口令時,重置此用戶口令為一個隨機口令,而后將此隨機口令發給用戶,讓用戶下次使用此口令登錄,則適合使用哈希。實際上很多網站都是這么做的,想想你以前登錄過的很多網站,是不是當你忘記口令的時候,網站并不是將你忘記的口令發送給你,而是發送給你一個新的、隨機的口令,然后讓你用這個新口令登錄。這是因為你在注冊時輸入的口令被哈希后存儲在數據庫里,而哈希算法不可逆,所以即使是網站管理員也不可能通過哈希結果復原你的口令,而只能重置口令。
相反,如果你做的系統要求在用戶忘記口令的時候必須將原口令發送給用戶,而不是重置其口令,則必須選擇加密而不是哈希。
3.2、使用簡單的一次哈希(Hash)方法進行數據保護
首先我們討論使用一次哈希進行數據保護的方法,其原理如下圖所示:
對上圖我想已無需多言,很多朋友應該使用過類似的哈希方法進行數據保護。當前最常用的哈希算法是MD5和SHA1,下面給出在.NET平臺上用C#語言實現MD5和SHA1哈希的代碼,由于.NET對于這兩個哈希算法已經進行很很好的封裝,因此我們不必自己實現其算法細節,直接調用相應的庫函數即可(實際上MD5和SHA1算法都十分復雜,有興趣的可以參考維基百科)。
using System;
using System.Web.Security;
namespace HashAndEncrypt
{
///
<summary>
///
哈希(Hash)工具類
///
</summary>
public sealed class HashHelper
{
///
<summary>
///
使用MD5算法進行哈希
///
</summary>
///
<param name="source">源字串</param>
///
<returns>雜湊字串</returns>
public static string MD5Hash(string source)
{
return FormsAuthentication.HashPasswordForStoringInConfigFile(source,"MD5");
}
///
<summary>
///
使用SHA1算法進行哈希
///
</summary>
///
<param name="source">源字串</param>
///
<returns>雜湊字串</returns>
public static string SHA1Hash(string source)
{
return FormsAuthentication.HashPasswordForStoringInConfigFile(source,"SHA1");
}
}
}
3.3、對簡單哈希(Hash)的攻擊
下面我們討論上述的數據保護方法是否安全。
對于哈希的攻擊,主要有尋找碰撞法和窮舉法。
先來說說尋找碰撞法。從哈希本身的定義和上面的數據保護原理圖可以看出,如果想非法登錄系統,不一定非要得到注冊時的輸入口令,只要能得到一個注冊口令的碰撞即可。因此,如果能從雜湊串中分析出一個口令的碰撞,則大功告成。
不過我的意見是,對這種攻擊大可不必擔心,因為目前對于MD5和SHA1并不存在有效地尋找碰撞方法。雖然我國杰出的數學家王小云教授曾經在國際密碼學會議上發布了對于MD5和SHA1的碰撞尋找改進算法,但這種方法和很多人口中所說的“破解”相去甚遠,其理論目前僅具有數學上的意義,她將破解MD5的預期步驟數從2^80降到了2^69,雖然從數學上降低了好幾個數量級,但2^69對于實際應用來說仍然是一個天文數字,就好比以前需要一億年,現在需要一萬年一樣。
不過這并不意味著使用MD5或SHA1后就萬事大吉了,因為還有一種對于哈希的攻擊方法——窮舉法。通俗來說,就是在一個范圍內,如從000000到999999,將其中所有值一個一個用相同的哈希算法哈希,然后將結果和雜湊串比較,如果相同,則這個值就一定是源字串或源字串的一個碰撞,于是就可以用這個值非法登錄了。
例如,下文是對MD5的窮舉攻擊的代碼(設攻擊范圍為000000到999999):
using System;
using System.Web.Security;
namespace HashAndEncrypt
{
///
<summary>
///
MD5攻擊工具類
///
</summary>
public sealed class MD5AttackHelper
{
///
<summary>
///
對MD5進行窮舉攻擊
///
</summary>
///
<param name="hashString">雜湊串</param>
///
<returns>雜湊串的源串或源串碰撞(攻擊失敗則返回null)</returns>
public static string AttackMD5(string hashString)
{
for (int i
= 0; i <= 999999; i++)
{
string testString
= i.ToString();
while (testString.Length
< 6)
testString
= "0" +
testString;
if (FormsAuthentication.HashPasswordForStoringInConfigFile(testString,"MD5")
== hashString)
return testString;
}
return null;
}
}
}
這種看似笨拙的方法,在現實中爆發的能量卻是驚人的,目前幾乎所有的MD5破解機或MD5在線破解都是用這種窮舉法,但就是這種“笨”方法,卻成功破解出很多哈希串。糾其緣由,就是相當一部分口令是非常簡單的,如“123456”或“000000”這種口令還有很多人在用,可以看出,窮舉法是否能成功很大程度上取決于口令的復雜性。因為窮舉法掃描的區間往往是單字符集、規則的區間,或者由字典數據進行組合,因此,如果使用復雜的口令,例如“ASDF#$%uiop.8930”這種變態級口令,窮舉法就很難奏效了。
3.4、對一次哈希(Hash)的改進——多重混合哈希(Hash)
上面說過,如果口令過于簡單,則使用窮舉法可以很有效地破解出一次哈希后的雜湊串。如果不想這樣,只有讓用戶使用復雜口令,但是,很多時候我們并不能強迫用戶,因此,我們需要想一種辦法,即使用戶使用諸如“000000”這種簡單密碼,也令窮舉法難奏效。其中一種辦法就是使用多重哈希,所謂多重哈希就是使用不同的哈希函數配合自定義的Key對口令進行多次哈希,如果Key很復雜,那么窮舉法將變得異常艱難。
例如,如果使用下面的混合公式進行哈希:
如果將Key設為一個極為復雜的字符串,那么在攻擊者不知道Key的情況下,幾乎無法通過窮舉法破解。因為即使S很簡單,但是Key的MD5值幾乎是無法在合理時間內窮舉完的。下面是這種多重混合哈希的代碼實現:
using System;
using System.Web.Security;
namespace HashAndEncrypt
{
///
<summary>
///
多重混合哈希工具類
///
</summary>
public sealed class HashHelper
{
private static readonly String
hashKey = "qwer#&^Buaa06";
///
<summary>
///
對敏感數據進行多重混合哈希
///
</summary>
///
<param name="source">待處理明文</param>
///
<returns>Hasn后的數據</returns>
public static String
Hash(String source)
{
String
hashCode = FormsAuthentication.HashPasswordForStoringInConfigFile(source, "MD5")
+
FormsAuthentication.HashPasswordForStoringInConfigFile(hashKey,"MD5");
return FormsAuthentication.HashPasswordForStoringInConfigFile(hashCode,"SHA1");
}
}
}
3.5、使用加密(Encrypt)方法進行數據保護
加密方法如果用于口令保護的話,與上述哈希方法的流程基本一致,只是在需要時,可以使用解密方法得到明文。關于加密本身是一個非常龐大的系統,而對于加密算法的攻擊更是可以寫好幾本書了,所以這里從略。下面只給出使用C#進行DES加密和解密的代碼。
using System;
using System.Security.Cryptography;
using System.Text;
using System.Web.Security;
namespace HashAndEncrypt
{
///
<summary>
///
工具類,封裝了加解密相關操作
///
</summary>
public sealed class EncryptHelper
{
private static readonly Byte[]
DesKey = {5, 7, 8, 9, 0, 2, 1, 6};
private static readonly Byte[]
DesVi = { 6, 9, 8, 5, 1, 6, 2, 8 };
///
<summary>
///
使用DES算法加密數據
///
</summary>
///
<param name="data">待加密數據</param>
///
<returns>密文</returns>
public static String
Encrypt(String data)
{
DESCryptoServiceProvider
des = new DESCryptoServiceProvider();
Encoding
utf = new UTF8Encoding();
ICryptoTransform
encryptor = des.CreateEncryptor(DesKey, DesVi);
byte[]
bData = utf.GetBytes(data);
byte[]
bEnc = encryptor.TransformFinalBlock(bData, 0, bData.Length);
return Convert.ToBase64String(bEnc);
}
///
<summary>
///
使用DES算法解密數據
///
</summary>
///
<param name="data">待解密數據</param>
///
<returns>明文</returns>
public static String
Decrypt(String data)
{
DESCryptoServiceProvider
des = new DESCryptoServiceProvider();
Encoding
utf = new UTF8Encoding();
ICryptoTransform
decryptor = des.CreateDecryptor(DesKey, DesVi);
byte[]
bEnc = Convert.FromBase64String(data);
byte[]
bDec = decryptor.TransformFinalBlock(bEnc, 0, bEnc.Length);
return utf.GetString(bDec);
}
}
}
4、總結
密碼學本身是一個非常深奧的數學分支,對于普通開發者,不需要了解過于深入的密碼學知識。本文僅僅講述哈希與加密的基礎內容,并對兩者做了比較,幫助讀者明晰概念,另外,對一些實際應用情況進行了簡單的討論。
原文地址:http://www.cnblogs.com/fenglie/articles/3323530.html
文章列表