加密算法簡(jiǎn)介

一、一點(diǎn)歷史

1976年以前,所有的加密方法都是同一種模式:

(1)甲方選擇某一種加密規(guī)則,對(duì)信息進(jìn)行加密;
 ?。?)乙方使用同一種規(guī)則,對(duì)信息進(jìn)行解密。

由于加密和解密使用同樣規(guī)則(簡(jiǎn)稱"密鑰"),這被稱為"對(duì)稱加密算法"(Symmetric-key algorithm)。
這種加密模式有一個(gè)最大弱點(diǎn):甲方必須把加密規(guī)則告訴乙方,否則無(wú)法解密。保存和傳遞密鑰,就成了最頭疼的問題。


1976年,兩位美國(guó)計(jì)算機(jī)學(xué)家Whitfield Diffie 和 Martin Hellman,提出了一種嶄新構(gòu)思,可以在不直接傳遞密鑰的情況下,完成解密。這被稱為"Diffie-Hellman密鑰交換算法"。這個(gè)算法啟發(fā)了其他科學(xué)家。人們認(rèn)識(shí)到,加密和解密可以使用不同的規(guī)則,只要這兩種規(guī)則之間存在某種對(duì)應(yīng)關(guān)系即可,這樣就避免了直接傳遞密鑰。
這種新的加密模式被稱為"非對(duì)稱加密算法"。
 ?。?)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
 ?。?)甲方獲取乙方的公鑰,然后用它對(duì)信息加密。
  (3)乙方得到加密后的信息,用私鑰解密。

如果公鑰加密的信息只有私鑰解得開,那么只要私鑰不泄漏,通信就是安全的。


1977年,三位數(shù)學(xué)家Rivest、Shamir 和 Adleman 設(shè)計(jì)了一種算法,可以實(shí)現(xiàn)非對(duì)稱加密。這種算法用他們?nèi)齻€(gè)人的名字命名,叫做RSA算法。從那時(shí)直到現(xiàn)在,RSA算法一直是最廣為使用的"非對(duì)稱加密算法"。毫不夸張地說(shuō),只要有計(jì)算機(jī)網(wǎng)絡(luò)的地方,就有RSA算法。
這種算法非常可靠,密鑰越長(zhǎng),它就越難破解。根據(jù)已經(jīng)披露的文獻(xiàn),目前被破解的最長(zhǎng)RSA密鑰是768個(gè)二進(jìn)制位。也就是說(shuō),長(zhǎng)度超過768位的密鑰,還無(wú)法破解(至少?zèng)]人公開宣布)。因此可以認(rèn)為,1024位的RSA密鑰基本安全,2048位的密鑰極其安全。


二、對(duì)稱加密算法(AES算法)

1. AES算法

對(duì)稱加密算法中,數(shù)據(jù)加密和解密采用的都是同一個(gè)密鑰,因而其安全性依賴于所持有密鑰的安全性。
對(duì)稱加密算法的主要優(yōu)點(diǎn)是加密和解密速度快,加密強(qiáng)度高,且算法公開。
缺點(diǎn)是實(shí)現(xiàn)密鑰的秘密分發(fā)困難,在大量用戶的情況下密鑰管理復(fù)雜,而且無(wú)法完成身份認(rèn)證等功能,不便于應(yīng)用在網(wǎng)絡(luò)開放的環(huán)境中。

由于密鑰是對(duì)稱加密解密的核心,密鑰本身的安全性要求較高,以AES算法為例,它的密鑰長(zhǎng)度至少為128位(因此也稱AES-128。AES-192AES-256自然也知道是什么意思了吧)

一般來(lái)說(shuō),對(duì)于對(duì)稱加密體制,通常也會(huì)包含3個(gè)算法:KeyGen(密鑰生成算法)Encrypt(加密算法)以及Decrypt(解密算法)

(1) 密鑰生成算法

 (Key) <— KeyGen(λ)    // 密鑰生成算法

對(duì)于對(duì)稱加密體制來(lái)說(shuō)(以AES為例),本身并沒有定義密鑰生成算法,僅僅是要求密鑰長(zhǎng)度達(dá)到要求即可(AES-128),也就是說(shuō),通常密鑰生成算法是由我們自己實(shí)現(xiàn),只要最終生成的密鑰長(zhǎng)度達(dá)到算法要求的即可。

我們通常會(huì)隨機(jī)生成密鑰,如下代碼為例:

