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

Java培訓:看懂這篇文章-你就懂了信息安全的密碼學

更新時間:2022-08-10 來源:黑馬程序員 瀏覽量:

  一、前言

   一個信息系統(tǒng)缺少不了信息安全模塊,今天就帶著大家全面了解并學習一下信息安全中的密碼學知識,本文將會通過案例展示讓你了解抽象的密碼學知識,閱讀本文你將會有如下收獲:

  + 熟悉現(xiàn)代密碼學體系包含的主流密碼技術(shù)

  + 掌握Base64和Hex編碼技術(shù)的特性與使用案例

  + 掌握對稱密碼和非對稱密碼的特性與使用案例

  + 掌握混合密碼系統(tǒng)和隨機數(shù)的特征與使用案例

  二、關于密碼

  提到密碼,你的第一印象是什么?我們平時登錄微信、郵箱都需要輸入用戶名和密碼,或者用手機支付也需要輸入支付密碼,大部分人想到的可能就是這些情形中涉及到的密碼。然而本文即將討論的密碼與此密碼完全是不同的概念。實際上無論是微信還是支付寶或者其他系統(tǒng)要求輸入的密碼都只是一種身份驗證的憑證,也就正確的密碼是可以證明你是這個賬號的主人的證據(jù)。這種密碼準確來講叫做口令比較合適,對應英文中的password、pin。

  本文中提到的密碼是什么呢?實際上,密碼(cryptography)是一個極其龐大復雜的信息處理體系,涉及到信息的機密性、完整性、認證、不可否認性等眾多方面,由此衍生出的很多保護我們信息安全的技術(shù),這些技術(shù)我們一般統(tǒng)稱為密碼技術(shù)。密碼技術(shù)是密碼學的核心。

  數(shù)學與密碼技術(shù)的關系:數(shù)學是密碼技術(shù)的基礎,復雜的密碼技術(shù)往往都會涉及到復雜的數(shù)學公式。

  密碼學:密碼學是網(wǎng)絡安全、信息安全、區(qū)塊鏈等領域的基礎,常見的對稱密碼、公鑰密鑰、散列函數(shù)等,都屬于密碼學范疇。密碼學中的密碼技術(shù)比如“密碼”可以讓竊聽者無法解讀竊取的信息,“單項散列函數(shù)”可以檢測出消息是否被篡改,“數(shù)字簽名”可以確定消息是否來源于合法的發(fā)送者。

  三、信息安全

  1. 概念

  
       信息安全是指信息網(wǎng)絡的硬件、軟件及其系統(tǒng)中的數(shù)據(jù)受到保護,不受偶然的或者惡意的原因而遭到破壞 、 更改 、泄露、否認等,系統(tǒng)連續(xù)可靠正常地運行,信息服務不中斷。 信息安全安全是建立在以密碼技術(shù)為基礎的計算機安全領域,輔以通信技術(shù)、計算機技術(shù)與網(wǎng)絡技術(shù)等方面的內(nèi)容。

  2. 與密碼學的關系

  + 密碼學是保障信息安全的核心技術(shù) ,但不是提供信息安全的唯一方式 。

  + 信息安全是密碼學研究與發(fā)展的目的 。

  + 信息安全的理論基礎是密碼學,信息安全的問題根本解決往往依靠密碼學理論 。

  3. 密碼學與信息安全常識

  + 不要使用保密的密碼算法

  + 使用低強度的密碼比不進行加密更危險

  + 任何密碼總有一天會被破解

  + 密碼只是信息安全的一部分

  四、現(xiàn)代密碼學體系

  信息安全及密碼學技術(shù),是整個信息技術(shù)的基石。在西方語文中,密碼學一詞源于希臘語,krypto意思是隱藏,graphene是書寫的意思。密碼學的發(fā)展總共經(jīng)歷了四個階段:遠古密碼、古典密碼、近代密碼和現(xiàn)代密碼,這四個階段的發(fā)展歷史詳細介紹可參見文章最后的附錄部分,接下來本文內(nèi)容主要介紹的是現(xiàn)代密碼學所涉及到的密碼知識。

  1. 信息安全威脅與密碼技術(shù)

  

1660101932919_1.jpg

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

  2. 密碼算法及重要概念

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

  

