首頁技術(shù)文章正文

Java培訓(xùn):看懂這篇文章-你就懂了信息安全的密碼學(xué)

更新時(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ā)送者。

  三、信息安全

  1. 概念

  
       信息安全是指信息網(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ù)

  

1660101932919_1.jpg

  該圖完整的展示了信息安全面臨的威脅與解決方案中會(huì)用到的密碼技術(shù),本文側(cè)重于介紹有關(guān)于保證數(shù)據(jù)機(jī)密性的密碼技術(shù)。

  2. 密碼算法及重要概念

  將明文通過處理變換為密文的規(guī)則稱為加密算法,將密文恢復(fù)成明文的規(guī)則稱為解密算法,加密解密一起稱為密碼算法。

  

1660101964324_2.jpg

  + 明文 (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打印字符

  

1660102012124_3.jpg

  

1660102024874_4.jpg

  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

  

1660102090366_5.jpg

  + 因?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è)可見字符來表示

  

1660102306351_6.jpg

  5.2.1 原理示例1-足夠三字節(jié)

  

1660102332674_7.jpg

  + 第一步:"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é)果的=號代替

  

1660102449908_8.jpg

  
       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)生的密文。

1660103004042_9.jpg


分享到:
在線咨詢 我要報(bào)名
和我們在線交談!