/**
     * 自動(dòng)生成AES128位密鑰
     */
    public static void getA221(){
        try {
            KeyGenerator kg = KeyGenerator.getInstance("AES");
            kg.init(128);//要生成多少位,只需要修改這里即可128, 192或256
            SecretKey sk = kg.generateKey();
            byte[] b = sk.getEncoded();
            String s = byteToHexString(b);
            System.out.println(s);
            System.out.println("十六進(jìn)制密鑰長(zhǎng)度為"+s.length());
            System.out.println("二進(jìn)制密鑰的長(zhǎng)度為"+s.length()*4);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            System.out.println("沒有此算法。");
        }
    }
    
    /**
     * 二進(jìn)制byte[]轉(zhuǎn)十六進(jìn)制string
     */
    public static String byteToHexString(byte[] bytes){   
         StringBuffer sb = new StringBuffer();   
         for (int i = 0; i < bytes.length; i++) {   
              String strHex=Integer.toHexString(bytes[i]);   
              if(strHex.length() > 3){   
                     sb.append(strHex.substring(6));   
              } else {
                   if(strHex.length() < 2){
                      sb.append("0" + strHex);
                   } else {
                      sb.append(strHex);   
                   }   
              }
         }
        return  sb.toString();   
    }
    
    /**
     * 十六進(jìn)制string轉(zhuǎn)二進(jìn)制byte[]
     */
    public static byte[] hexStringToByte(String s) {   
        byte[] baKeyword = new byte[s.length() / 2];   
        for (int i = 0; i < baKeyword.length; i++) {   
            try {   
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));   
            } catch (Exception e) {   
                System.out.println("十六進(jìn)制轉(zhuǎn)byte發(fā)生錯(cuò)誤?。?!");   
                e.printStackTrace();   
            }   
        }   
        return baKeyword;   
    } 
    
    /**
     * 使用對(duì)稱密鑰進(jìn)行加密
     */
    public static void getA231() throws Exception{
        String keys = "c0e9fcff59ecc3b8b92939a1a2724a44";   //密鑰
        byte[] keyb = hexStringToByte(keys);
        String mingwen = "hello word!";                         //明文
        SecretKeySpec sKeySpec = new SecretKeySpec(keyb, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
        byte[] bjiamihou = cipher.doFinal(mingwen.getBytes());
        System.out.println(byteToHexString(bjiamihou));     //加密后數(shù)據(jù)為ecf0a6bc80dbaf657eac9b06ecd92962
    }
    
    /**
     * 使用對(duì)稱密鑰進(jìn)行解密 
     */
    public static void getA232() throws Exception{
        String keys = "c0e9fcff59ecc3b8b92939a1a2724a44";   //密鑰
        byte[] keyb = hexStringToByte(keys);
        String sjiami = "ecf0a6bc80dbaf657eac9b06ecd92962"; //密文
        byte[] miwen = hexStringToByte(sjiami);
        SecretKeySpec sKeySpec = new SecretKeySpec(keyb, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
        byte[] bjiemihou = cipher.doFinal(miwen);
        System.out.println(new String(bjiemihou));
    }

(2) 加密算法

 (CT) <— Encrypt(Key,M)    // 加密算法

加密算法以明文(我們要加密的內(nèi)容)和密鑰作為參數(shù)輸入,輸出密文CT。

這里解釋一下什么是可逆:當(dāng)我們拿到密文,又拿到了密鑰,那么是可以推算出原文的,這就是對(duì)稱加密體制中的解密算法
再多思考一下假如我們拿到了明文,又拿到了密文,我們可以推算出密鑰嗎?很直白的告訴你,沒有辦法直接算出密鑰,唯一的方式就是窮舉,俗稱暴力破解。舉個(gè)生活中的例子:我們知道礦泉水的原材料是水,但是礦泉水并不是簡(jiǎn)單的將水裝到瓶子包裝一下就成了礦泉水(農(nóng)夫三拳除外),是需要經(jīng)過工廠的很多工序之后,才會(huì)生產(chǎn)出一瓶礦泉水,我們能看到原材料-水(原文),我們也能看到產(chǎn)品-礦泉水(密文),但是我們看不到中間的工序(密鑰,不為外人所知,只有工廠自己知道)
突然發(fā)現(xiàn)礦泉水的這個(gè)栗子非常貼切:

礦泉水 <— 工廠工序(水)    // 加密算法
水<—倒掉(礦泉水)  // 解密算法,我們將礦泉水倒在地上(或者喝掉),最終又變回了水,
// 這里只是想說(shuō)明礦泉水是能夠!!!變回水的,不必太較真礦泉水是怎么!!!變回水的...

(3) 解密算法

 (M) <— Decrypt(Key,CT)    // 解密算法

解密算法以密鑰和密文CT作為參數(shù)輸入,輸出明文M。

這里的栗子可以參照上面礦泉水變?yōu)樗焕?br> 那么在這里提個(gè)疑問:我們?cè)趯?shí)際應(yīng)用中,比如手機(jī)和后臺(tái)交互,數(shù)據(jù)采用對(duì)稱加密(對(duì)稱加密速度快?。?,那么這個(gè)密鑰該如何傳遞呢?明文傳遞密鑰肯定不合適咯,那么我們?cè)撊绾伟踩膫鬟f密鑰呢?
Follow Me!Let's go!