1660101964324_2.jpg

  + 明文 (Plaintext): 信息的原始數(shù)據(jù)

  + 密文(Ciphertext):明文經(jīng)過編碼變換所生成的數(shù)據(jù)

  + 加密(Encryption):對明文進行編碼變換生成密文的過程

  + 解密(Decryption):將密文恢復成明文的過程

  + 密鑰:密碼算法需要用到密鑰的,密鑰就相當于保險庫大門的鑰匙,重要性不言而喻,所以切記不要泄露密碼的密鑰。 密鑰 (Key):控制明文與密文之間相互變換的,分為加密密鑰和解密密鑰。

  3. ASCII編碼

  **ASCII碼** 是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng),并等同于國際標準ISO/IEC 646 。在這個頁面,你可以找到8位的256個字符、ASCII碼表和Windows-1252 (code page 1252,它是國際標準ISO 8859-1的一個擴展字符集) 標準保持一致;

  **ASCII碼** 是 **A**merican **S**tandard **C**ode for **I**nformation **I**nterchange 的縮寫,而不是ASCⅡ(羅馬數(shù)字2),有很多人在這個地方產(chǎn)生誤解;

  **ASCII碼** 規(guī)范于1967年第一次發(fā)布,最后一次更新是在1986年,它包含了33個控制字符(具有某些特殊功能但是無法顯示的字符)和95個可顯示字符;

  ASCII碼大致可以分作三部分組成。

  第一部分是:ASCII非打印控制字符

  第二部分是:ASCII打印字符

  第三部分是:擴展ASCII打印字符

  

1660102012124_3.jpg

  

1660102024874_4.jpg

  3.1 第一部分:ASCII非打印控制字符表

  ASCII表上的數(shù)字0–31分配給了控制字符,用于控制像打印機等一些外圍設備。例如,12代表換頁/新頁功能。此命令指示打印機跳到下一頁的開頭。(參詳ASCII碼表中0-31)

  3.2 第二部分:ASCII打印字符

  數(shù)字 32–126 分配給了能在鍵盤上找到的字符,當您查看或打印文檔時就會出現(xiàn)。數(shù)字127代表 DELETE 命令。(參詳ASCII碼表中32-127)

  3.3 第三部分:擴展ASCII打印字符

  擴展的ASCII字符滿足了對更多字符的需求。擴展的ASCII包含ASCII中已有的128個字符(數(shù)字0–32顯示在下圖中),又增加了128個字符,總共是256個。即使有了這些更多的字符,許多語言還是包含無法壓縮到256個字符中的符號。因此,出現(xiàn)了一些ASCII的變體來囊括地區(qū)性字符和符號。例如,許多軟件程序把ASCII表(又稱作ISO8859-1)用于北美、西歐、澳大利亞和非洲的語言。

  4. 字符串的ASCII碼與二進制位

``````java
public class ASCIITest {

    @Test
    public void test01() {
        String str = "heima";
        byte[] bytes = str.getBytes();
        for (byte b : bytes) {
            //打印ascii碼
            System.out.println(b);

            //獲取二進制位
            String s = Integer.toBinaryString(b);
            System.out.println(s);
        }
    }
   
   
    @Test
    public void test02() throws UnsupportedEncodingException {
        String str = "黑馬"; //中文UTF-8編碼一個漢字占3個字節(jié),中文GBK編碼一個漢字占2個字節(jié)。
        byte[] bytes = str.getBytes("UTF-8");
        System.out.println("字節(jié)個數(shù):"+ bytes.length);
        char[] chars = str.toCharArray();

        for (char c : chars) {
            //打印字符
            System.out.println(c);
            //字符類型會自動提升為int類型,獲取二進制值(10進制轉(zhuǎn)二進制)
            String s = Integer.toBinaryString(c);
            System.out.println(s);
        }
    }

}  
``````

  5.1 Hex編碼

  1字節(jié)=8位2進制,比如小寫字母a,ASCII表對應十進制為97,二進制表示為01100001

  1字節(jié)=2位16進制,比如小寫字母a,ASCII表對應十進制為97, 十六進制表示為61

  

