更新時(shí)間:2022-08-10 來源:黑馬程序員 瀏覽量:
一、前言
一個(gè)信息系統(tǒng)缺少不了信息安全模塊,今天就帶著大家全面了解并學(xué)習(xí)一下信息安全中的密碼學(xué)知識,本文將會(huì)通過案例展示讓你了解抽象的密碼學(xué)知識,閱讀本文你將會(huì)有如下收獲:
+ 熟悉現(xiàn)代密碼學(xué)體系包含的主流密碼技術(shù)
+ 掌握Base64和Hex編碼技術(shù)的特性與使用案例
+ 掌握對稱密碼和非對稱密碼的特性與使用案例
+ 掌握混合密碼系統(tǒng)和隨機(jī)數(shù)的特征與使用案例
二、關(guān)于密碼
提到密碼,你的第一印象是什么?我們平時(shí)登錄微信、郵箱都需要輸入用戶名和密碼,或者用手機(jī)支付也需要輸入支付密碼,大部分人想到的可能就是這些情形中涉及到的密碼。然而本文即將討論的密碼與此密碼完全是不同的概念。實(shí)際上無論是微信還是支付寶或者其他系統(tǒng)要求輸入的密碼都只是一種身份驗(yàn)證的憑證,也就正確的密碼是可以證明你是這個(gè)賬號的主人的證據(jù)。這種密碼準(zhǔn)確來講叫做口令比較合適,對應(yīng)英文中的password、pin。
本文中提到的密碼是什么呢?實(shí)際上,密碼(cryptography)是一個(gè)極其龐大復(fù)雜的信息處理體系,涉及到信息的機(jī)密性、完整性、認(rèn)證、不可否認(rèn)性等眾多方面,由此衍生出的很多保護(hù)我們信息安全的技術(shù),這些技術(shù)我們一般統(tǒng)稱為密碼技術(shù)。密碼技術(shù)是密碼學(xué)的核心。
數(shù)學(xué)與密碼技術(shù)的關(guān)系:數(shù)學(xué)是密碼技術(shù)的基礎(chǔ),復(fù)雜的密碼技術(shù)往往都會(huì)涉及到復(fù)雜的數(shù)學(xué)公式。
密碼學(xué):密碼學(xué)是網(wǎng)絡(luò)安全、信息安全、區(qū)塊鏈等領(lǐng)域的基礎(chǔ),常見的對稱密碼、公鑰密鑰、散列函數(shù)等,都屬于密碼學(xué)范疇。密碼學(xué)中的密碼技術(shù)比如“密碼”可以讓竊聽者無法解讀竊取的信息,“單項(xiàng)散列函數(shù)”可以檢測出消息是否被篡改,“數(shù)字簽名”可以確定消息是否來源于合法的發(fā)送者。
三、信息安全
概念
信息安全是指信息網(wǎng)絡(luò)的硬件、軟件及其系統(tǒng)中的數(shù)據(jù)受到保護(hù),不受偶然的或者惡意的原因而遭到破壞 、 更改 、泄露、否認(rèn)等,系統(tǒng)連續(xù)可靠正常地運(yùn)行,信息服務(wù)不中斷。 信息安全安全是建立在以密碼技術(shù)為基礎(chǔ)的計(jì)算機(jī)安全領(lǐng)域,輔以通信技術(shù)、計(jì)算機(jī)技術(shù)與網(wǎng)絡(luò)技術(shù)等方面的內(nèi)容。
2. 與密碼學(xué)的關(guān)系
+ 密碼學(xué)是保障信息安全的核心技術(shù) ,但不是提供信息安全的唯一方式 。
+ 信息安全是密碼學(xué)研究與發(fā)展的目的 。
+ 信息安全的理論基礎(chǔ)是密碼學(xué),信息安全的問題根本解決往往依靠密碼學(xué)理論 。
3. 密碼學(xué)與信息安全常識
+ 不要使用保密的密碼算法
+ 使用低強(qiáng)度的密碼比不進(jìn)行加密更危險(xiǎn)
+ 任何密碼總有一天會(huì)被破解
+ 密碼只是信息安全的一部分
四、現(xiàn)代密碼學(xué)體系
信息安全及密碼學(xué)技術(shù),是整個(gè)信息技術(shù)的基石。在西方語文中,密碼學(xué)一詞源于希臘語,krypto意思是隱藏,graphene是書寫的意思。密碼學(xué)的發(fā)展總共經(jīng)歷了四個(gè)階段:遠(yuǎn)古密碼、古典密碼、近代密碼和現(xiàn)代密碼,這四個(gè)階段的發(fā)展歷史詳細(xì)介紹可參見文章最后的附錄部分,接下來本文內(nèi)容主要介紹的是現(xiàn)代密碼學(xué)所涉及到的密碼知識。
1. 信息安全威脅與密碼技術(shù)
該圖完整的展示了信息安全面臨的威脅與解決方案中會(huì)用到的密碼技術(shù),本文側(cè)重于介紹有關(guān)于保證數(shù)據(jù)機(jī)密性的密碼技術(shù)。
2. 密碼算法及重要概念
將明文通過處理變換為密文的規(guī)則稱為加密算法,將密文恢復(fù)成明文的規(guī)則稱為解密算法,加密解密一起稱為密碼算法。
+ 明文 (Plaintext): 信息的原始數(shù)據(jù)
+ 密文(Ciphertext):明文經(jīng)過編碼變換所生成的數(shù)據(jù)
+ 加密(Encryption):對明文進(jìn)行編碼變換生成密文的過程
+ 解密(Decryption):將密文恢復(fù)成明文的過程
+ 密鑰:密碼算法需要用到密鑰的,密鑰就相當(dāng)于保險(xiǎn)庫大門的鑰匙,重要性不言而喻,所以切記不要泄露密碼的密鑰。 密鑰 (Key):控制明文與密文之間相互變換的,分為加密密鑰和解密密鑰。
3. ASCII編碼
**ASCII碼** 是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng),并等同于國際標(biāo)準(zhǔn)ISO/IEC 646 。在這個(gè)頁面,你可以找到8位的256個(gè)字符、ASCII碼表和Windows-1252 (code page 1252,它是國際標(biāo)準(zhǔn)ISO 8859-1的一個(gè)擴(kuò)展字符集) 標(biāo)準(zhǔn)保持一致;
**ASCII碼** 是 **A**merican **S**tandard **C**ode for **I**nformation **I**nterchange 的縮寫,而不是ASCⅡ(羅馬數(shù)字2),有很多人在這個(gè)地方產(chǎn)生誤解;
**ASCII碼** 規(guī)范于1967年第一次發(fā)布,最后一次更新是在1986年,它包含了33個(gè)控制字符(具有某些特殊功能但是無法顯示的字符)和95個(gè)可顯示字符;
ASCII碼大致可以分作三部分組成。
第一部分是:ASCII非打印控制字符
第二部分是:ASCII打印字符
第三部分是:擴(kuò)展ASCII打印字符
3.1 第一部分:ASCII非打印控制字符表
ASCII表上的數(shù)字0–31分配給了控制字符,用于控制像打印機(jī)等一些外圍設(shè)備。例如,12代表換頁/新頁功能。此命令指示打印機(jī)跳到下一頁的開頭。(參詳ASCII碼表中0-31)
3.2 第二部分:ASCII打印字符
數(shù)字 32–126 分配給了能在鍵盤上找到的字符,當(dāng)您查看或打印文檔時(shí)就會(huì)出現(xiàn)。數(shù)字127代表 DELETE 命令。(參詳ASCII碼表中32-127)
3.3 第三部分:擴(kuò)展ASCII打印字符
擴(kuò)展的ASCII字符滿足了對更多字符的需求。擴(kuò)展的ASCII包含ASCII中已有的128個(gè)字符(數(shù)字0–32顯示在下圖中),又增加了128個(gè)字符,總共是256個(gè)。即使有了這些更多的字符,許多語言還是包含無法壓縮到256個(gè)字符中的符號。因此,出現(xiàn)了一些ASCII的變體來囊括地區(qū)性字符和符號。例如,許多軟件程序把ASCII表(又稱作ISO8859-1)用于北美、西歐、澳大利亞和非洲的語言。
4. 字符串的ASCII碼與二進(jìn)制位
``````java public class ASCIITest { @Test public void test01() { String str = "heima"; byte[] bytes = str.getBytes(); for (byte b : bytes) { //打印ascii碼 System.out.println(b); //獲取二進(jìn)制位 String s = Integer.toBinaryString(b); System.out.println(s); } } @Test public void test02() throws UnsupportedEncodingException { String str = "黑馬"; //中文UTF-8編碼一個(gè)漢字占3個(gè)字節(jié),中文GBK編碼一個(gè)漢字占2個(gè)字節(jié)。 byte[] bytes = str.getBytes("UTF-8"); System.out.println("字節(jié)個(gè)數(shù):"+ bytes.length); char[] chars = str.toCharArray(); for (char c : chars) { //打印字符 System.out.println(c); //字符類型會(huì)自動(dòng)提升為int類型,獲取二進(jìn)制值(10進(jìn)制轉(zhuǎn)二進(jìn)制) String s = Integer.toBinaryString(c); System.out.println(s); } } } ``````
5.1 Hex編碼
1字節(jié)=8位2進(jìn)制,比如小寫字母a,ASCII表對應(yīng)十進(jìn)制為97,二進(jìn)制表示為01100001
1字節(jié)=2位16進(jìn)制,比如小寫字母a,ASCII表對應(yīng)十進(jìn)制為97, 十六進(jìn)制表示為61
+ 因?yàn)橐粋€(gè)字節(jié)中存在8個(gè) bit可以表示256個(gè)字符,而非擴(kuò)展 ASCII 碼只能表示0-127種字符,為了能完整地表示一個(gè)字節(jié),可以將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制數(shù)據(jù)的方式來實(shí)現(xiàn)。所以 Hex 編碼也被稱作為 Base16 編碼,相比于原先8位表示一個(gè)字節(jié),Hex 編碼能夠只用2位表示一個(gè)字節(jié)。Hex 編碼最常用于二進(jìn)制文件查看時(shí)展示的編碼,如010Editor 就可以支持查看二進(jìn)制文件。
+ 使用16個(gè)可見字符來表示一個(gè)二進(jìn)制數(shù)組,編碼后數(shù)據(jù)大小將x2
+ 1個(gè)字符需要用2個(gè)可見字符來表示
##### 5.1.1 代碼示例
引入依賴
``````xml <dependencies> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency> </dependencies>
``````
單元測試:
```````java public class HexDemoTest { @Test public void test01() { String data = "itcast" ; byte[] bytes = data.getBytes() ; //測試hex String encoded = Hex.encodeHexString(bytes) ; System.out.println(encoded); } }
```````
5.2 base64編碼
+ Base64編碼要求把3個(gè)8位字節(jié)(3乘8=24)轉(zhuǎn)化為4個(gè)6位的字節(jié)(4乘6=24),之后在6位的前面補(bǔ)兩個(gè)0,形成8位一個(gè)字節(jié)的形式。 如果剩下的字符不足3個(gè)字節(jié),則用0填充,輸出字符使用'=',因此編碼后輸出的文本末尾可能會(huì)出現(xiàn)1或2個(gè)'='。為了保證所輸出的編碼位可讀字符,Base64制定了一個(gè)編碼表,以便進(jìn)行統(tǒng)一轉(zhuǎn)換。編碼表的大小為2^6=64,這也是Base64名稱的由來。標(biāo)準(zhǔn)base64只有64個(gè)字符(大寫A到Z、小寫a到z、數(shù)字0到9、“+”和“/”)以及用作后綴等號;
+ Base64是網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)碼的可讀性編碼算法之一
+ 以每 3 個(gè) 字符(1Byte=8bit)為一組,然后針對每組,首先獲取每個(gè)字符的 ASCII 編碼(字符'a'=97=01100001),然后將 ASCII 編碼轉(zhuǎn)換成 8 bit 的二進(jìn)制,得到一組 3 * 8=24 bit 的字節(jié)。然后再將這 24 bit 劃分為 4 個(gè) 6 bit 的字節(jié),并在每個(gè) 6 bit 的字節(jié)前面都填兩個(gè)高位 0,得到 4 個(gè) 8 bit 的字節(jié),然后將這 4 個(gè) 8 bit 的字節(jié)轉(zhuǎn)換成十進(jìn)制,對照 BASE64 編碼表 (下表),得到對應(yīng)編碼后的字符。
+ 使用64個(gè)可見字符來表示一個(gè)二進(jìn)制數(shù)組,編碼后數(shù)據(jù)大小變成原來的4/3
+ 3個(gè)字符用4個(gè)可見字符來表示
5.2.1 原理示例1-足夠三字節(jié)
+ 第一步:"jay"、“a”、"n"對應(yīng)的ASCII碼值分別為106,97,121,對應(yīng)的二進(jìn)制值是01101010、01100001、01111001。如圖第二三行所示,由此組成一個(gè)24位的二進(jìn)制字符串。
+ 第二步:如圖第四行,將24位每6位二進(jìn)制位一組分成四組。
+ 第三步:在上面每一組前面補(bǔ)兩個(gè)0(紅色背景),擴(kuò)展成32個(gè)二進(jìn)制位,此時(shí)變?yōu)樗膫€(gè)字節(jié):00011010、00100110、00000101、00111001。分別對應(yīng)的值(Base64編碼索引)為:26、38、5、57。
+ 第四步:用上面的值在Base64編碼表中進(jìn)行查找,分別對應(yīng):a、m、F、5。因此“jay”Base64編碼之后就變?yōu)椋篴mF5。
5.2.2 代碼示例1-足夠三字節(jié)
``````java public class Base64DemoTest { @Test public void test01() { //jay正好三個(gè)字節(jié),編碼后輸出的結(jié)果沒有= System.out.println(Base64.encodeBase64String("jay".getBytes())); } }
``````
5.2.3 原理示例2-不夠三字節(jié)
如果字節(jié)不足三個(gè)怎么辦,分組的時(shí)候不組8位的都補(bǔ)0,計(jì)算沒結(jié)果的=號代替
5.2.4 代碼示例2-不夠三字節(jié)
單元測試:
``````java public class Base64Demo { @Test public void test02() { //ja不夠三個(gè)字節(jié),編碼后一定會(huì)有= System.out.println(Base64.encodeBase64String("ja".getBytes())); } }
``````
5.3 代碼示例-編碼與解碼
單元測試:
``````java /** * hex編碼與base64編碼測試 */ public class HexAndBase64Test { @Test public void test() throws DecoderException { String data = "黑馬程序員" ; byte[] bytes = data.getBytes() ; //測試hex String encryStr = Hex.encodeHexString(bytes) ; String decryStr = new String(Hex.decodeHex(encryStr.toCharArray())) ; System.out.println("Hex編碼解碼:"+ encryStr + " | " + decryStr) ; //測試base64 encryStr = Base64.encodeBase64String(bytes) ; decryStr = new String(Base64.decodeBase64(encryStr.getBytes()) ); System.out.println("Base64編碼解碼:"+ encryStr + " | " + decryStr) ; } }
``````
上面我們已經(jīng)看到了Base64就是用6位(2的6次冪就是64)表示字符,因此成為Base64。同理,Base32就是用5位,Base16就是用4位。
對比:hex編碼速度快,體積大;base64編碼速度慢,體積小
6. 密碼分類
6.1 對稱密碼
加密密鑰和解密密鑰相同,又稱傳統(tǒng)密碼體制、共享密鑰密碼體制、秘密密鑰體制或單密鑰體制。從密鑰使用方式上分為分組密碼和序列密碼 ,這點(diǎn)后文會(huì)有介紹。
對稱加密算法的優(yōu)點(diǎn):算法公開、計(jì)算量小、加密速度快、加密效率高。
對稱加密算法的缺點(diǎn):交易雙方都使用同樣鑰匙,安全性得不到保證。此外,每對用戶每次使用對稱加密算法時(shí),都需要使用其他人不知道的惟一鑰匙,這會(huì)使得發(fā)收信雙方所擁有的鑰匙數(shù)量呈幾何級數(shù)增長,密鑰管理成為用戶的負(fù)擔(dān)。對稱加密算法在分布式網(wǎng)絡(luò)系統(tǒng)上使用較為困難,主要是因?yàn)槊荑€管理困難,使用成本較高。
對稱加密通常使用的是相對較小的密鑰,一般小于256 bit。因?yàn)槊荑€越大,加密越強(qiáng),但加密與解密的過程越慢。如果你只用1 bit來做這個(gè)密鑰,那黑客們可以先試著用0來解密,不行的話就再用1解;但如果你的密鑰有1 MB大,黑客們可能永遠(yuǎn)也無法破解,但加密和解密的過程要花費(fèi)很長的時(shí)間。密鑰的大小既要照顧到安全性,也要照顧到效率,是一個(gè)trade-off。
常用對稱加密算法
1. DES(Data Encryption Standard):數(shù)據(jù)加密標(biāo)準(zhǔn),速度較快,適用于加密大量數(shù)據(jù)的場合。
2. 3DES(Triple DES):是基于DES,對一塊數(shù)據(jù)用三個(gè)不同的密鑰進(jìn)行三次加密,強(qiáng)度更高。
3. AES(Advanced Encryption Standard):高級加密標(biāo)準(zhǔn),是下一代的加密算法標(biāo)準(zhǔn),速度快,安全級別高,支持128、192、256、512位密鑰的加密。
算法特征
1. 加密方和解密方使用同一個(gè)密鑰,一旦密鑰文件泄漏, 就會(huì)導(dǎo)致數(shù)據(jù)暴露
2. 加密解密的速度比較快,適合數(shù)據(jù)比較長時(shí)的使用,可以加密大文件
3. 密鑰傳輸?shù)倪^程不安全,且容易被破解,密鑰管理也比較麻煩。
4. 加密后編碼表找不到對應(yīng)字符, 出現(xiàn)亂碼
5. 一般結(jié)合Base64使用
6.1.1 DES
+ DES是1997年美國聯(lián)邦信息處理標(biāo)準(zhǔn)中所采用的一種對稱密碼算法,一直以來被美國以及其他國家的政府和銀行等廣泛采用。隨著計(jì)算機(jī)的快速發(fā)展,DES已經(jīng)被暴力破解,1997年用時(shí)96天破譯密鑰,1998年41天破譯密鑰,到了1999年只用22小時(shí)15分鐘就可以破譯。
+ DES技術(shù)是一種將64比特的明文加密成64比特的密文的對稱密碼算法,因此理論上來講,他的密鑰長度也是64位,但因?yàn)樵贒ES的密鑰中每隔7比特,就會(huì)設(shè)置一個(gè)用于錯(cuò)誤檢查的比特,所以實(shí)際上DES的密鑰的長度只有56比特。
+ DES是以64比特的明文(比特序列)為一個(gè)單位進(jìn)行加密,這64比特的單位成為分組,一般來說,以分組為單位進(jìn)行處理的密碼算法稱為分組密碼。
+ DES每次每次只能加密64比特的數(shù)據(jù),如果要加密的明文比較長,就需要對DES加密進(jìn)行迭代(反復(fù)),而迭代的具體方案就稱為模式。
> Java中有關(guān)對稱和非對稱加密的核心類:javax.crypto.Cipher
代碼示例
``````java /** * DES加密算法測試 */ public class DesTest { /** * 測試DES加密 */ @Test public void testEncrypt() throws Exception { //明文 String text = "黑馬程序員"; //密鑰,長度必須為8個(gè)字節(jié)(字符) byte[] secretKeyBytes = "12345678".getBytes(); //secretKeyBytes = generateSecretKey("DES", 56); // Cipher:獲取密碼對象,參數(shù)按"算法/模式/填充模式" Cipher cipher = Cipher.getInstance("DES"); // 參數(shù)1:密鑰,key的字節(jié)數(shù)組,參數(shù)2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DES"); //加密對象初始化數(shù)據(jù),參數(shù)1:模式,有加密模式和解密模式,參數(shù)2:密鑰規(guī)則 cipher.init(Cipher.ENCRYPT_MODE,sks); //執(zhí)行加密,得到加密結(jié)果 byte[] bytes = cipher.doFinal(text.getBytes()); //輸出字節(jié),因?yàn)閍scii碼有負(fù)數(shù),解析不出來,所以亂碼 //將byte數(shù)組轉(zhuǎn)成ASCII編碼,必須確保byte數(shù)組的值在ASCII的可視字符范圍,否則會(huì)出現(xiàn)亂碼, //因?yàn)锳SCII的取值范圍比byte小,byte的取值范圍是-128到127 for (byte b : bytes) { System.out.println(b); } // 打印密文 System.out.println(new String(bytes)); //將byte數(shù)組轉(zhuǎn)成Base64編碼。 String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } /** * 測試DES解密 */ @Test public void testDecrypt() throws Exception { //密文 String crpyt = "+rBmhkThnKQf8IJTM/qmMA=="; //密鑰,長度必須為8個(gè)字節(jié)(字符) byte[] secretKeyBytes = "12345678".getBytes(); //獲取Cipher對象 Cipher cipher = Cipher.getInstance("DES"); // 指定密鑰規(guī)則 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DES"); cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面使用的base64編碼,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 因?yàn)槭敲魑?,所以直接返? String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } /** * 生成密鑰 * @param algorithm 算法 * @param len 密鑰長度 */ public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密鑰生成器 keyGenerator.init(len);//密鑰長度 SecretKey secretKey = keyGenerator.generateKey();//生成密鑰 return secretKey.getEncoded(); //密鑰字節(jié)數(shù)組轉(zhuǎn)字符串 } }
``````
6.1.2 3DES
+ 三重DES,是為了加強(qiáng)DES的強(qiáng)度,將DES重復(fù)3次所得到的一種密碼算法。明文需經(jīng)過3次DES處理才能得到最后密文,由于DES密鑰實(shí)際長度為56比特,因此3DES的密鑰密鑰實(shí)際長度就是56*3=168比特。通過增加迭代次數(shù)提高安全性,常應(yīng)用在銀行等金融機(jī)構(gòu)。
+ DES密鑰長度是8字節(jié)(64比特),3DES密鑰長度是24字節(jié)(192比特)
+ 三重DES不是進(jìn)行三次DES加密(加密-加密-加密),而是加密-解密-加密的過程。
+ 加密過程:用第一支密鑰對原文進(jìn)行加密,再使用第二支密鑰對第一步操作后的信息進(jìn)行解密,最后使用第三支密鑰對第二步操作后的信息進(jìn)行加密得到最終密文。
解密過程:用第三支密鑰對密文進(jìn)行解密,再采用第二支密鑰進(jìn)行加密,最后采用第一支密鑰解密得到原文。
+ 三重DES中所有密鑰都相同時(shí),三重DES等同于普通DES,因?yàn)榍皟刹郊用芙饷芎蟮玫降氖窃瓉淼拿魑摹?br/>
+ EDE:表示加密(Encryption)-> 解密(Decryption)->加密(Encryption)這個(gè)流程。
+ 缺點(diǎn):處理速度較慢、密鑰計(jì)算時(shí)間較長、加密效率不高。
``````java /** * 3DES加密算法測試 */ public class Des3Test { /** * 測試3DES加密 */ @Test public void testEncrypt() throws Exception { //明文 String text = "黑馬程序員"; //密鑰,長度必須24個(gè)字節(jié)(字符) byte[] secretKeyBytes = "123456781234567812345678".getBytes(); //可指定密鑰實(shí)際長度是168 //secretKeyBytes = generateSecretKey("DESede", 168); // Cipher:獲取密碼對象,參數(shù)按"算法/模式/填充模式" Cipher cipher = Cipher.getInstance("DESede"); // 參數(shù)1:密鑰,key的字節(jié)數(shù)組,參數(shù)2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DESede"); //加密對象初始化數(shù)據(jù),參數(shù)1:模式,有加密模式和解密模式,參數(shù)2:密鑰規(guī)則 cipher.init(Cipher.ENCRYPT_MODE,sks); //執(zhí)行加密,得到加密結(jié)果 byte[] bytes = cipher.doFinal(text.getBytes()); //將byte數(shù)組轉(zhuǎn)成Base64編碼。 String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } /** * 測試3DES解密 */ @Test public void testDecrypt() throws Exception { //密文 String crpyt = "+rBmhkThnKQf8IJTM/qmMA=="; //密鑰,長度必須24個(gè)字節(jié)(字符) byte[] secretKeyBytes = "123456781234567812345678".getBytes(); //獲取Cipher對象 Cipher cipher = Cipher.getInstance("DESede"); // 指定密鑰規(guī)則 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DESede"); cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面使用的base64編碼,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 因?yàn)槭敲魑?,所以直接返? String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } /** * 生成密鑰 * @param algorithm 算法 * @param len 密鑰長度 */ public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密鑰生成器 keyGenerator.init(len);//密鑰長度 SecretKey secretKey = keyGenerator.generateKey();//生成密鑰 return secretKey.getEncoded(); //密鑰字節(jié)數(shù)組轉(zhuǎn)字符串 } }
6.1.3 AES
+ AES(Advanced Encryption Standard)是取代其前任標(biāo)準(zhǔn)(DES)而稱為新標(biāo)準(zhǔn)的一種對稱算法。
+ AES分組長度為128比特,密鑰長度有128、192、256比特三種,AES-128、AES192和AES-256。
+ 至今還沒有有效破解AES的方式
還是之前的代碼,替換密鑰值和加密算法即可
``````java /** * AES加密算法測試 */ public class AesTest { /** * 測試AES加密 */ @Test public void testEncrypt() throws Exception { //明文 String text = "黑馬程序員"; //密鑰,長度必須為16個(gè)字節(jié)(字符) byte[] secretKeyBytes = "1234567812345678".getBytes(); //密鑰實(shí)際長度128比特 //secretKeyBytes = generateSecretKey("AES", 128); // Cipher:獲取密碼對象,參數(shù)按"算法/模式/填充模式" Cipher cipher = Cipher.getInstance("AES"); // 參數(shù)1:密鑰,key的字節(jié)數(shù)組,參數(shù)2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "AES"); //加密對象初始化數(shù)據(jù),參數(shù)1:模式,有加密模式和解密模式,參數(shù)2:密鑰規(guī)則 cipher.init(Cipher.ENCRYPT_MODE,sks); //執(zhí)行加密,得到加密結(jié)果 byte[] bytes = cipher.doFinal(text.getBytes()); //將byte數(shù)組轉(zhuǎn)成Base64編碼。 String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } /** * 測試AES解密 */ @Test public void testDecrypt() throws Exception { //密文 String crpyt = "j9qMqmunoPEtMRpNYPWfCw=="; //密鑰,長度必須為16個(gè)字節(jié)(字符) byte[] secretKeyBytes = "1234567812345678".getBytes(); //獲取Cipher對象 Cipher cipher = Cipher.getInstance("AES"); //指定密鑰規(guī)則 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "AES"); cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面使用的base64編碼,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); //因?yàn)槭敲魑?,所以直接返? String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } /** * 生成密鑰 * @param algorithm 算法 * @param len 密鑰長度 */ public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密鑰生成器 keyGenerator.init(len);//密鑰長度 SecretKey secretKey = keyGenerator.generateKey();//生成密鑰 return secretKey.getEncoded(); //密鑰字節(jié)數(shù)組轉(zhuǎn)字符串 } } ``````
6.1.4 破解AES的難度
據(jù)統(tǒng)計(jì),完全破解要花費(fèi)時(shí)長為2104億年,消耗電量1.1201 * 10^22 kWh,電費(fèi)1.368 * 10^13 億美元
6.1.5 選用哪一種?
DES已被破解不要再使用,3DES在部分金融機(jī)構(gòu)內(nèi)還有在使用將來會(huì)被AES取代,推薦使用AES。
6.2 分組密碼
6.2.1 概念
按對明文的處理方式,密碼算法可以分為分組密碼( Blok cipher)和流密碼(Stream cipher)。
6.2.2 分組密碼:**也叫塊加密(block cyphers),每次只能處理特定長度的一塊數(shù)據(jù)的密碼算法,“一塊”稱為分組,一個(gè)分組的比特?cái)?shù)就是分組長度。一次加密明文中的一個(gè)塊,將明文按一定的位長分組,明文組經(jīng)過加密運(yùn)算得到密文組,密文組經(jīng)過解密運(yùn)算(加密運(yùn)算的逆運(yùn)算),還原成明文組。比如:DES和3DES的分組長度都是64比特,一次性只能加密64比特的明文并生成64比特的密文。
6.2.3 序列密碼**:也叫流加密(stream cyphers),對數(shù)據(jù)流進(jìn)行連續(xù)處理的密碼算法,是指利用少量的密鑰(制亂元素)通過某種復(fù)雜的運(yùn)算(密碼算法)產(chǎn)生大量的偽隨機(jī)位流,用于對明文位流的加密。解密是指用同樣的密鑰和密碼算法及與加密相同的偽隨機(jī)位流,用以還原明文位流。流密碼中一般以1比特、8比特或32比特等為單位進(jìn)行加解密。
6.2.4 對比:**分組密碼處理一個(gè)分組就結(jié)束,無需通過內(nèi)部狀態(tài)記錄加密進(jìn)度;流密碼是對一串?dāng)?shù)據(jù)流進(jìn)行連續(xù)處理,需要保持內(nèi)部狀態(tài)。
前文所提到的DES、3DES、AES等大部分對稱加密算法都屬于分組密碼。流密碼的典型例子有一次性密碼本。
> 本文內(nèi)容主要講解的是分組密碼。
6.2.2 加密模式
分組算法只能加密固定長度的分組,但有時(shí)加密的明文長度會(huì)超過分組密碼的分組長度,此時(shí)就需要對分組密碼進(jìn)行迭代,以便將一段很長的明文全部加密。迭代的方法就稱為分組密碼的加密模式(model)。
加密模式的種類:常見的有ECB模式(電子密碼本模式)、CBC模式(密碼分組鏈接模式)、CTR模式(計(jì)數(shù)器模式)等,本課中重點(diǎn)說明ECB模式和CBC模式。
6.2.3 明文分組與密文分組
明文分組: 分組密碼算法中作為加密對象的明文。明文分組的長度與分組密碼算法的分組長度相等。
密文分組:分組加密算法中對明文分組加密之后產(chǎn)生的密文。