三、非對(duì)稱加密算法(RSA算法)

注意:非對(duì)稱加密由于非對(duì)稱體制,可能難于理解,但是只要記住我下面的筆記,你就能很清晰的記住后面我所講的一些名詞。
首先給大家畫一張思維導(dǎo)圖,這里我推薦一家在線制圖網(wǎng)站https://www.processon.com

https://www.processon.com

思維導(dǎo)圖

1. RSA的加密算法(PK加密,SK解密)

我們來(lái)回顧一下RSA的加密算法。我們從公鑰加密算法和簽名算法的定義出發(fā),用比較規(guī)范的語(yǔ)言來(lái)描述這一算法。

RSA公鑰加密體制包含如下3個(gè)算法:KeyGen(密鑰生成算法),Encrypt(加密算法)以及Decrypt(解密算法)。

(1) 密鑰生成算法

[圖片上傳失敗...(image-e1c0cc-1513844367128)]

密鑰生成算法以安全常數(shù)λ作為輸入,輸出一個(gè)公鑰PK,和一個(gè)私鑰SK。安全常數(shù)用于確定這個(gè)加密算法的安全性有多高,一般以加密算法使用的質(zhì)數(shù)p的大小有關(guān)。λ越大,質(zhì)數(shù)p一般越大,保證體制有更高的安全性。在RSA中,密鑰生成算法如下:算法首先隨機(jī)產(chǎn)生兩個(gè)不同大質(zhì)數(shù)p和q,計(jì)算N=pq。隨后,算法計(jì)算歐拉函數(shù)φ(N)=(p-1)(q-1)。接下來(lái),算法隨機(jī)選擇一個(gè)小于φ(N)的整數(shù)e,并計(jì)算e關(guān)于φ(N)的模反元素d。最后,公鑰為PK=(N, e),私鑰為SK=(N, d)。

(2) 加密算法

加密算法

加密算法以公鑰PK和待加密的消息M作為輸入,輸出密文CT。在RSA中,加密算法如下:算法直接輸出密文為CT = M^e mod N

(3) 解密算法

解密算法

解密算法以私鑰SK和密文CT作為輸入,輸出消息M。在RSA中,解密算法如下:算法直接輸出明文為M = CT^d mod N。由于e和d在φ(N)下互逆,因此我們有:CT^d = M^ed = M mod N

所以,從算法描述中我們也可以看出:公鑰用于對(duì)數(shù)據(jù)進(jìn)行加密,私鑰用于對(duì)數(shù)據(jù)進(jìn)行解密。當(dāng)然了,這個(gè)也可以很直觀的理解:公鑰就是公開的密鑰,其公開了大家才能用它來(lái)加密數(shù)據(jù)。私鑰是私有的密鑰,誰(shuí)有這個(gè)密鑰才能夠解密密文。否則大家都能看到私鑰,就都能解密,那不就亂套了。


2. RSA的簽名算法(SK加密,PK解密)

我們?cè)賮?lái)回顧一下RSA簽名體制。簽名體制同樣包含3個(gè)算法:KeyGen(密鑰生成算法),Sign(簽名算法),Verify(驗(yàn)證算法)。

(1) 密鑰生成算法

密鑰生成算法

密鑰生成算法同樣以安全常數(shù)λ作為輸入,輸出一個(gè)公鑰PK和一個(gè)私鑰SK。在RSA簽名中,密鑰生成算法與加密算法完全相同。

(2) 簽名算法

簽名算法

簽名算法以私鑰SK和待簽名的消息M作為輸入,輸出簽名α。在RSA簽名中,簽名算法直接輸出簽名為α = M^d mod N。注意,簽名算法和RSA加密體制中的解密算法非常像。

(3) 驗(yàn)證算法

驗(yàn)證算法

驗(yàn)證算法以公鑰PK,簽名α以及消息M作為輸入,輸出一個(gè)比特值b。b=1意味著驗(yàn)證通過。b=0意味著驗(yàn)證不通過。在RSA簽名中,驗(yàn)證算法首先計(jì)算M' = α^e mod N,隨后對(duì)比M'與M,如果相等,則輸出b=1,否則輸出b=0。注意:驗(yàn)證算法和RSA加密體制中的加密算法非常像。