1660102090366_5.jpg

  + 因為一個字節(jié)中存在8個 bit可以表示256個字符,而非擴展 ASCII 碼只能表示0-127種字符,為了能完整地表示一個字節(jié),可以將二進制數(shù)據(jù)轉(zhuǎn)換為十六進制數(shù)據(jù)的方式來實現(xiàn)。所以 Hex 編碼也被稱作為 Base16 編碼,相比于原先8位表示一個字節(jié),Hex 編碼能夠只用2位表示一個字節(jié)。Hex 編碼最常用于二進制文件查看時展示的編碼,如010Editor 就可以支持查看二進制文件。

  + 使用16個可見字符來表示一個二進制數(shù)組,編碼后數(shù)據(jù)大小將x2

  + 1個字符需要用2個可見字符來表示

  ##### 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個8位字節(jié)(3乘8=24)轉(zhuǎn)化為4個6位的字節(jié)(4乘6=24),之后在6位的前面補兩個0,形成8位一個字節(jié)的形式。 如果剩下的字符不足3個字節(jié),則用0填充,輸出字符使用'=',因此編碼后輸出的文本末尾可能會出現(xiàn)1或2個'='。為了保證所輸出的編碼位可讀字符,Base64制定了一個編碼表,以便進行統(tǒng)一轉(zhuǎn)換。編碼表的大小為2^6=64,這也是Base64名稱的由來。標準base64只有64個字符(大寫A到Z、小寫a到z、數(shù)字0到9、“+”和“/”)以及用作后綴等號;

  + Base64是網(wǎng)絡上最常見的用于傳輸8Bit字節(jié)碼的可讀性編碼算法之一

  + 以每 3 個 字符(1Byte=8bit)為一組,然后針對每組,首先獲取每個字符的 ASCII 編碼(字符'a'=97=01100001),然后將 ASCII 編碼轉(zhuǎn)換成 8 bit 的二進制,得到一組 3 * 8=24 bit 的字節(jié)。然后再將這 24 bit 劃分為 4 個 6 bit 的字節(jié),并在每個 6 bit 的字節(jié)前面都填兩個高位 0,得到 4 個 8 bit 的字節(jié),然后將這 4 個 8 bit 的字節(jié)轉(zhuǎn)換成十進制,對照 BASE64 編碼表 (下表),得到對應編碼后的字符。

  + 使用64個可見字符來表示一個二進制數(shù)組,編碼后數(shù)據(jù)大小變成原來的4/3

  + 3個字符用4個可見字符來表示

  

1660102306351_6.jpg

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

  

1660102332674_7.jpg

  + 第一步:"jay"、“a”、"n"對應的ASCII碼值分別為106,97,121,對應的二進制值是01101010、01100001、01111001。如圖第二三行所示,由此組成一個24位的二進制字符串。

  + 第二步:如圖第四行,將24位每6位二進制位一組分成四組。

  + 第三步:在上面每一組前面補兩個0(紅色背景),擴展成32個二進制位,此時變?yōu)樗膫€字節(jié):00011010、00100110、00000101、00111001。分別對應的值(Base64編碼索引)為:26、38、5、57。

  + 第四步:用上面的值在Base64編碼表中進行查找,分別對應:a、m、F、5。因此“jay”Base64編碼之后就變?yōu)椋篴mF5。

   5.2.2 代碼示例1-足夠三字節(jié)

``````java
public class Base64DemoTest {

    @Test
    public void test01() {
        //jay正好三個字節(jié),編碼后輸出的結(jié)果沒有=
        System.out.println(Base64.encodeBase64String("jay".getBytes()));
    }
}

  ``````

  5.2.3 原理示例2-不夠三字節(jié)

  如果字節(jié)不足三個怎么辦,分組的時候不組8位的都補0,計算沒結(jié)果的=號代替

  

1660102449908_8.jpg

  
       5.2.4 代碼示例2-不夠三字節(jié)

  
       單元測試:

``````java
public class Base64Demo {

    @Test
    public void test02() {
        //ja不夠三個字節(jié),編碼后一定會有=
        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)密碼體制、共享密鑰密碼體制、秘密密鑰體制或單密鑰體制。從密鑰使用方式上分為分組密碼和序列密碼 ,這點后文會有介紹。

  對稱加密算法的優(yōu)點:算法公開、計算量小、加密速度快、加密效率高。

