常見加密算法 :
DES(Data Encryption Standard):數據加密標準,速度較快,適用於加密大量數據的場合;
3DES(Triple DES):是基於DES,對一塊數據用三個不同的密鑰進行三次加密,強度更高;
RC2和 RC4:用變長密鑰對大量數據進行加密,比 DES 快;
IDEA(International Data Encryption Algorithm)國際數據加密算法:使用 128 位密鑰提供非常強的安全性;
RSA:由 RSA 公司發明,是一個支持變長密鑰的公共密鑰算法,需要加密的文件塊的長度也是可變的;
DSA(Digital Signature Algorithm):數字簽名算法,是一種標準的 DSS(數字簽名標準);
AES(Advanced Encryption Standard):高級加密標準,是下一代的加密算法標準,速度快,安全級別高,目前 AES 標準的一個實現是 Rijndael 算法;
BLOWFISH,它使用變長的密鑰,長度可達448位,運行速度很快;
其它算法,如ElGamal、Deffie-Hellman、新型橢圓曲線算法ECC等。 比如說,MD5,你在一些比較正式而嚴格的網站下的東西一般都會有MD5值給出,如安全焦點的軟件工具,每個都有MD5。嚴格來說MD5並不能算是一種加密算法,只能說是一種摘要算法(數據摘要算法是密碼學算法中非常重要的一個分支,它通過對所有數據提取指紋信息以實現數據簽名、數據完整性校驗等功能,由於其不可逆性,有時候會被用做敏感信息的加密。數據摘要算法也被稱爲哈希(Hash)算法、散列算法。)
MD5分類:
1、CRC8、CRC16、CRC32
CRC(Cyclic Redundancy Check,循環冗餘校驗)算法出現時間較長,應用也十分廣泛,尤其是通訊領域,現在應用最多的就是 CRC32 算法,它產生一個4字節(32位)的校驗值,一般是以8位十六進制數,如FA 12 CD 45等。CRC算法的優點在於簡便、速度快,嚴格的來說,CRC更應該被稱爲數據校驗算法,但其功能與數據摘要算法類似,因此也作爲測試的可選算法。
在 WinRAR、WinZIP 等軟件中,也是以 CRC32 作爲文件校驗算法的。一般常見的簡單文件校驗(Simple File Verify – SFV)也是以 CRC32算法爲基礎,它通過生成一個後綴名爲 .SFV 的文本文件,這樣可以任何時候可以將文件內容 CRC32運算的結果與 .SFV 文件中的值對比來確定此文件的完整性。
與 SFV 相關工具軟件有很多,如MagicSFV、MooSFV等。
2、MD2 、MD4、MD5
這是應用非常廣泛的一個算法家族,尤其是 MD5(Message-Digest Algorithm 5,消息摘要算法版本5),它由MD2、MD3、MD4發展而來,由Ron Rivest(RSA公司)在1992年提出,被廣泛應用於數據完整性校驗、數據(消息)摘要、數據加密等。MD2、MD4、MD5 都產生16字節(128位)的校驗值,一般用32位十六進制數表示。MD2的算法較慢但相對安全,MD4速度很快,但安全性下降,MD5比MD4更安全、速度更快。
在互聯網上進行大文件傳輸時,都要得用MD5算法產生一個與文件匹配的、存儲MD5值的文本文件(後綴名爲 .md5或.md5sum),這樣接收者在接收到文件後,就可以利用與 SFV 類似的方法來檢查文件完整性,絕大多數大型軟件公司或開源組織都是以這種方式來校驗數據完整性,而且部分操作系統也使用此算法來對用戶密碼進行加密,另外,它也是目前計算機犯罪中數據取證的最常用算法。
與MD5 相關的工具有很多,如 WinMD5等。
3、SHA1、SHA256、SHA384、SHA512
SHA(Secure Hash Algorithm)是由美國專門制定密碼算法的標準機構-- 美國國家標準技術研究院(NIST)制定的,SHA系列算法的摘要長度分別爲:SHA爲20字節(160位)、SHA256爲32字節(256位)、 SHA384爲48字節(384位)、SHA512爲64字節(512位),由於它產生的數據摘要的長度更長,因此更難以發生碰撞,因此也更爲安全,它是未來數據摘要算法的發展方向。由於SHA系列算法的數據摘要長度較長,因此其運算速度與MD5相比,也相對較慢。
SHA1的應用較爲廣泛,主要應用於CA和數字證書中,另外在互聯網中流行的BT軟件中,也是使用SHA1來進行文件校驗的。
4、RIPEMD、PANAMA、TIGER、ADLER32 等
RIPEMD是Hans Dobbertin等3人在對MD4,MD5缺陷分析基礎上,於1996年提出來的,有4個標準128、160、256和320,其對應輸出長度分別爲16字節、20字節、32字節和40字節。
TIGER由Ross在1995年提出。Tiger號稱是最快的Hash算法,專門爲64位機器做了優化。
常用的加密算法有對稱加密和非對稱加密兩大類型:
對稱加密
簡介:
對稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時又叫傳統密碼算法,就是加密密鑰能夠從解密密鑰中推算出來,同時解密密鑰也可以從加密密鑰中推算出來。而在大多數的對稱算法中,加密密鑰和解密密鑰是相同的,所以也稱這種加密算法爲祕密密鑰算法或單密鑰算法。它要求發送方和接收方在安全通信之前,商定一個密鑰。對稱算法的安全性依賴於密鑰,泄漏密鑰就意味着任何人都可以對他們發送或接收的消息解密,所以密鑰的保密性對通信性至關重要。
特點:
對稱加密算法的特點是算法公開、計算量小、加密速度快、加密效率高。
不足之處是,交易雙方都使用同樣鑰匙,安全性得不到保證。此外,每對用戶每次使用對稱加密算法時,都需要使用其他人不知道的惟一鑰匙,這會使得發收信雙方所擁有的鑰匙數量呈幾何級數增長,密鑰管理成爲用戶的負擔。對稱加密算法在分佈式網絡系統上使用較爲困難,主要是因爲密鑰管理困難,使用成本較高。而與公開密鑰加密算法比起來,對稱加密算法能夠提供加密和認證卻缺乏了簽名功能,使得使用範圍有所縮小。在計算機專網系統中廣泛使用的對稱加密算法有DES和IDEA等。美國國家標準局倡導的AES即將作爲新標準取代DES。
具體算法:DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法。
原理應用:對稱加密算法的優點在於加解密的高速度和使用長密鑰時的難破解性。假設兩個用戶需要使用對稱加密方法加密然後交換數據,則用戶最少需要2個密鑰並交換使用,如果企業內用戶有n個,則整個企業共需要n×(n-1) 個密鑰,密鑰的生成和分發將成爲企業信息部門的惡夢。對稱加密算法的安全性取決於加密密鑰的保存情況,但要求企業中每一個持有密鑰的人都保守祕密是不可能的,他們通常會有意無意的把密鑰泄漏出去--如果一個用戶使用的密鑰被入侵者所獲得,入侵者便可以讀取該用戶密鑰加密的所有文檔,如果整個企業共用一個加密密鑰,那整個企業文檔的保密性便無從談起。
對稱加密算法中最經典的算法莫過於DES加密算法。DES加密採用的是分組加密的方法,使用56位密鑰加密64位明文,最後產生64位密文。DES算法的基本流程如圖6-2所示。
圖6-2 DES加密算法基本流程
現在對圖6-2的整個流程做簡要的分析。DES對64位的明文分組M進行操作,M經過一個初始置換IP置換成m0,將m0明文分成左半部分和右半部分m0=(L0,R0),各32位長。然後進行16輪完全相同的運算,這些運算稱爲函數f,在運算過程中,數據與密匙結合。經過16輪運算之後,可以看到第16輪運算,將右側第15輪運算的結果(R15)作爲左側運算的最終結果(L16),而右側最後的結果(R16)爲左側第15輪運算結果(L15)和函數f運算結果的異或運算所得。此後,再將左、右部分合在一起經過一個逆置換,輸出密文。
實際加密過程要分成兩個同時進行的過程,即加密過程和密鑰生成過程,如圖6-3所示。結合圖6-2和圖6-3簡單講解密鑰生成過程。
圖6-3 加密與密鑰生成
如圖6-3所示,在16輪循環的每一輪中,密匙位移位,然後再從密匙的64位中選出48位。通過一個擴展置換將數據的右半部分擴展成48位,並通過一個異或操作替代成新的32位數據,在將其置換一次。這四步運算構成了圖6-2中的函數f。然後,通過另一個異或運算,函數f的輸出與左半部分結合,其結果成爲新的右半部分,原來的右半部分成爲新的左半部分。該操作重複16次。
DES算法的解密過程和加密過程幾乎完全相同,只是使用密鑰的順序相反。
關於DES算法的更加詳細的細節不在本書的講解範圍之內,請讀者參考相關資料。
NIST(National Institute of Standards and Technology,美國國家標準技術研究院)在1999年發佈了新的DES加密標準,3DES取代DES成爲新的加密標準。3DES採用168位的密鑰,三重加密,但速度較慢。之後,又出現了AES(Advanced Encryption Standard,先進加密標準)等高級對稱機密算法。
由於DES算法安全性方面的原因,爲了提高DES算法的抗攻擊性,因此提出了Triple-DES算法。
Triple-DES算法的基本原理是:用兩個密鑰對數據進行3次加密/解密運算。即首先使用第一個密鑰對數據進行加密,然後用第二個密鑰對其進行解密,最後用第一個密鑰再加密。這兩個密鑰可以是同一個,也可以不同,它們也可以來源於一個128位密鑰,只是在加密/解密時將其分割成兩個64位的密鑰,分別輪換使用這兩個64位密鑰去完成加密/解密運算。Triple-DES算法保留了DES算法運算速度快的特點,通過增加運算次數和密鑰長度(兩個64位密鑰相當於128位密鑰)來增加破解者的破解時間,但是從密碼學本身來說,其安全強度並沒有增加。
現在我們用到的RC系列算法包括RC2、RC4、RC5、RC6算法,其中RC4是序列密碼算法,其他三種是分組密碼算法。
(1) RC2算法
該算法設計的目的是用來取代DES算法,它採用密鑰長度可變的對明文采取64位分組的分組加密算法,屬於Festel網絡結構。
(2) RC4算法
該算法是一個密鑰長度可變的面向字節流的加密算法,以隨機置換爲基礎。該算法執行速度快,每輸出1字節的結果僅需要8~16字節的機器指令。RC4算法比較容易描述,它首先用8~2048位可變長度的密鑰初始化一個256字節的狀態矢量S。S的成員標記爲S[0],S[1],…,S[255],整個置換過程都包含0~255的8比特數。對於加密和解密,設字節數據爲K,由S中256個元素按一定方式選出一個元素生成,每生成一個K值,元素中的數據就要被重新置換一次。RC4初始化的僞代碼如代碼清單6-1所示。
代碼清單6-1 RC4初始化的僞代碼
for i=0 to 255
{
S[i]=i;
T[i]=K[i mod KeyLen ];
}
j=0;
for i=0 to 255
{
j=(j+T[i]+S[i]) mod 256;
swap(S[i],S[j];
}
如代碼清單6-1所示,初始化開始時,S的元素按從0到255依次賦值,同時建立一個臨時矢量T。如果密鑰K的長度爲256字節,則將K賦值給T。否則,若密鑰長度爲KeyLen字節,則將K的值賦給T的前KeyLen個元素,並循環重複用K餘下的元素賦給T剩下的元素。從“j=0”開始,用T產生S的初始置換。從S[0]~S[255],對每個S[i]根據T[i]確定的方案,將S[i]置換成S中的另一字節。
在完成S的初始化之後,輸入密鑰將被拋棄,接下來將使用密鑰流,生成密鑰流的僞代碼如代碼清單6-2所示。
代碼清單6-2 生成密鑰流
i=0;
j=0;
while(true)
{
i=(i+1) mod 256;
j=(j+S[i]) mod 256;
swap(S[i],j[i];
T=(S[i]+S[j]) mod 256;
K=S[T];
}
如代碼清單6-2所示,密鑰流的生成是從S[0]到S[255],對每個S[i]根據當前S的值將S[i]與S中的另一字節替換,當S[255]完成置換後操作繼續重複。在加密過程中將K的值與下一明文字節異或,解密過程中將K的值與下一密文字節異或即可。
(3) RC5算法
該算法是一種分組長度、密鑰長度、加密迭代輪數都可變的分組加密算法。該算法主要包含三部分內容:密鑰擴展、加密算法和解密算法。該算法包含三個參數:w(字的長度,單位:位)、r(迭代次數)、b(密鑰長度,單位:字節)。由於RC5算法需要(2r+2)個w位密鑰,所以需要密鑰擴展。
通過密鑰擴展,把密鑰K擴展成密鑰陣S,它由K所決定的t=2(r+1)個隨機二進制字構成。密鑰擴展算法利用了兩個幻常數:
函數Odd(x)的結果爲與x最近的奇整數。密鑰擴展的第一步是將密鑰K轉換成字格式,利用K的各字節構造字陣L。密鑰擴展的第二步是利用模232線性同餘算法初始化S陣。密鑰擴展的第三步是L陣和S陣混合。
加密過程也很簡單。假設選用的數據分組長度爲2w位(w允許的值有16、32和64),迭代次數爲r輪(r爲0~255)。首先將明文劃分成兩個w位的字A和B,運算過程如代碼清單6-3所示。
代碼清單6-3 RC5算法加密過程
A=A+S0;
B=B+S1;
for i=1 to r
{
A=((A+B)<<<B))+S2i;
B= ((B+A) <<<A)) +S2i+1;
}
代碼清單6-3的結果輸出到寄存器A和B中。
解密過程是加密過程的逆運算,基本過程如代碼清單6-4所示。
代碼清單6-4 RC5算法解密過程
for i=r down to 1
{
B=((B- S2i+1)>>>A)+A;
A=((A- S2i)>>>B)+B;
}
B=B-S1;
A=A-S0;
說明 加密和解密過程中的加減都是模2w的,表示逐位異或。<<<表示循環左移,>>>表示循環右移。
(4) RC6算法
RC6秉承了RC5設計簡單、廣泛使用數據相關的循環移位思想,同時增強了抵抗攻擊的能力,改進了RC5中循環移位的位數依賴於寄存器中所有位的不足。
RC6的特點是輸入的明文由原先2個區塊擴展爲4個區塊,另外,在運算方面則是使用了整數乘法,而整數乘法的使用則在每一個運算回合中增加了擴散(diffusion)的行爲,並且使得即使很少的回合數也有很高的安全性。同時,RC6中所用的操作可以在大部分處理器上高效率地實現,提高了加密速度。RC6是一種安全、架構完整而且簡單的區塊加密法。它提供了較好的測試結果和參數方面相當大的彈性。RC6可以抵抗所有已知的攻擊,能夠提供AES所要求的安全性,可以說是近幾年來相當優秀的一種加密法。
Rijndael是一個反覆運算的加密算法,它允許可變動的數據區塊及密鑰的長度。數據區塊與密鑰長度的變動是各自獨立的。
在Rijndael算法中定義了兩個名詞:
1) State:在運算過程中所產生的中間值,是一個4×Nb的矩陣,Nb可由數據長度除以32位求得,也就是把數據分割成Nb個區塊。
2) Cipher Key:用來做加密運算的密鑰,形式是一個4×Nk的矩陣,Nk可由金鑰長度除以32位求得,也就是把密鑰分割成Nk個32位的子密鑰。
在Rijndael算法中,運算的回合數(Nr)是由Nb及Nk決定的,回合數的變動定義如表6-1所示。
表6-1 Rijndael算法回合變動定義
Nr | Nb=4 | Nb=6 | Nb=8 |
Nk=4 | 10 | 12 | 14 |
Nk=6 | 12 | 12 | 14 |
Nk=8 | 14 | 14 | 14 |
在Rijndael中使用了許多字節層級的運算,而這些運算是以GF(28)爲基礎架構。也有一些採用了4-byte的字組運算。各種運算的定義如下:
假設一個字節b由b7b6b5b4b3b2b1b0組成,可以把這些bi想象成一個7次多項式的係數,而這些係數不是0就是1:
b7 x7+ b6 x6+ b5 x5+ b4 x4+ b3 x3+ b2 x2+ b1 x + b0
例如,(57)16的二進制表示法爲(0101,0111)2,表示成多項式,則爲:
x6+ x4+ x2+ x + 1
兩個多項式的加法,則是定義爲相同指數項的係數和再模2,簡單地說,就是作EXOR運算(1+1=0)。例如:
(57)16+(83)16=(01010111)2+(10000011)2 = (11010100)2 = (D4)16
或是
(x6+x4+x2+x+1)+(x7+x+1)=x7+x6+x4+x2
在乘法運算中,多項式相乘之後的結果很容易造成溢位的問題,解決溢位的方式是把相乘的結果,再模餘一個不可分解的多項式m(x)。在Rijndael中,定義一個這樣的多項式爲m(x)=x8+x4+x3+x+1或是(11B)16例如:
(57)16‧(83)16
=(x6+ x4+ x2+ x + 1)‧(x7+ x + 1)
=x13+ x11+ x9+ x8+ x7+x7+ x5+ x3+ x2+x+x6+ x4+ x2+ x + 1
=(x13+x11+x9+x8+x6+x5+x4+x3+1+x13+x11+x9+x8+x6+x5+x4+x3+1)mod(x8+x4+x3+x+1)
= x7+ x6+ 1
=(C1)16
若把b(x)乘以x,得到
b7 x8+ b6 x7+ b5 x6+ b4 x5+ b3 x4+ b2 x3+ b1 x2 + b0x
若b7=0,不會發生溢位問題,答案即是正確的;若b7=1,發生溢位問題,必須減去m(x)。可以把這種運算表示爲xtime(x),其運算方式爲left shift(若溢位則和(1B)16做EXOR運算),例如:
‘57’· ‘13’ = ‘FE’
‘57’ · ‘02’ = xtime(57) = ‘AE’
‘57’ · ‘04’ = xtime(AE) = ‘47’
‘57’ · ‘08’ = xtime(47) = ‘8E’
‘57’ · ‘10’ = xtime(8E) = ‘07’
‘57’ · ‘13’ = ‘57’ · (‘01’⊕‘02’⊕‘10’) = ‘57’⊕‘AE’⊕‘07’ = ‘FE’
Rijndael算法分爲四個步驟:
步驟 1 字節轉換。
字節轉換是一個以字節爲單位的非線性取代運算,取代表(S-box)是經過2個運算過程而建立,並且是可逆的。首先找出每個字節在GF(28)中的乘法反元素;接着經過1個仿射(Affine)轉換運算,轉換運算的定義如圖6-4所示。
圖6-4 轉換運算定義
取代表生成之後就可以進行字節取代運算。取代運算的示意圖如圖6-5所示。
圖6-5 取代運算示意圖
進行如圖6-5的取代運算之後,結果如圖6-6所示。
圖6-6 取代運算後的S-Box
說明 字節取代轉換的反運算:計算仿射對應之後的相反運算可得到S-1-box,以此S-1-box做字節取代(Subbytes)即可。
步驟 2 移行轉換。
在這個轉換中,State的每一行以不同的偏移量做環狀位移:第0 行不動,第1 行位移1 C個字節,第2 行位移2 C個字節,第3 行位移3 C個字節。位移的偏移量C1,C2,C3跟區塊的數目(Nb)有關,關係見圖6-7。
圖6-7 C1、 C2、 C3與區塊數目(Nb)的關係
移行轉換(Shift rows)運算對於State 的影響如圖6-8所示。
圖6-8 移行轉換對State的影響
說明 移行轉換的反運算:對第2、第3 及第4 行做Nb-C1、、Nb-C2、Nb-C3個字節的環狀位移即可。
步驟 3 混列轉換。
在這個轉換中,把State當做一個GF(28)中的多項式。並且對一個固定的多項式C(X)作乘法,如果發生溢位,則再模X4 +1. 表示如下:
C(X) ='03' X3 +'01' X2 +'01' X +'02'
C(X)與X4 +1互質,令
B(X) = C(X)⊕ A(X)
以矩陣乘法表示如圖6-9所示。
圖6-9 混列轉換的矩陣乘法表示
State經過混列(Mix columns)運算之後的變化如圖6-9所示。
圖6-9 混列運算對State的影響
說明 混列轉換的反運算是乘以一個特殊的多項式D(X):
('03' X3 +'01' X2 +'01' X +'02' )⊕ D(X)
='01' D(X)
='0B' X3 +'0D' X2 +'09' X +'0E'。
步驟 4 輪密鑰加。
這個運算主要是把每一個回合密鑰(Roundkey)透過簡單的Bitwise exor加入到每一個State中,如圖6-10所示。
圖6-10 Bitwise exor加入後的State
說明 此時Add round key的逆是它自身。
非對稱加密
非對稱加密算法是一種密鑰的保密方法。
非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。 非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將其中的一把作爲公用密鑰向其它方公開;得到該公用密鑰的乙方使用該密鑰對機密信息進行加密後再發送給甲方;甲方再用自己保存的另一把專用密鑰對加密後的信息進行解密。
另一方面,甲方可以使用乙方的公鑰對機密信息進行簽名後再發送給乙方;乙方再用自己的私匙對數據進行驗籤。
甲方只能用其專用密鑰解密由其公用密鑰加密後的任何信息。 非對稱加密算法的保密性比較好,它消除了最終用戶交換密鑰的需要。
非對稱密碼體制的特點:算法強度複雜、安全性依賴於算法與密鑰但是由於其算法複雜,而使得加密解密速度沒有對稱加密解密的速度快。對稱密碼體制中只有一種密鑰,並且是非公開的,如果要解密就得讓對方知道密鑰。所以保證其安全性就是保證密鑰的安全,而非對稱密鑰體制有兩種密鑰,其中一個是公開的,這樣就可以不需要像對稱密碼那樣傳輸對方的密鑰了。這樣安全性就大了很多。
起源:W.Diffie和M.Hellman 1976年在IEEE Trans.on Information刊物上發表了“ New Direction in Cryptography”文章,提出了“非對稱密碼體制即公開密鑰密碼體制”的概念,開創了密碼學研究的新方向。
工作原理:
公鑰和私鑰的產生
假設Alice想要通過一個不可靠的媒體接收Bob的一條私人訊息。她可以用以下的方式來產生一個公鑰和一個私鑰:
隨意選擇兩個大的質數p和q,p不等於q,計算N=pq。
根據歐拉函數,不大於N且與N互質的整數個數爲(p-1)(q-1)
選擇一個整數e與(p-1)(q-1)互質,並且e小於(p-1)(q-1)
用以下這個公式計算d:d×e≡1(mod(p-1)(q-1))
將p和q的記錄銷燬。
(N,e)是公鑰,(N,d)是私鑰。(N,d)是祕密的。Alice將她的公鑰(N,e)傳給Bob,而將她的私鑰(N,d)藏起來。
加密消息
假設Bob想給Alice送一個消息m,他知道Alice產生的N和e。他使用起先與Alice約好的格式將m轉換爲一個小於N的整數n,比如他可以將每一個字轉換爲這個字的Unicode碼,然後將這些數字連在一起組成一個數字。假如他的信息非常長的話,他可以將這個信息分爲幾段,然後將每一段轉換爲n。用下面這個公式他可以將n加密爲c:
計算c並不複雜。Bob算出c後就可以將它傳遞給Alice。
解密消息
Alice得到Bob的消息c後就可以利用她的密鑰d來解碼。她可以用以下這個公式來將c轉換爲n:
得到n後,她可以將原來的信息m重新復原。
解碼的原理是
以及ed≡1(modp-1)和ed≡1(modq-1)。由費馬小定理可證明(因爲p和q是質數)
這說明(因爲p和q是不同的質數,所以p和q互質)
主要應用:
非對稱加密(公鑰加密):指加密和解密使用不同密鑰的加密算法,也稱爲公私鑰加密。假設兩個用戶要加密交換數據,雙方交換公鑰,使用時一方用對方的公鑰加密,另一方即可用自己的私鑰解密。如果企業中有n個用戶,企業需要生成n對密鑰,並分發n個公鑰。由於公鑰是可以公開的,用戶只要保管好自己的私鑰即可,因此加密密鑰的分發將變得 十分簡單。同時,由於每個用戶的私鑰是唯一的,其他用戶除了可以可以通過信息發送者的公鑰來驗證信息的來源是否真實,還可以確保發送者無法否認曾發送過該信息。非對稱加密的缺點是加解密速度要遠遠慢於對稱加密,在某些極端情況下,甚至能比非對稱加密慢上1000倍。
DSACryptoServiceProvider
RSACryptoServiceProvider
//加密
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] PasswordBytes = encoding.GetBytes(password);//將密碼轉換爲字節數組RSACryptoServiceProvider crypt=new RSACryptoServiceProvider();//RSA加密算法,非對稱PasswordBytes=crypt.Encrypt(password ,false);//加密字節數組,這是加密後的密碼值,放入數據庫中的表字段中。
string key=crypt.ToXmlString(true);//輸出密鑰爲XML格式的字符串,且包含私鑰,這個字符串要作爲數據庫表中的一個字段同用戶的密碼放在一起。
//解密
RSACryptoServiceProvider crypt=new RSACryptoServiceProvider();//已隨機生成了一個密鑰對
crypt.Clear();//毀掉當前密鑰對
crypt.FromXmlString(key)//輸入密鑰對,key是從數據庫表字段中讀取的那個XML格式的字符串,即密鑰字段PasswordBytes=crypt.Decrypt(password ,false);//解密字節數組,返回原始密碼給用戶
上面方法的一個特點是每個用戶對應一個密鑰(包含公鑰和私鑰),它們都是隨機生成的,所以各不相同。不過缺點也是很明顯的,就是密鑰存儲在數據庫中,如果數據庫被攻破密鑰就泄漏了。
還有另外一個方法就是依照上面方法隨機生成一個密鑰對(包含公鑰和私鑰),通過ToXmlString(true)方法導出,然後把這個XML字符串格式的密鑰放到你的Web程序的Web.config文件的AppSetting節點裏面,然後通過FromXmlString(key)方法讀入密鑰,這樣就意味着所有的用戶密碼都用同一個密鑰對加密和解密。
主要功能:
非對稱加密體系不要求通信雙方事先傳遞密鑰或有任何約定就能完成保密通信,並且密鑰管理方便,可實現防止假冒和抵賴,因此,更適合網絡通信中的保密通信要求。
主要算法:
RSA、Elgamal、揹包算法、Rabin、HD,ECC(橢圓曲線加密算法)。
使用最廣泛的是RSA算法,Elgamal是另一種常用的非對稱加密算法。
Elgamal由Taher Elgamal於1985年發明,其基礎是DiffieˉHellman密鑰交換算法,後者使通信雙方能通過公開通信來推導出只有他們知道的祕密密鑰值[DiffieˉHellman]。DiffieˉHellman是Whitfield Diffie和Martin Hellman於1976年發明的,被視爲第一種 非對稱加密算法,DiffieˉHellman 與RSA的不同之處在於,DiffieˉHellman不是加密算法,它只是生成可用作對稱密鑰的祕密數值。在DiffieˉHellman密鑰交換過程中,發送方和接收方分別生成一個祕密的隨機數,並根據隨機數推導出公開值,然後,雙方再交換公開值。DiffieˉHellman算法的基礎是具備生成共享密鑰的能力。只要交換了公開值,雙方就能使用自己的私有數和對方的公開值來生成對稱密鑰,稱爲共享密鑰,對雙方來說,該對稱密鑰是相同的,可以用於使用對稱加密算法加密數據。
與RSA相比,DiffieˉHellman的優勢之一是每次交換密鑰時都使用一組新值,而使用RSA算法時,如果攻擊者獲得了私鑰,那麼他不僅能解密之前截獲的消息,還能解密之後的所有消息。然而,RSA可以通過認證(如使用X.509數字證書)來防止中間人攻擊,但Diff ieˉHellman在應對中間人攻擊時非常脆弱。
與對稱加密算法的區別
首先,用於消息解密的密鑰值與用於消息加密的密鑰值不同;
其次,非對稱加密算法比對稱加密算法慢數千倍,但在保護通信安全方面,非對稱加密算法卻具有對稱密碼難以企及的優勢。
爲說明這種優勢,使用對稱加密算法的例子來強調:
Alice使用密鑰K加密消息並將其發送給Bob,Bob收到加密的消息後,使用密鑰K對其解密以恢復原始消息。這裏存在一個問題,即Alice如何將用於加密消息的密鑰值發送給 Bob?答案是,Alice發送密鑰值給Bob時必須通過獨立的安全通信信道(即沒人能監聽到該信道中的通信)。
這種使用獨立安全信道來交換對稱加密算法密鑰的需求會帶來更多問題:
首先,有獨立的安全信道,但是安全信道的帶寬有限,不能直接用它發送原始消息。
其次,Alice和Bob不能確定他們的密鑰值可以保持多久而不泄露(即不被其他人知道)以及何時交換新的密鑰值
當然,這些問題不只Alice會遇到,Bob和其他每個人都會遇到,他們都需要交換密鑰並處理這些密鑰管理問題(事實上,X9.17是一項DES密鑰管理ANSI標準[ANSIX9.17])。如果Alice要給數百人發送消息,那麼事情將更麻煩,她必須使用不同的密鑰值來加密每條消息。例如,要給200個人發送通知,Alice需要加密消息200次,對每個接收方加密一次消息。顯然,在這種情況下,使用對稱加密算法來進行安全通信的開銷相當大。
非對稱加密算法的主要優勢就是使用兩個而不是一個密鑰值:一個密鑰值用來加密消息,另一個密鑰值用來解密消息。這兩個密鑰值在同一個過程中生成,稱爲密鑰對。用來加密消息的密鑰稱爲公鑰,用來解密消息的密鑰稱爲私鑰。用公鑰加密的消息只能用與之對應的私鑰來解密,私鑰除了持有者外無人知道,而公鑰卻可通過非安全管道來發送或在目錄中發佈。
Alice需要通過電子郵件給Bob發送一個機密文檔。首先,Bob使用電子郵件將自己的公鑰發送給Alice。然後Alice用Bob的公鑰對文檔加密並通過電子郵件將加密消息發送給Bob。由於任何用Bob 的公鑰加密的消息只能用Bob的私鑰解密,因此即使窺探者知道Bob的公鑰,消息也仍是安全的。Bob在收到加密消息後,用自己的私鑰進行解密從而恢復原始文檔。
Base64加密算法
Base64加密後進行GZIP壓縮處理,獲得明文,安全性得到了保證。
簡介
標準的Base64並不適合直接放在URL裏傳輸,因爲URL編碼器會把標準Base64中的“/”和“+”字符變爲形如“%XX”的形式,而這些“%”號在存入數據庫時還需要再進行轉換,因爲ANSI SQL中已將“%”號用作通配符。
爲解決此問題,可採用一種用於URL的改進Base64編碼,它不在末尾填充'='號,並將標 準Base64中的“+”和“/”分別改成了“*”和“-”,這樣就免去了在URL編解碼和數據庫存儲時所要作的轉換,避免了編碼信息長度在此過程中的增 加,並統一了數據庫、表單等處對象標識符的格式。
另有一種用於正則表達式的改進Base64變種,它將“+”和“/”改成了“!”和“-”,因爲“+”,“*”以及前面在IRCu中用到的“[”和“]”在正則表達式中都可能具有特殊含義。
此外還有一些變種,它們將“+/”改爲“_-”或“._”(用作編程語言中的標識符名稱)或“.-”(用於XML中的Nmtoken)甚至“_:”(用於XML中的Name)。
Base64要求把每三個8Bit的字節轉換爲四個6Bit的字節(3*8 = 4*6 = 24),然後把6Bit再添兩位高位0,組成四個8Bit的字節,也就是說,轉換後的字符串理論上將要比原來的長1/3。
規則
關於這個編碼的規則:
①.把3個字符變成4個字符..
②每76個字符加一個換行符..
③.最後的結束符也要處理..
這樣說會不會太抽象了?不怕,我們來看一個例子:
轉換前 aaaaaabb ccccdddd eeffffff
轉換後 00aaaaaa 00bbcccc 00ddddee 00ffffff
應該很清楚了吧?上面的三個字節是原文,下面的四個字節是轉換後的Base64編碼,其前兩位均爲0。
轉換後,我們用一個碼錶來得到我們想要的字符串(也就是最終的Base64編碼),這個表是這樣的:(摘自RFC2045)
轉換表
索引 | 對應字符 | 索引 | 對應字符 | 索引 | 對應字符 | 索引 | 對應字符 |
0 | A | 17 | R | 34 | i | 51 | z |
1 | B | 18 | S | 35 | j | 52 | 0 |
2 | C | 19 | T | 36 | k | 53 | 1 |
3 | D | 20 | U | 37 | l | 54 | 2 |
4 | E | 21 | V | 38 | m | 55 | 3 |
5 | F | 22 | W | 39 | n | 56 | 4 |
6 | G | 23 | X | 40 | o | 57 | 5 |
7 | H | 24 | Y | 41 | p | 58 | 6 |
8 | I | 25 | Z | 42 | q | 59 | 7 |
9 | J | 26 | a | 43 | r | 60 | 8 |
10 | K | 27 | b | 44 | s | 61 | 9 |
11 | L | 28 | c | 45 | t | 62 | + |
12 | M | 29 | d | 46 | u | 63 | / |
13 | N | 30 | e | 47 | v |
|
|
14 | O | 31 | f | 48 | w |
|
|
15 | P | 32 | g | 49 | x |
|
|
16 | Q | 33 | h | 50 | y | pad | = |
舉例
讓我們再來看一個實際的例子,加深印象!
轉換前 10101101 10111010 01110110
轉換後 00101011 00011011 00101001 00110110
十進制 43 27 41 54
對應碼錶中的值 r b p 2
所以上面的24位編碼,編碼後的Base64值爲rbp2
解碼同理,把 rbq2 的二進制位連接上再重組得到三個8位值,得出原碼。
(解碼只是編碼的逆過程,在此我就不多說了,另外有關MIME的RFC還是有很多的,如果需要詳細情況請自行查找。)
用更接近於編程的思維來說,編碼的過程是這樣的:
第一個字符通過右移2位獲得第一個目標字符的Base64表位置,根據這個數值取到表上相應的字符,就是第一個目標字符。
然後將第一個字符左移4位加上第二個字符右移4位,即獲得第二個目標字符。
再將第二個字符左移2位加上第三個字符右移6位,獲得第三個目標字符。
最後取第三個字符的右6位即獲得第四個目標字符。
在以上的每一個步驟之後,再把結果與 0x3F 進行 AND 位操作,就可以得到編碼後的字符了。
可是等等……聰明的你可能會問到,原文的字節數量應該是3的倍數啊,如果這個條件不能滿足的話,那該怎麼辦呢?
我們的解決辦法是這樣的:原文的字節不夠的地方可以用全0來補足,轉換時Base64編碼用=號來代替。這就是爲什麼有些Base64編碼會以一個或兩個等號結束的原因,但等號最多隻有兩個。因爲:
餘數 = 原文字節數 MOD 3
所以餘數任何情況下都只可能是0,1,2這三個數中的一個。如果餘數是0的話,就表示原文字節數正好是3的倍數(最理想的情況啦)。如果是1的話,爲了讓Base64編碼是3的倍數,就要補2個等號;同理,如果是2的話,就要補1個等號。
各種下載軟件地址
先以“迅雷下載”爲例: 很多下載類網站都提供“迅雷下載”的鏈接,其地址通常是加密的迅雷專用下載地址。
如thunder://QUFodHRwOi8vd3d3LmJhaWR1LmNvbS9pbWcvc3NsbTFfbG9nby5naWZaWg==
其實迅雷的“專用地址”也是用Base64加密的,其加密過程如下:
一、在地址的前後分別添加AA和ZZ
如www.baidu.com/img/sslm1_logo.gif變成
AAwww.baidu.com/img/sslm1_logo.gifZZ
二、對新的字符串進行Base64編碼
如AAwww.baidu.com/img/sslm1_logo.gifZZ用Base64編碼得到
QUF3d3cuYmFpZHUuY29tL2ltZy9zc2xtMV9sb2dvLmdpZlpa
三、在上面得到的字符串前加上“thunder://”就成了
thunder://QUF3d3cuYmFpZHUuY29tL2ltZy9zc2xtMV9sb2dvLmdpZlpa
另:
Flashget的與迅雷類似,只不過在第一步時加的“料”不同罷了,Flashget在地址前後加的“料”是[FLASHGET]
而QQ旋風的乾脆不加料,直接就對地址進行Base64編碼了
各語言實現方式
php
[下列代碼僅在GBK中實現,UTF8代碼請把 if($button=="迅雷地址->普通地址") echosubstr(base64_decode(str_ireplace("thunder://","",$txt1)),2,-2);這句改爲if($button=="迅雷地址->普通地址") echosubstr(mb_convert_encoding(base64_decode(str_ireplace("thunder://","",$txt1))),2,-2);並把charset=gb2312改爲charset=utf-8]
- <?php
- $txt1=trim($_POST['text1']);
- $txt2=trim($_POST['text2']);
- $txt3=trim($_POST['text3']);
- $button=$_POST['button'];
- ?>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
- <html>
- <head>
- <title>迅雷和FlashGet,QQ旋風地址 地址轉換工具</title>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <meta content="迅雷,FlashGet,地址轉換," name="keywords">
- </head>
- <body>
- <form name="form1" method="post" action="">
- <hr size="1">
- <h3>迅雷轉換</h3>
- <P>轉換地址:
- <input name="text1" value="<?php echo $txt1;?>" type="text" style="width:516px;" /></P>
- <P>轉換後的:
- <input type="text" value="<?php
- if($button=="普通地址->迅雷地址") echo "thunder://".base64_encode("AA".$txt1."ZZ");
- if($button=="迅雷地址->普通地址") echo substr(base64_decode(str_ireplace("thunder://","",$txt1)),2,-2);
- ?>" style="width:516px;" /></P>
- <P>
- <input type="submit" name="button" value="普通地址->迅雷地址" />
- <input type="submit" name="button" value="迅雷地址->普通地址" /></P>
- <h3>FlashGet轉換</h3>
- <P>FlashGet地址:
- <input name="text2" value="<?php echo $txt2;?>" type="text" style="width:516px;" /></P>
- <P>轉換後 地址:
- <input type="text" value="<?php
- if($button=="普通地址->FlashGet地址") echo "flashget://".base64_encode($txt2);
- if($button=="FlashGet地址->普通地址") echo str_ireplace("[FLASHGET]","",base64_decode(str_ireplace("flashget://","",$txt2)));
- ?>" style="width:516px;" /></P>
- <P>
- <input type="submit" value="普通地址->FlashGet地址" name="button" />
- <input type="submit" value="FlashGet地址->普通地址" name="button" /></P>
- <h3>QQ旋風轉換</h3>
- <P>QQ旋風地址:
- <input name="text3" value="<?php echo $txt3;?>" type="text" style="width:516px;" /></P>
- <P>轉換後 地址:
- <input type="text" value="<?php
- if($button=="普通地址->QQ旋風") echo "qqdl://".base64_encode($txt3);
- if($button=="QQ旋風->普通地址") echo base64_decode(str_ireplace("qqdl://","",$txt3));
- ?>" style="width:516px;" /></P>
- <P>
- <input type="submit" value="普通地址->QQ旋風" name="button" />
- <input type="submit" value="QQ旋風->普通地址" name="button" /></P>
- </form>
- </body>
- </html>
VB
- Option Explicit
- ' Base64 Encoding/Decoding Algorithm
- ' By: David Midkiff ([email protected])
- '
- ' This algorithms encodes and decodes data into Base64
- ' format. This format is extremely more efficient than
- ' Hexadecimal encoding.
- Private m_bytIndex(0 To 63) As Byte
- Private m_bytReverseIndex(0 To 255) As Byte
- Private Const k_bytEqualSign As Byte = 61
- Private Const k_bytMask1 As Byte = 3
- Private Const k_bytMask2 As Byte = 15
- Private Const k_bytMask3 As Byte = 63
- Private Const k_bytMask4 As Byte = 192
- Private Const k_bytMask5 As Byte = 240
- Private Const k_bytMask6 As Byte = 252
- Private Const k_bytShift2 As Byte = 4
- Private Const k_bytShift4 As Byte = 16
- Private Const k_bytShift6 As Byte = 64
- Private Const k_lMaxBytesPerLine As Long = 152
- Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
- Public Function Decode64(sInput As String) As String
- If sInput = "" Then Exit Function
- Decode64 = StrConv(DecodeArray64(sInput), vbUnicode)
- End Function
- Private Function DecodeArray64(sInput As String) As Byte()
- Dim bytInput() As Byte
- Dim bytWorkspace() As Byte
- Dim bytResult() As Byte
- Dim lInputCounter As Long
- Dim lWorkspaceCounter As Long
- bytInput = Replace(Replace(sInput, vbCrLf, ""), "=", "")
- ReDim bytWorkspace(LBound(bytInput) To (UBound(bytInput) * 2)) As Byte
- lWorkspaceCounter = LBound(bytWorkspace)
- For lInputCounter = LBound(bytInput) To UBound(bytInput)
- bytInput(lInputCounter) = m_bytReverseIndex(bytInput(lInputCounter))
- Next lInputCounter
- For lInputCounter = LBound(bytInput) To (UBound(bytInput) - ((UBound(bytInput) Mod 8) + 8)) Step 8
- bytWorkspace(lWorkspaceCounter) = (bytInput(lInputCounter) * k_bytShift2) + (bytInput(lInputCounter + 2) \ k_bytShift4)
- bytWorkspace(lWorkspaceCounter + 1) = ((bytInput(lInputCounter + 2) And k_bytMask2) * k_bytShift4) + (bytInput(lInputCounter + 4) \ k_bytShift2)
- bytWorkspace(lWorkspaceCounter + 2) = ((bytInput(lInputCounter + 4) And k_bytMask1) * k_bytShift6) + bytInput(lInputCounter + 6)
- lWorkspaceCounter = lWorkspaceCounter + 3
- Next lInputCounter
- Select Case (UBound(bytInput) Mod 8):
- Case 3:
- bytWorkspace(lWorkspaceCounter) = (bytInput(lInputCounter) * k_bytShift2) + (bytInput(lInputCounter + 2) \ k_bytShift4)
- Case 5:
- bytWorkspace(lWorkspaceCounter) = (bytInput(lInputCounter) * k_bytShift2) + (bytInput(lInputCounter + 2) \ k_bytShift4)
- bytWorkspace(lWorkspaceCounter + 1) = ((bytInput(lInputCounter + 2) And k_bytMask2) * k_bytShift4) + (bytInput(lInputCounter + 4) \ k_bytShift2)
- lWorkspaceCounter = lWorkspaceCounter + 1
- Case 7:
- bytWorkspace(lWorkspaceCounter) = (bytInput(lInputCounter) * k_bytShift2) + (bytInput(lInputCounter + 2) \ k_bytShift4)
- bytWorkspace(lWorkspaceCounter + 1) = ((bytInput(lInputCounter + 2) And k_bytMask2) * k_bytShift4) + (bytInput(lInputCounter + 4) \ k_bytShift2)
- bytWorkspace(lWorkspaceCounter + 2) = ((bytInput(lInputCounter + 4) And k_bytMask1) * k_bytShift6) + bytInput(lInputCounter + 6)
- lWorkspaceCounter = lWorkspaceCounter + 2
- End Select
- ReDim bytResult(LBound(bytWorkspace) To lWorkspaceCounter) As Byte
- If LBound(bytWorkspace) = 0 Then lWorkspaceCounter = lWorkspaceCounter + 1
- CopyMemory VarPtr(bytResult(LBound(bytResult))), VarPtr(bytWorkspace(LBound(bytWorkspace))), lWorkspaceCounter
- DecodeArray64 = bytResult
- End Function
- Public Function Encode64(ByRef sInput As String) As String
- If sInput = "" Then Exit Function
- Dim bytTemp() As Byte
- bytTemp = StrConv(sInput, vbFromUnicode)
- Encode64 = EncodeArray64(bytTemp)
- End Function
- Private Function EncodeArray64(ByRef bytInput() As Byte) As String
- On Error GoTo ErrorHandler
- Dim bytWorkspace() As Byte, bytResult() As Byte
- Dim bytCrLf(0 To 3) As Byte, lCounter As Long
- Dim lWorkspaceCounter As Long, lLineCounter As Long
- Dim lCompleteLines As Long, lBytesRemaining As Long
- Dim lpWorkSpace As Long, lpResult As Long
- Dim lpCrLf As Long
- If UBound(bytInput) < 1024 Then
- ReDim bytWorkspace(LBound(bytInput) To (LBound(bytInput) + 4096)) As Byte
- Else
- ReDim bytWorkspace(LBound(bytInput) To (UBound(bytInput) * 4)) As Byte
- End If
- lWorkspaceCounter = LBound(bytWorkspace)
- For lCounter = LBound(bytInput) To (UBound(bytInput) - ((UBound(bytInput) Mod 3) + 3)) Step 3
- bytWorkspace(lWorkspaceCounter) = m_bytIndex((bytInput(lCounter) \ k_bytShift2))
- bytWorkspace(lWorkspaceCounter + 2) = m_bytIndex(((bytInput(lCounter) And k_bytMask1) * k_bytShift4) + ((bytInput(lCounter + 1)) \ k_bytShift4))
- bytWorkspace(lWorkspaceCounter + 4) = m_bytIndex(((bytInput(lCounter + 1) And k_bytMask2) * k_bytShift2) + (bytInput(lCounter + 2) \ k_bytShift6))
- bytWorkspace(lWorkspaceCounter + 6) = m_bytIndex(bytInput(lCounter + 2) And k_bytMask3)
- lWorkspaceCounter = lWorkspaceCounter + 8
- Next lCounter
- Select Case (UBound(bytInput) Mod 3):
- Case 0:
- bytWorkspace(lWorkspaceCounter) = m_bytIndex((bytInput(lCounter) \ k_bytShift2))
- bytWorkspace(lWorkspaceCounter + 2) = m_bytIndex((bytInput(lCounter) And k_bytMask1) * k_bytShift4)
- bytWorkspace(lWorkspaceCounter + 4) = k_bytEqualSign
- bytWorkspace(lWorkspaceCounter + 6) = k_bytEqualSign
- Case 1:
- bytWorkspace(lWorkspaceCounter) = m_bytIndex((bytInput(lCounter) \ k_bytShift2))
- bytWorkspace(lWorkspaceCounter + 2) = m_bytIndex(((bytInput(lCounter) And k_bytMask1) * k_bytShift4) + ((bytInput(lCounter + 1)) \ k_bytShift4))
- bytWorkspace(lWorkspaceCounter + 4) = m_bytIndex((bytInput(lCounter + 1) And k_bytMask2) * k_bytShift2)
- bytWorkspace(lWorkspaceCounter + 6) = k_bytEqualSign
- Case 2:
- bytWorkspace(lWorkspaceCounter) = m_bytIndex((bytInput(lCounter) \ k_bytShift2))
- bytWorkspace(lWorkspaceCounter + 2) = m_bytIndex(((bytInput(lCounter) And k_bytMask1) * k_bytShift4) + ((bytInput(lCounter + 1)) \ k_bytShift4))
- bytWorkspace(lWorkspaceCounter + 4) = m_bytIndex(((bytInput(lCounter + 1) And k_bytMask2) * k_bytShift2) + ((bytInput(lCounter + 2)) \ k_bytShift6))
- bytWorkspace(lWorkspaceCounter + 6) = m_bytIndex(bytInput(lCounter + 2) And k_bytMask3)
- End Select
- lWorkspaceCounter = lWorkspaceCounter + 8
- If lWorkspaceCounter <= k_lMaxBytesPerLine Then
- EncodeArray64 = Left$(bytWorkspace, InStr(1, bytWorkspace, Chr$(0)) - 1)
- Else
- bytCrLf(0) = 13
- bytCrLf(1) = 0
- bytCrLf(2) = 10
- bytCrLf(3) = 0
- ReDim bytResult(LBound(bytWorkspace) To UBound(bytWorkspace))
- lpWorkSpace = VarPtr(bytWorkspace(LBound(bytWorkspace)))
- lpResult = VarPtr(bytResult(LBound(bytResult)))
- lpCrLf = VarPtr(bytCrLf(LBound(bytCrLf)))
- lCompleteLines = Fix(lWorkspaceCounter / k_lMaxBytesPerLine)
- For lLineCounter = 0 To lCompleteLines
- CopyMemory lpResult, lpWorkSpace, k_lMaxBytesPerLine
- lpWorkSpace = lpWorkSpace + k_lMaxBytesPerLine
- lpResult = lpResult + k_lMaxBytesPerLine
- CopyMemory lpResult, lpCrLf, 4&
- lpResult = lpResult + 4&
- Next lLineCounter
- lBytesRemaining = lWorkspaceCounter - (lCompleteLines * k_lMaxBytesPerLine)
- If lBytesRemaining > 0 Then CopyMemory lpResult, lpWorkSpace, lBytesRemaining
- EncodeArray64 = Left$(bytResult, InStr(1, bytResult, Chr$(0)) - 1)
- End If
- Exit Function
- ErrorHandler:
- Erase bytResult
- EncodeArray64 = bytResult
- End Function
- Private Sub Class_Initialize()
- m_bytIndex(0) = 65 'Asc("A")
- m_bytIndex(1) = 66 'Asc("B")
- m_bytIndex(2) = 67 'Asc("C")
- m_bytIndex(3) = 68 'Asc("D")
- m_bytIndex(4) = 69 'Asc("E")
- m_bytIndex(5) = 70 'Asc("F")
- m_bytIndex(6) = 71 'Asc("G")
- m_bytIndex(7) = 72 'Asc("H")
- m_bytIndex(8) = 73 'Asc("I")
- m_bytIndex(9) = 74 'Asc("J")
- m_bytIndex(10) = 75 'Asc("K")
- m_bytIndex(11) = 76 'Asc("L")
- m_bytIndex(12) = 77 'Asc("M")
- m_bytIndex(13) = 78 'Asc("N")
- m_bytIndex(14) = 79 'Asc("O")
- m_bytIndex(15) = 80 'Asc("P")
- m_bytIndex(16) = 81 'Asc("Q")
- m_bytIndex(17) = 82 'Asc("R")
- m_bytIndex(18) = 83 'Asc("S")
- m_bytIndex(19) = 84 'Asc("T")
- m_bytIndex(20) = 85 'Asc("U")
- m_bytIndex(21) = 86 'Asc("V")
- m_bytIndex(22) = 87 'Asc("W")
- m_bytIndex(23) = 88 'Asc("X")
- m_bytIndex(24) = 89 'Asc("Y")
- m_bytIndex(25) = 90 'Asc("Z")
- m_bytIndex(26) = 97 'Asc("a")
- m_bytIndex(27) = 98 'Asc("b")
- m_bytIndex(28) = 99 'Asc("c")
- m_bytIndex(29) = 100 'Asc("d")
- m_bytIndex(30) = 101 'Asc("e")
- m_bytIndex(31) = 102 'Asc("f")
- m_bytIndex(32) = 103 'Asc("g")
- m_bytIndex(33) = 104 'Asc("h")
- m_bytIndex(34) = 105 'Asc("i")
- m_bytIndex(35) = 106 'Asc("j")
- m_bytIndex(36) = 107 'Asc("k")
- m_bytIndex(37) = 108 'Asc("l")
- m_bytIndex(38) = 109 'Asc("m")
- m_bytIndex(39) = 110 'Asc("n")
- m_bytIndex(40) = 111 'Asc("o")
- m_bytIndex(41) = 112 'Asc("p")
- m_bytIndex(42) = 113 'Asc("q")
- m_bytIndex(43) = 114 'Asc("r")
- m_bytIndex(44) = 115 'Asc("s")
- m_bytIndex(45) = 116 'Asc("t")
- m_bytIndex(46) = 117 'Asc("u")
- m_bytIndex(47) = 118 'Asc("v")
- m_bytIndex(48) = 119 'Asc("w")
- m_bytIndex(49) = 120 'Asc("x")
- m_bytIndex(50) = 121 'Asc("y")
- m_bytIndex(51) = 122 'Asc("z")
- m_bytIndex(52) = 48 'Asc("0")
- m_bytIndex(53) = 49 'Asc("1")
- m_bytIndex(54) = 50 'Asc("2")
- m_bytIndex(55) = 51 'Asc("3")
- m_bytIndex(56) = 52 'Asc("4")
- m_bytIndex(57) = 53 'Asc("5")
- m_bytIndex(58) = 54 'Asc("6")
- m_bytIndex(59) = 55 'Asc("7")
- m_bytIndex(60) = 56 'Asc("8")
- m_bytIndex(61) = 57 'Asc("9")
- m_bytIndex(62) = 43 'Asc("+")
- m_bytIndex(63) = 47 'Asc("/")
- m_bytReverseIndex(65) = 0 'Asc("A")
- m_bytReverseIndex(66) = 1 'Asc("B")
- m_bytReverseIndex(67) = 2 'Asc("C")
- m_bytReverseIndex(68) = 3 'Asc("D")
- m_bytReverseIndex(69) = 4 'Asc("E")
- m_bytReverseIndex(70) = 5 'Asc("F")
- m_bytReverseIndex(71) = 6 'Asc("G")
- m_bytReverseIndex(72) = 7 'Asc("H")
- m_bytReverseIndex(73) = 8 'Asc("I")
- m_bytReverseIndex(74) = 9 'Asc("J")
- m_bytReverseIndex(75) = 10 'Asc("K")
- m_bytReverseIndex(76) = 11 'Asc("L")
- m_bytReverseIndex(77) = 12 'Asc("M")
- m_bytReverseIndex(78) = 13 'Asc("N")
- m_bytReverseIndex(79) = 14 'Asc("O")
- m_bytReverseIndex(80) = 15 'Asc("P")
- m_bytReverseIndex(81) = 16 'Asc("Q")
- m_bytReverseIndex(82) = 17 'Asc("R")
- m_bytReverseIndex(83) = 18 'Asc("S")
- m_bytReverseIndex(84) = 19 'Asc("T")
- m_bytReverseIndex(85) = 20 'Asc("U")
- m_bytReverseIndex(86) = 21 'Asc("V")
- m_bytReverseIndex(87) = 22 'Asc("W")
- m_bytReverseIndex(88) = 23 'Asc("X")
- m_bytReverseIndex(89) = 24 'Asc("Y")
- m_bytReverseIndex(90) = 25 'Asc("Z")
- m_bytReverseIndex(97) = 26 'Asc("a")
- m_bytReverseIndex(98) = 27 'Asc("b")
- m_bytReverseIndex(99) = 28 'Asc("c")
- m_bytReverseIndex(100) = 29 'Asc("d")
- m_bytReverseIndex(101) = 30 'Asc("e")
- m_bytReverseIndex(102) = 31 'Asc("f")
- m_bytReverseIndex(103) = 32 'Asc("g")
- m_bytReverseIndex(104) = 33 'Asc("h")
- m_bytReverseIndex(105) = 34 'Asc("i")
- m_bytReverseIndex(106) = 35 'Asc("j")
- m_bytReverseIndex(107) = 36 'Asc("k")
- m_bytReverseIndex(108) = 37 'Asc("l")
- m_bytReverseIndex(109) = 38 'Asc("m")
- m_bytReverseIndex(110) = 39 'Asc("n")
- m_bytReverseIndex(111) = 40 'Asc("o")
- m_bytReverseIndex(112) = 41 'Asc("p")
- m_bytReverseIndex(113) = 42 'Asc("q")
- m_bytReverseIndex(114) = 43 'Asc("r")
- m_bytReverseIndex(115) = 44 'Asc("s")
- m_bytReverseIndex(116) = 45 'Asc("t")
- m_bytReverseIndex(117) = 46 'Asc("u")
- m_bytReverseIndex(118) = 47 'Asc("v")
- m_bytReverseIndex(119) = 48 'Asc("w")
- m_bytReverseIndex(120) = 49 'Asc("x")
- m_bytReverseIndex(121) = 50 'Asc("y")
- m_bytReverseIndex(122) = 51 'Asc("z")
- m_bytReverseIndex(48) = 52 'Asc("0")
- m_bytReverseIndex(49) = 53 'Asc("1")
- m_bytReverseIndex(50) = 54 'Asc("2")
- m_bytReverseIndex(51) = 55 'Asc("3")
- m_bytReverseIndex(52) = 56 'Asc("4")
- m_bytReverseIndex(53) = 57 'Asc("5")
- m_bytReverseIndex(54) = 58 'Asc("6")
- m_bytReverseIndex(55) = 59 'Asc("7")
- m_bytReverseIndex(56) = 60 'Asc("8")
- m_bytReverseIndex(57) = 61 'Asc("9")
- m_bytReverseIndex(43) = 62 'Asc("+")
- m_bytReverseIndex(47) = 63 'Asc("/")
- End Sub
JS
- var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- var base64DecodeChars = new Array(
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
- function base64encode(str)
- {
- var returnVal, i, len;
- var c1, c2, c3;
- len = str.length;
- i = 0;
- returnVal = "";
- while(i < len)
- {
- c1 = str.charCodeAt(i++) & 0xff;
- if(i == len)
- {
- returnVal += base64EncodeChars.charAt(c1 >> 2);
- returnVal += base64EncodeChars.charAt((c1 & 0x3) << 4);
- returnVal += "==";
- break;
- }
- c2 = str.charCodeAt(i++);
- if(i == len)
- {
- returnVal += base64EncodeChars.charAt(c1 >> 2);
- returnVal += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
- returnVal += base64EncodeChars.charAt((c2 & 0xF) << 2);
- returnVal += "=";
- break;
- }
- c3 = str.charCodeAt(i++);
- returnVal += base64EncodeChars.charAt(c1 >> 2);
- returnVal += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
- returnVal += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
- returnVal += base64EncodeChars.charAt(c3 & 0x3F);
- }
- return returnVal;
- }
- function base64decode(str)
- {
- var c1, c2, c3, c4;
- var i, len, returnVal;
- len = str.length;
- i = 0;
- returnVal = "";
- while(i < len)
- {
- /* c1 */
- do
- {
- c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
- } while(i < len && c1 == -1);
- if(c1 == -1)
- break;
- /* c2 */
- do
- {
- c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
- } while(i < len && c2 == -1);
- if(c2 == -1)
- break;
- returnVal += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
- /* c3 */
- do
- {
- c3 = str.charCodeAt(i++) & 0xff;
- if(c3 == 61)
- return returnVal;
- c3 = base64DecodeChars[c3];
- } while(i < len && c3 == -1);
- if(c3 == -1)
- break;
- returnVal += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
- /* c4 */
- do
- {
- c4 = str.charCodeAt(i++) & 0xff;
- if(c4 == 61)
- return returnVal;
- c4 = base64DecodeChars[c4];
- } while(i < len && c4 == -1);
- if(c4 == -1)
- break;
- returnVal += String.fromCharCode(((c3 & 0x03) << 6) | c4);
- }
- return returnVal;
- }
AS
- package crypto{
- import flash.utils.ByteArray;
- public class Base64 {
- private static const BASE64_CHARS:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- public static function encode(data:String):String {
- // Convert string to ByteArray
- var bytes:ByteArray = new ByteArray();
- bytes.writeUTFBytes(data);
- // Return encoded ByteArray
- return encodeByteArray(bytes);
- }
- public static function encodeByteArray(data:ByteArray):String {
- // Initialise output
- var output:String = "";
- // Create data and output buffers
- var dataBuffer:Array;
- var outputBuffer:Array = new Array(4);
- // Rewind ByteArray
- data.position = 0;
- // while there are still bytes to be processed
- while (data.bytesAvailable > 0) {
- // Create new data buffer and populate next 3 bytes from data
- dataBuffer = new Array();
- for (var i:uint = 0; i < 3 && data.bytesAvailable > 0; i++) {
- dataBuffer= data.readUnsignedByte();
- }
- // Convert to data buffer Base64 character positions and
- // store in output buffer
- outputBuffer[0] = (dataBuffer[0] & 0xfc) >> 2;
- outputBuffer[1] = ((dataBuffer[0] & 0x03) << 4) | ((dataBuffer[1]) >> 4);
- outputBuffer[2] = ((dataBuffer[1] & 0x0f) << 2) | ((dataBuffer[2]) >> 6);
- outputBuffer[3] = dataBuffer[2] & 0x3f;
- // If data buffer was short (i.e not 3 characters) then set
- // end character indexes in data buffer to index of '=' symbol.
- // This is necessary because Base64 data is always a multiple of
- // 4 bytes and is basses with '=' symbols.
- for (var j:uint = dataBuffer.length; j < 3; j++) {
- outputBuffer[j + 1] = 64;
- }
- // Loop through output buffer and add Base64 characters to
- // encoded data string for each character.
- for (var k:uint = 0; k < outputBuffer.length; k++) {
- output += BASE64_CHARS.charAt(outputBuffer[k]);
- }
- }
- // Return encoded data
- return output;
- }
- public static function decode(data:String):String {
- // Decode data to ByteArray
- var bytes:ByteArray = decodeToByteArray(data);
- // Convert to string and return
- return bytes.readUTFBytes(bytes.length);
- }
- public static function decodeToByteArray(data:String):ByteArray {
- // Initialise output ByteArray for decoded data
- var output:ByteArray = new ByteArray();
- // Create data and output buffers
- var dataBuffer:Array = new Array(4);
- var outputBuffer:Array = new Array(3);
- // While there are data bytes left to be processed
- for (var i:uint = 0; i < data.length; i += 4) {
- // Populate data buffer with position of Base64 characters for
- // next 4 bytes from encoded data
- for (var j:uint = 0; j < 4 && i + j < data.length; j++) {
- dataBuffer[j] = BASE64_CHARS.indexOf(data.charAt(i + j));
- }
- // Decode data buffer back into bytes
- outputBuffer[0] = (dataBuffer[0] << 2) + ((dataBuffer[1] & 0x30) >> 4);
- outputBuffer[1] = ((dataBuffer[1] & 0x0f) << 4) + ((dataBuffer[2] & 0x3c) >> 2);
- outputBuffer[2] = ((dataBuffer[2] & 0x03) << 6) + dataBuffer[3];
- // Add all non-padded bytes in output buffer to decoded data
- for (var k:uint = 0; k < outputBuffer.length; k++) {
- if (dataBuffer[k+1] == 64) break;
- output.writeByte(outputBuffer[k]);
- }
- }
- // Rewind decoded data ByteArray
- output.position = 0;
- // Return decoded data
- return output;
- }
- public function Base64() {
- throw new Error("Base64 class is static container only");
- }
- }
- }
C#
方法一:自己寫實現過程
- /// <summary>
- /// Base64加密
- /// </summary>
- /// <param name="Message"></param>
- /// <returns></returns>
- public string Base64Code(string Message)
- {
- char[] Base64Code = new char[]{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
- 'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
- 'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7',
- '8','9','+','/','='};
- byte empty = (byte)0;
- System.Collections.ArrayList byteMessage = new System.Collections.ArrayList(System.Text.Encoding.Default.GetBytes(Message));
- System.Text.StringBuilder outmessage;
- int messageLen = byteMessage.Count;
- //將字符分成3個字節一組,如果不足,則以0補齊
- int page = messageLen / 3;
- int use = 0;
- if ((use = messageLen % 3) > 0)
- {
- for (int i = 0; i < 3 - use; i++)
- byteMessage.Add(empty);
- page++;
- }
- //將3個字節的每組字符轉換成4個字節一組的。3個一組,一組一組變成4個字節一組
- //方法是:轉換成ASCII碼,按順序排列24 位數據,再把這24位數據分成4組,即每組6位。再在每組的的最高位前補兩個0湊足一個字節。
- outmessage = new System.Text.StringBuilder(page * 4);
- for (int i = 0; i < page; i++)
- {
- //取一組3個字節的組
- byte[] instr = new byte[3];
- instr[0] = (byte)byteMessage[i * 3];
- instr[1] = (byte)byteMessage[i * 3 + 1];
- instr[2] = (byte)byteMessage[i * 3 + 2];
- //六個位爲一組,補0變成4個字節
- int[] outstr = new int[4];
- //第一個輸出字節:取第一輸入字節的前6位,並且在高位補0,使其變成8位(一個字節)
- outstr[0] = instr[0] >> 2;
- //第二個輸出字節:取第一輸入字節的後2位和第二個輸入字節的前4位(共6位),並且在高位補0,使其變成8位(一個字節)
- outstr[1] = ((instr[0] & 0x03) << 4) ^ (instr[1] >> 4);
- //第三個輸出字節:取第二輸入字節的後4位和第三個輸入字節的前2位(共6位),並且在高位補0,使其變成8位(一個字節)
- if (!instr[1].Equals(empty))
- outstr[2] = ((instr[1] & 0x0f) << 2) ^ (instr[2] >> 6);
- else
- outstr[2] = 64;
- //第四個輸出字節:取第三輸入字節的後6位,並且在高位補0,使其變成8位(一個字節)
- if (!instr[2].Equals(empty))
- outstr[3] = (instr[2] & 0x3f);
- else
- outstr[3] = 64;
- outmessage.Append(Base64Code[outstr[0]]);
- outmessage.Append(Base64Code[outstr[1]]);
- outmessage.Append(Base64Code[outstr[2]]);
- outmessage.Append(Base64Code[outstr[3]]);
- }
- return outmessage.ToString();
- }
- /// <summary>
- /// Base64解密
- /// </summary>
- /// <param name="Message"></param>
- /// <returns></returns>
- public string Base64Decode(string Message)
- {
- if ((Message.Length % 4) != 0)
- {
- throw new ArgumentException("不是正確的BASE64編碼,請檢查。", "Message");
- }
- if (!System.Text.RegularExpressions.Regex.IsMatch(Message, "^[A-Z0-9/+=]*$", System.Text.RegularExpressions.RegexOptions.IgnoreCase))
- {
- throw new ArgumentException("包含不正確的BASE64編碼,請檢查。", "Message");
- }
- string Base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- int page = Message.Length / 4;
- System.Collections.ArrayList outMessage = new System.Collections.ArrayList(page * 3);
- char[] message = Message.ToCharArray();
- for (int i = 0; i < page; i++)
- {
- byte[] instr = new byte[4];
- instr[0] = (byte)Base64Code.IndexOf(message[i * 4]);
- instr[1] = (byte)Base64Code.IndexOf(message[i * 4 + 1]);
- instr[2] = (byte)Base64Code.IndexOf(message[i * 4 + 2]);
- instr[3] = (byte)Base64Code.IndexOf(message[i * 4 + 3]);
- byte[] outstr = new byte[3];
- outstr[0] = (byte)((instr[0] << 2) ^ ((instr[1] & 0x30) >> 4));
- if (instr[2] != 64)
- {
- outstr[1] = (byte)((instr[1] << 4) ^ ((instr[2] & 0x3c) >> 2));
- }
- else
- {
- outstr[2] = 0;
- }
- if (instr[3] != 64)
- {
- outstr[2] = (byte)((instr[2] << 6) ^ instr[3]);
- }
- else
- {
- outstr[2] = 0;
- }
- outMessage.Add(outstr[0]);
- if (outstr[1] != 0)
- outMessage.Add(outstr[1]);
- if (outstr[2] != 0)
- outMessage.Add(outstr[2]);
- }
- byte[] outbyte = (byte[])outMessage.ToArray(Type.GetType("System.Byte"));
- return System.Text.Encoding.Default.GetString(outbyte);
- }
方法二:直接調用。net中的類庫
- /// <summary>
- /// Base64加密
- /// </summary>
- /// <param name="Message"></param>
- /// <returns></returns>
- public string Base64Code(string Message)
- {
- byte[] bytes = Encoding.Default.GetBytes(Message);
- return Convert.ToBase64String(bytes);
- }
- /// <summary>
- /// Base64解密
- /// </summary>
- /// <param name="Message"></param>
- /// <returns></returns>
- public string Base64Decode(string Message)
- {
- byte[] bytes = Convert.FromBase64String(Message);
- return Encoding.Default.GetString(bytes);
- }
轉自CSDN:
shenggaofei的博客
地
地址:https://blog.csdn.net/shenggaofei/article/details/52333687