所以,在簽名算法中,私鑰用于對(duì)數(shù)據(jù)進(jìn)行簽名,公鑰用于對(duì)簽名進(jìn)行驗(yàn)證。這也可以直觀地進(jìn)行理解:對(duì)一個(gè)文件簽名,當(dāng)然要用私鑰,因?yàn)槲覀兿M挥凶约翰拍芡瓿珊炞?。?yàn)證過程當(dāng)然希望所有人都能夠執(zhí)行,大家看到簽名都能通過驗(yàn)證證明確實(shí)是我自己簽的。

3. 應(yīng)用場(chǎng)景

其實(shí)公鑰和私鑰都可以用來(lái)加密或解密——只要能保證用A加密,就用B解密就行。至于A是公鑰還是私鑰,其實(shí)可以根據(jù)不同的用途而定。例如說(shuō),如果你想把某個(gè)消息秘密的發(fā)給某人,那你就可以用他的公鑰加密。因?yàn)橹挥兴浪乃借€,所以這消息也就只有他本人能解開,于是你就達(dá)到了你的目的。
但是如果你想發(fā)布一個(gè)公告,需要一個(gè)手段來(lái)證明這確實(shí)是你本人發(fā)的,而不是其他人冒名頂替的。那你可以在你的公告開頭或者結(jié)尾附上一段用你的私鑰加密的內(nèi)容(例如說(shuō)就是你公告正文的一段話),那所有其他人都可以用你的公鑰來(lái)解密,看看解出來(lái)的內(nèi)容是不是相符的。如果是的話,那就說(shuō)明這公告確實(shí)是你發(fā)的---因?yàn)橹挥心愕墓€才能解開你的私鑰加密的內(nèi)容,而其他人是拿不到你的私鑰的。
最后再說(shuō)一下數(shù)字簽名。數(shù)字簽名無(wú)非就兩個(gè)目的:證明這消息是你發(fā)的;證明這消息內(nèi)容確實(shí)是完整的——也就是沒有經(jīng)過任何形式的篡改(包括替換、缺少、新增)。其實(shí),上面關(guān)于“公告”那段內(nèi)容,已經(jīng)證明了第一點(diǎn):證明這消息是你發(fā)的。那么要做到第二點(diǎn),也很簡(jiǎn)單,就是把你公告的原文做一次哈希(md5或者sha1都行),然后用你的私鑰加密這段哈希作為簽名,并一起公布出去。當(dāng)別人收到你的公告時(shí),他可以用你的公鑰解密你的簽名,如果解密成功,并且解密出來(lái)的哈希值確實(shí)和你的公告原文一致,那么他就證明了兩點(diǎn):這消息確實(shí)是你發(fā)的,而且內(nèi)容是完整的。


四、散列算法(也稱HASH,消息摘要,不可逆算法)

Hash的應(yīng)用場(chǎng)景非常之多,常見的算法有MD5、SHA-1,只要涉及到通訊傳輸,都離不開hash(說(shuō)的有些絕對(duì),只為突出其重要性),因?yàn)閔ash最大的用途是用于校驗(yàn)信息完整性,保證服務(wù)端傳送的信息被客戶端完整的收到,防止丟包后客戶端無(wú)法判定文件是否完整。

1. MD5算法

hash值 <— MD5(M); // 算法表達(dá)式

哈希運(yùn)算的輸入M可以是任意長(zhǎng)度的字節(jié)碼(長(zhǎng)度不限,但是過長(zhǎng)會(huì)導(dǎo)致hash運(yùn)算很慢,因此一般我們會(huì)發(fā)送的消息截取部分進(jìn)行hash),輸出固定長(zhǎng)度的hash值(通常為128位)
由于hash的不可逆性,我們會(huì)經(jīng)常使用它來(lái)生成唯一標(biāo)示,只要M不同,那么輸出的hash值絕對(duì)不會(huì)相同,我們的UUID生成就使用到了hash。

2. Hash的碰撞攻擊