  對稱加密算法的缺點:交易雙方都使用同樣鑰匙,安全性得不到保證。此外,每對用戶每次使用對稱加密算法時,都需要使用其他人不知道的惟一鑰匙,這會使得發(fā)收信雙方所擁有的鑰匙數(shù)量呈幾何級數(shù)增長,密鑰管理成為用戶的負擔。對稱加密算法在分布式網(wǎng)絡系統(tǒng)上使用較為困難,主要是因為密鑰管理困難,使用成本較高。

  對稱加密通常使用的是相對較小的密鑰,一般小于256 bit。因為密鑰越大,加密越強,但加密與解密的過程越慢。如果你只用1 bit來做這個密鑰,那黑客們可以先試著用0來解密,不行的話就再用1解;但如果你的密鑰有1 MB大,黑客們可能永遠也無法破解,但加密和解密的過程要花費很長的時間。密鑰的大小既要照顧到安全性,也要照顧到效率,是一個trade-off。

  常用對稱加密算法

  1. DES(Data Encryption Standard):數(shù)據(jù)加密標準,速度較快,適用于加密大量數(shù)據(jù)的場合。

  2. 3DES(Triple DES):是基于DES,對一塊數(shù)據(jù)用三個不同的密鑰進行三次加密,強度更高。

  3. AES(Advanced Encryption Standard):高級加密標準,是下一代的加密算法標準,速度快,安全級別高,支持128、192、256、512位密鑰的加密。

  算法特征

  1. 加密方和解密方使用同一個密鑰,一旦密鑰文件泄漏, 就會導致數(shù)據(jù)暴露

  2. 加密解密的速度比較快,適合數(shù)據(jù)比較長時的使用,可以加密大文件

  3. 密鑰傳輸?shù)倪^程不安全,且容易被破解,密鑰管理也比較麻煩。

  4. 加密后編碼表找不到對應字符, 出現(xiàn)亂碼

  5. 一般結(jié)合Base64使用

  6.1.1 DES

  + DES是1997年美國聯(lián)邦信息處理標準中所采用的一種對稱密碼算法,一直以來被美國以及其他國家的政府和銀行等廣泛采用。隨著計算機的快速發(fā)展,DES已經(jīng)被暴力破解,1997年用時96天破譯密鑰,1998年41天破譯密鑰,到了1999年只用22小時15分鐘就可以破譯。

  + DES技術(shù)是一種將64比特的明文加密成64比特的密文的對稱密碼算法,因此理論上來講,他的密鑰長度也是64位,但因為在DES的密鑰中每隔7比特,就會設置一個用于錯誤檢查的比特,所以實際上DES的密鑰的長度只有56比特。

  + DES是以64比特的明文(比特序列)為一個單位進行加密,這64比特的單位成為分組,一般來說,以分組為單位進行處理的密碼算法稱為分組密碼。

  + DES每次每次只能加密64比特的數(shù)據(jù),如果要加密的明文比較長,就需要對DES加密進行迭代(反復),而迭代的具體方案就稱為模式。

  > Java中有關對稱和非對稱加密的核心類:javax.crypto.Cipher

  代碼示例

``````java
/**
 * DES加密算法測試
 */
public class DesTest {

    /**
     * 測試DES加密
     */
    @Test
    public void testEncrypt() throws Exception {
        //明文
        String text = "黑馬程序員";
        //密鑰,長度必須為8個字節(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é),因為ascii碼有負數(shù),解析不出來,所以亂碼
        //將byte數(shù)組轉(zhuǎn)成ASCII編碼,必須確保byte數(shù)組的值在ASCII的可視字符范圍,否則會出現(xiàn)亂碼,
        //因為ASCII的取值范圍比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個字節(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));
        //  因為是明文,所以直接返回
        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,是為了加強DES的強度,將DES重復3次所得到的一種密碼算法。明文需經(jīng)過3次DES處理才能得到最后密文,由于DES密鑰實際長度為56比特,因此3DES的密鑰密鑰實際長度就是56*3=168比特。通過增加迭代次數(shù)提高安全性,常應用在銀行等金融機構(gòu)。

  + DES密鑰長度是8字節(jié)(64比特),3DES密鑰長度是24字節(jié)(192比特)

  + 三重DES不是進行三次DES加密(加密-加密-加密),而是加密-解密-加密的過程。

  + 加密過程:用第一支密鑰對原文進行加密,再使用第二支密鑰對第一步操作后的信息進行解密,最后使用第三支密鑰對第二步操作后的信息進行加密得到最終密文。

  解密過程:用第三支密鑰對密文進行解密,再采用第二支密鑰進行加密,最后采用第一支密鑰解密得到原文。

  + 三重DES中所有密鑰都相同時,三重DES等同于普通DES,因為前兩步加密解密后得到的是原來的明文。

  + EDE:表示加密(Encryption)-> 解密(Decryption)->加密(Encryption)這個流程。

  + 缺點:處理速度較慢、密鑰計算時間較長、加密效率不高。

``````java
/**
 * 3DES加密算法測試
 */
public class Des3Test {

    /**
     * 測試3DES加密
     */
    @Test
    public void testEncrypt() throws Exception {
        //明文
        String text = "黑馬程序員";
        //密鑰,長度必須24個字節(jié)(字符)
        byte[] secretKeyBytes = "123456781234567812345678".getBytes();
        //可指定密鑰實際長度是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個字節(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));
        //  因為是明文,所以直接返回
        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)是取代其前任標準(DES)而稱為新標準的一種對稱算法。

  + 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個字節(jié)(字符)
        byte[] secretKeyBytes = "1234567812345678".getBytes();
        //密鑰實際長度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個字節(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));
        //因為是明文,所以直接返回
        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)計,完全破解要花費時長為2104億年,消耗電量1.1201 * 10^22 kWh,電費1.368 * 10^13 億美元

  6.1.5 選用哪一種?

  DES已被破解不要再使用,3DES在部分金融機構(gòu)內(nèi)還有在使用將來會被AES取代,推薦使用AES。

  6.2 分組密碼

  6.2.1 概念

  按對明文的處理方式,密碼算法可以分為分組密碼( Blok cipher)和流密碼(Stream cipher)。

  6.2.2 分組密碼:**也叫塊加密(block cyphers),每次只能處理特定長度的一塊數(shù)據(jù)的密碼算法,“一塊”稱為分組,一個分組的比特數(shù)就是分組長度。一次加密明文中的一個塊,將明文按一定的位長分組,明文組經(jīng)過加密運算得到密文組,密文組經(jīng)過解密運算(加密運算的逆運算),還原成明文組。比如:DES和3DES的分組長度都是64比特,一次性只能加密64比特的明文并生成64比特的密文。

  6.2.3 序列密碼**:也叫流加密(stream cyphers),對數(shù)據(jù)流進行連續(xù)處理的密碼算法,是指利用少量的密鑰(制亂元素)通過某種復雜的運算(密碼算法)產(chǎn)生大量的偽隨機位流,用于對明文位流的加密。解密是指用同樣的密鑰和密碼算法及與加密相同的偽隨機位流,用以還原明文位流。流密碼中一般以1比特、8比特或32比特等為單位進行加解密。

  6.2.4 對比:**分組密碼處理一個分組就結(jié)束,無需通過內(nèi)部狀態(tài)記錄加密進度;流密碼是對一串數(shù)據(jù)流進行連續(xù)處理,需要保持內(nèi)部狀態(tài)。

  前文所提到的DES、3DES、AES等大部分對稱加密算法都屬于分組密碼。流密碼的典型例子有一次性密碼本。

  > 本文內(nèi)容主要講解的是分組密碼。

  6.2.2 加密模式

  分組算法只能加密固定長度的分組,但有時加密的明文長度會超過分組密碼的分組長度,此時就需要對分組密碼進行迭代,以便將一段很長的明文全部加密。迭代的方法就稱為分組密碼的加密模式(model)。

  加密模式的種類:常見的有ECB模式(電子密碼本模式)、CBC模式(密碼分組鏈接模式)、CTR模式(計數(shù)器模式)等,本課中重點說明ECB模式和CBC模式。

  6.2.3 明文分組與密文分組

  明文分組: 分組密碼算法中作為加密對象的明文。明文分組的長度與分組密碼算法的分組長度相等。

  密文分組:分組加密算法中對明文分組加密之后產(chǎn)生的密文。

1660103004042_9.jpg


分享到:
在線咨詢 我要報名
和我們在線交談!