我們一上來(lái)也提到了hash是一種不可逆運(yùn)算,那么想根據(jù)hash值反推明文的方式就只有一種,暴力破解!但是,暴力破解并不是無(wú)腦破解(就像你猜一個(gè)人的銀行密碼一樣,你肯定會(huì)從這個(gè)人的身份信息開始猜測(cè))。由于Hash算法本身是公開的,算法本身可能存在一些漏洞,2004年8月17日的美國(guó)加州圣巴巴拉的國(guó)際密碼學(xué)會(huì)議(Crypto’2004)上,來(lái)自中國(guó)山東大學(xué)的王小云教授做了破譯MD5、HAVAL-128、 MD4和RIPEMD算法的報(bào)告,公布了MD系列算法的破解結(jié)果。宣告了固若金湯的世界通行密碼標(biāo)準(zhǔn)MD5的堡壘轟然倒塌,引發(fā)了密碼學(xué)界的軒然大波。(注意:并非是真正的破解,只是加速了雜湊沖撞)
關(guān)于王小云博士的故事有興趣的人可以自己百度(還是蠻有意思的)。
而目前大數(shù)據(jù)云計(jì)算的興起,越多越多的MD5計(jì)算網(wǎng)站開始興起,他們有大量的機(jī)器(分布式云計(jì)算)不停地計(jì)算不同的文本對(duì)應(yīng)的md5值,并將結(jié)果存入數(shù)據(jù)庫(kù)或Hadoop(大數(shù)據(jù))。如圖所示:

百度搜索結(jié)果


五、常見名詞解釋

1. 數(shù)字簽名

數(shù)字簽名是非對(duì)稱密鑰加密技術(shù)數(shù)字摘要技術(shù)的應(yīng)用。

主要功能
保證信息傳輸?shù)耐暾?、發(fā)送者的身份認(rèn)證、防止交易中的抵賴發(fā)生。
數(shù)字簽名技術(shù)是將摘要信息用發(fā)送者的私鑰加密,與原文一起傳送給接收者。接收者只有用發(fā)送者的公鑰才能解密被加密的摘要信息,然后用HASH函數(shù)對(duì)收到的原文產(chǎn)生一個(gè)摘要信息,與解密的摘要信息對(duì)比。如果相同,則說(shuō)明收到的信息是完整的,在傳輸過程中沒有被修改,否則說(shuō)明信息被修改過,因此數(shù)字簽名能夠驗(yàn)證信息的完整性。
數(shù)字簽名是個(gè)加密的過程,數(shù)字簽名驗(yàn)證是個(gè)解密的過程。

狹義上的數(shù)字簽名(也被叫做數(shù)字指紋)過程
發(fā)送報(bào)文時(shí),發(fā)送方用一個(gè)哈希函數(shù)從報(bào)文文本中生成報(bào)文摘要,然后用自己的私人密鑰對(duì)這個(gè)摘要進(jìn)行加密(簽名),這個(gè)加密(簽名)后的摘要將作為報(bào)文的數(shù)字簽名和報(bào)文一起發(fā)送給接收方,接收方首先用與發(fā)送方一樣的哈希函數(shù)從接收到的原始報(bào)文中計(jì)算出報(bào)文摘要,接著再用發(fā)送方的公用密鑰來(lái)對(duì)報(bào)文附加的數(shù)字簽名進(jìn)行解密,如果這兩個(gè)摘要相同、那么接收方就能確認(rèn)該數(shù)字簽名是發(fā)送方的。
數(shù)字簽名有兩種功效:一是能確定消息確實(shí)是由發(fā)送方簽名并發(fā)出來(lái)的,因?yàn)閯e人假冒不了發(fā)送方的簽名。二是數(shù)字簽名能確定消息的完整性。因?yàn)閿?shù)字簽名的特點(diǎn)是它代表了文件的特征,文件如果發(fā)生改變,數(shù)字摘要的值也將發(fā)生變化。不同的文件將得到不同的數(shù)字摘要。 一次數(shù)字簽名涉及到一個(gè)哈希函數(shù)、發(fā)送者的公鑰、發(fā)送者的私鑰。

廣義上的數(shù)字簽名過程(僅僅是簽名與校驗(yàn)):
發(fā)送方用自己的密鑰對(duì)報(bào)文X進(jìn)行Encrypt(編碼)運(yùn)算,生成不可讀取的密文Dsk,然后將Dsk傳送給接收方,接收方為了核實(shí)簽名,用發(fā)送方的公用密鑰進(jìn)行Decrypt(解碼)運(yùn)算,還原報(bào)文。


2. 數(shù)字證書

狹義上的數(shù)字證書是一個(gè)經(jīng)證書授權(quán)中心數(shù)字簽名的包含公開密鑰擁有者信息以及公開密鑰的文件。最簡(jiǎn)單的證書包含一個(gè)公開密鑰、名稱以及證書授權(quán)中心的數(shù)字簽名。數(shù)字證書還有一個(gè)重要的特征就是只在特定的時(shí)間段內(nèi)有效。

廣義上的數(shù)字證書指包含了公鑰以及證書有效期,加密算法信息,頒發(fā)機(jī)構(gòu)等信息的文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容