嚴格地說,AES和Rijndael加密法並不完全一樣(雖然在實際應用中二者可以互換),因為Rijndael加密法可以支罩鬧持更大范圍的區塊和密鑰長度:
AES的區塊長度固定為128位,密鑰長度則可以是128,192或256位;而Rijndael使用的密鑰和區塊長度可以是32位的整數倍,以128位為下限,256位為上限。加密過程中使用的密鑰是由Rijndael密鑰生成方案產生。
(1)下列不屬於ec演算法密鑰長度的是擴展閱讀
AES加密模式
對稱/分組密碼一般分為流加密(如OFB、CFB等)和塊加密(如ECB、CBC等)。對於流加密,需要將分組密碼轉化為流模式工作。對於塊加密(或稱分組加密),如果要加密超過塊大小的數據,就需要涉及填充和鏈加物凳罩密模式。
優點:1、簡單;
2、有利於並行計算;
3、誤差不會被傳送;
缺點:
1、不能隱藏明文的模式;
2、可能對明文進行主動粗鍵攻擊;
3、因此,此模式適於加密小消息。
② ¥¥¥¥基於java語言的數字簽名¥¥¥¥¥
畢業設計起碼也得2個月時間,你現在才開始,不復制粘貼來不及啊~
Java加密和數字簽名編程快速入門
本文主要談一下密碼學中的加密和數字簽名,以及其在java中如何進行使用。對密碼學有興趣的夥伴,推薦看Bruce Schneier的著作:Applied Crypotography。在jdk1.5的發行版本中安全性方面有了很大的改進,也提供了對RSA演算法的直接支持,現在我們從實例入手解決問題(本文僅是作為簡單介紹):
一、密碼學上常用的概念
1)消息摘要:
這是一種與消息認證碼結合使用以確保消息完整性的技術。主要使用單向散列函數演算法,可用於檢驗消息的完整性,和通過散列密碼直接以文本形式保存等,目前廣泛使用的演算法有MD4、MD5、SHA-1,jdk1.5對上面都提供了支持,在java中進行消息摘要很簡單, java.security.MessageDigest提供了一個簡易的操作方法:
/**
*MessageDigestExample.java
*Copyright 2005-2-16
*/
import java.security.MessageDigest;
/**
*單一的消息摘要演算法,不使用密碼.可以用來對明文消息(如:密碼)隱藏保存
*/
public class MessageDigestExample{
public static void main(String[] args) throws Exception{
if(args.length!=1){
System.err.println("Usage:java MessageDigestExample text");
System.exit(1);
}
byte[] plainText=args[0].getBytes("UTF8");
//使用getInstance("演算法")來獲得消息摘要,這里使用SHA-1的160位演算法
MessageDigest messageDigest=MessageDigest.getInstance("SHA-1");
System.out.println("\n"+messageDigest.getProvider().getInfo());
//開始使用演算法
messageDigest.update(plainText);
System.out.println("\nDigest:");
//輸出演算法運算結果
System.out.println(new String(messageDigest.digest(),"UTF8"));
}
}
還可以通過消息認證碼來進行加密實現,javax.crypto.Mac提供了一個解決方案,有興趣者可以參考相關API文檔,本文只是簡單介紹什麼是摘要演算法。
2)私鑰加密:
消息摘要只能檢查消息的完整性,但是單向的,對明文消息並不能加密,要加密明文的消息的話,就要使用其他的演算法,要確保機密性,我們需要使用私鑰密碼術來交換私有消息。
這種最好理解,使用對稱演算法。比如:A用一個密鑰對一個文件加密,而B讀取這個文件的話,則需要和A一樣的密鑰,雙方共享一個私鑰(而在web環境下,私鑰在傳遞時容易被偵聽):
使用私鑰加密的話,首先需要一個密鑰,可用javax.crypto.KeyGenerator產生一個密鑰(java.security.Key),然後傳遞給一個加密工具(javax.crypto.Cipher),該工具再使用相應的演算法來進行加密,主要對稱演算法有:DES(實際密鑰只用到56位),AES(支持三種密鑰長度:128、192、256位),通常首先128位,其他的還有DESede等,jdk1.5種也提供了對對稱演算法的支持,以下例子使用AES演算法來加密:
/**
*PrivateExmaple.java
*Copyright 2005-2-16
*/
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;
/**
*私鈅加密,保證消息機密性
*/
public class PrivateExample{
public static void main(String[] args) throws Exception{
if(args.length!=1){
System.err.println("Usage:java PrivateExample <text>");
System.exit(1);
}
byte[] plainText=args[0].getBytes("UTF8");
//通過KeyGenerator形成一個key
System.out.println("\nStart generate AES key");
KeyGenerator keyGen=KeyGenerator.getInstance("AES");
keyGen.init(128);
Key key=keyGen.generateKey();
System.out.println("Finish generating DES key");
//獲得一個私鈅加密類Cipher,ECB是加密方式,PKCS5Padding是填充方法
Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
System.out.println("\n"+cipher.getProvider().getInfo());
//使用私鈅加密
System.out.println("\nStart encryption:");
cipher.init(Cipher.ENCRYPT_MODE,key);
byte[] cipherText=cipher.doFinal(plainText);
System.out.println("Finish encryption:");
System.out.println(new String(cipherText,"UTF8"));
System.out.println("\nStart decryption:");
cipher.init(Cipher.DECRYPT_MODE,key);
byte[] newPlainText=cipher.doFinal(cipherText);
System.out.println("Finish decryption:");
System.out.println(new String(newPlainText,"UTF8"));
}
}
3)公鑰加密:
上面提到,私鑰加密需要一個共享的密鑰,那麼如何傳遞密鑰呢?web環境下,直接傳遞的話很容易被偵聽到,幸好有了公鑰加密的出現。公鑰加密也叫不對稱加密,不對稱演算法使用一對密鑰對,一個公鑰,一個私鑰,使用公鑰加密的數據,只有私鑰能解開(可用於加密);同時,使用私鑰加密的數據,只有公鑰能解開(簽名)。但是速度很慢(比私鑰加密慢100到1000倍),公鑰的主要演算法有RSA,還包括Blowfish,Diffie-Helman等,jdk1.5種提供了對RSA的支持,是一個改進的地方:
/**
*PublicExample.java
*Copyright 2005-2-16
*/
import java.security.Key;
import javax.crypto.Cipher;
import java.security.KeyPairGenerator;
import java.security.KeyPair;
/**
*一個簡單的公鈅加密例子,Cipher類使用KeyPairGenerator生成的公鈅和私鈅
*/
public class PublicExample{
public static void main(String[] args) throws Exception{
if(args.length!=1){
System.err.println("Usage:java PublicExample <text>");
System.exit(1);
}
byte[] plainText=args[0].getBytes("UTF8");
//構成一個RSA密鑰
System.out.println("\nStart generating RSA key");
KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair key=keyGen.generateKeyPair();
System.out.println("Finish generating RSA key");
//獲得一個RSA的Cipher類,使用公鈅加密
Cipher cipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");
System.out.println("\n"+cipher.getProvider().getInfo());
System.out.println("\nStart encryption");
cipher.init(Cipher.ENCRYPT_MODE,key.getPublic());
byte[] cipherText=cipher.doFinal(plainText);
System.out.println("Finish encryption:");
System.out.println(new String(cipherText,"UTF8"));
//使用私鈅解密
System.out.println("\nStart decryption");
cipher.init(Cipher.DECRYPT_MODE,key.getPrivate());
byte[] newPlainText=cipher.doFinal(cipherText);
System.out.println("Finish decryption:");
System.out.println(new String(newPlainText,"UTF8"));
}
}
4)數字簽名:
數字簽名,它是確定交換消息的通信方身份的第一個級別。上面A通過使用公鑰加密數據後發給B,B利用私鑰解密就得到了需要的數據,問題來了,由於都是使用公鑰加密,那麼如何檢驗是A發過來的消息呢?上面也提到了一點,私鑰是唯一的,那麼A就可以利用A自己的私鑰進行加密,然後B再利用A的公鑰來解密,就可以了;數字簽名的原理就基於此,而通常為了證明發送數據的真實性,通過利用消息摘要獲得簡短的消息內容,然後再利用私鑰進行加密散列數據和消息一起發送。java中為數字簽名提供了良好的支持,java.security.Signature類提供了消息簽名:
/**
*DigitalSignature2Example.java
*Copyright 2005-2-16
*/
import java.security.Signature;
import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.security.SignatureException;
/**
*數字簽名,使用RSA私鑰對對消息摘要簽名,然後使用公鈅驗證 測試
*/
public class DigitalSignature2Example{
public static void main(String[] args) throws Exception{
if(args.length!=1){
System.err.println("Usage:java DigitalSignature2Example <text>");
System.exit(1);
}
byte[] plainText=args[0].getBytes("UTF8");
//形成RSA公鑰對
System.out.println("\nStart generating RSA key");
KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair key=keyGen.generateKeyPair();
System.out.println("Finish generating RSA key");
//使用私鈅簽名
Signature sig=Signature.getInstance("SHA1WithRSA");
sig.initSign(key.getPrivate());
sig.update(plainText);
byte[] signature=sig.sign();
System.out.println(sig.getProvider().getInfo());
System.out.println("\nSignature:");
System.out.println(new String(signature,"UTF8"));
//使用公鈅驗證
System.out.println("\nStart signature verification");
sig.initVerify(key.getPublic());
sig.update(plainText);
try{
if(sig.verify(signature)){
System.out.println("Signature verified");
}else System.out.println("Signature failed");
}catch(SignatureException e){
System.out.println("Signature failed");
}
}
}
5)數字證書。
還有個問題,就是公鑰問題,A用私鑰加密了,那麼B接受到消息後,用A提供的公鑰解密;那麼現在有個討厭的C,他把消息攔截了,然後用自己的私鑰加密,同時把自己的公鑰發給B,並告訴B,那是A的公鑰,結果....,這時候就需要一個中間機構出來說話了(相信權威,我是正確的),就出現了Certificate Authority(也即CA),有名的CA機構有Verisign等,目前數字認證的工業標準是:CCITT的X.509:
數字證書:它將一個身份標識連同公鑰一起進行封裝,並由稱為認證中心或 CA 的第三方進行數字簽名。
密鑰庫:java平台為你提供了密鑰庫,用作密鑰和證書的資源庫。從物理上講,密鑰庫是預設名稱為 .keystore 的文件(有一個選項使它成為加密文件)。密鑰和證書可以擁有名稱(稱為別名),每個別名都由唯一的密碼保護。密鑰庫本身也受密碼保護;您可以選擇讓每個別名密碼與主密鑰庫密碼匹配。
使用工具keytool,我們來做一件自我認證的事情吧(相信我的認證):
1、創建密鑰庫keytool -genkey -v -alias feiUserKey -keyalg RSA 默認在自己的home目錄下(windows系統是c:\documents and settings\<你的用戶名> 目錄下的.keystore文件),創建我們用 RSA 演算法生成別名為 feiUserKey 的自簽名的證書,如果使用了-keystore mm 就在當前目錄下創建一個密鑰庫mm文件來保存密鑰和證書。
2、查看證書:keytool -list 列舉了密鑰庫的所有的證書
也可以在dos下輸入keytool -help查看幫助。
二、JAR的簽名
我們已經學會了怎樣創建自己的證書了,現在可以開始了解怎樣對JAR文件簽名,JAR文件在Java中相當於 ZIP 文件,允許將多個 Java 類文件打包到一個具有 .jar 擴展名的文件中,然後可以對這個jar文件進行數字簽名,以證實其來源和真實性。該 JAR 文件的接收方可以根據發送方的簽名決定是否信任該代碼,並可以確信該內容在接收之前沒有被篡改過。同時在部署中,可以通過在策略文件中放置訪問控制語句根據簽名者的身份分配對機器資源的訪問權。這樣,有些Applet的安全檢驗訪問就得以進行。
使用jarsigner工具可以對jar文件進行簽名:
現在假設我們有個Test.jar文件(可以使用jar命令行工具生成):
jarsigner Test.jar feiUserKey (這里我們上面創建了該別名的證書) ,詳細信息可以輸入jarsigner查看幫助
驗證其真實性:jarsigner -verify Test.jar(注意,驗證的是jar是否被修改了,但不檢驗減少的,如果增加了新的內容,也提示,但減少的不會提示。)
使用Applet中:<applet code="Test.class" archive="Test.jar" width="150" height="100"></applet>然後瀏覽器就會提示你:准許這個會話-拒絕-始終准許-查看證書等。
三、安全套接字層(SSL Secure Sockets Layer)和傳輸層安全性(TLS Transport Layer Security)
安全套接字層和傳輸層安全性是用於在客戶機和伺服器之間構建安全的通信通道的協議。它也用來為客戶機認證伺服器,以及(不太常用的)為伺服器認證客戶機。該協議在瀏覽器應用程序中比較常見,瀏覽器窗口底部的鎖表明 SSL/TLS 有效:
1)當使用 SSL/TLS(通常使用 https:// URL)向站點進行請求時,從伺服器向客戶機發送一個證書。客戶機使用已安裝的公共 CA 證書通過這個證書驗證伺服器的身份,然後檢查 IP 名稱(機器名)與客戶機連接的機器是否匹配。
2)客戶機生成一些可以用來生成對話的私鑰(稱為會話密鑰)的隨機信息,然後用伺服器的公鑰對它加密並將它發送到伺服器。伺服器用自己的私鑰解密消息,然後用該隨機信息派生出和客戶機一樣的私有會話密鑰。通常在這個階段使用 RSA 公鑰演算法。
3)客戶機和伺服器使用私有會話密鑰和私鑰演算法(通常是 RC4)進行通信。使用另一個密鑰的消息認證碼來確保消息的完整性。
java中javax.net.ssl.SSLServerSocketFactory類提供了一個很好的SSLServerSocker的工廠類,熟悉Socket編程的讀者可以去練習。當編寫完伺服器端之後,在瀏覽器上輸入https://主機名:埠 就會通過SSL/TLS進行通話了。注意:運行服務端的時候要帶系統環境變數運行:javax.net.ssl.keyStore=密鑰庫(創建證書時,名字應該為主機名,比如localhost)和javax.net.ssl.keyStorePassword=你的密碼
③ 快速了解常用的對稱加密演算法,再也不用擔心面試官的刨根問底
加密演算法通常被分為兩種: 對稱加密 和 非對稱加密 。其中,對稱加密演算法在加密和解密時使用的密鑰相同;非對稱加密演算法在加密和解密時使用的密鑰不同,分為公鑰和私鑰。此外,還有一類叫做 消息摘要演算法 ,是對數據進行摘要並且不可逆的演算法。
這次我們了解一下對稱加密演算法。
對稱加密演算法在加密和解密時使用的密鑰相同,或是使用兩個可以簡單地相互推算的密鑰。在大多數的對稱加密演算法中,加密和解密的密鑰是相同的。
它要求雙方在安全通信之前,商定一個密鑰。對稱演算法的安全性依賴於密鑰,泄漏密鑰就意味著任何人都可以對他們發送的信息進行解密,這也是對稱加密演算法的主要缺點之一。
常見的對稱加密演算法有:DES演算法、3DES演算法、AES演算法。
DES演算法(Data Encryption Standard)是一種常見的分組加密演算法。
分組加密演算法是將明文分成固定長度的組,每一組都採用同一密鑰和演算法進行加密,輸出也是固定長度的密文。
由IBM公司在1972年研製,1976年被美國聯邦政府的國家標准局確定為聯邦資料處理標准(FIPS),隨後在國際上廣泛流傳開來。
在DES演算法中,密鑰固定長度為64位。明文按64位進行分組,分組後的明文組和密鑰按位置換或交換的方法形成密文組,然後再把密文組拼裝成密文。
密鑰的每個第八位設置為奇偶校驗位,也就是第8、16、24、32、40、48、56、64位,所以密鑰的實際參與加密的長度為56位。
我們用Java寫個例子:
運行結果如下:
DES現在已經不是一種安全的加密方法,主要因為它使用的密鑰過短,很容易被暴力破解。
3DES演算法(Triple Data Encryption Algorithm)是DES演算法的升級版本,相當於是對明文進行了三次DES加密。
由於計算機運算能力的增強,DES演算法由於密鑰長度過低容易被暴力破解;3DES演算法提供了一種相對簡單的方法,即通過增加DES的密鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼演算法。
在DES演算法中,密鑰固定長度為192位。在加密和解密時,密鑰會被分為3個64位的密鑰。
加密過程如下:
解密過程如下:
我們用Java寫個例子:
運行結果如下:
雖然3DES演算法在安全性上有所提升,但是因為使用了3次DES演算法,加密和解密速度比較慢。
AES(Advanced Encryption Standard,高級加密標准)主要是為了取代DES加密演算法的,雖然出現了3DES的加密方法,但由於它的加密時間是DES演算法的3倍多,密鑰位數還是不能滿足對安全性的要求。
1997年1月2號,美國國家標准與技術研究院(NIST)宣布希望徵集高級加密標准,用以取代DES。全世界很多密碼工作者都提交了自己設計的演算法。經過甄選流程,高級加密標准由美國國家標准與技術研究院於2001年11月26日發布於FIPS PUB 197,並在2002年5月26日成為有效的標准。
該演算法為比利時密碼學家Joan Daemen和Vincent Rijmen所設計,結合兩位作者的名字,以 Rijndael 為名投稿高級加密標準的甄選流程。
AES演算法的密鑰長度是固定,密鑰的長度可以使用128位、192位或256位。
AES演算法也是一種分組加密演算法,其分組長度只能是128位。分組後的明文組和密鑰使用幾種不同的方法來執行排列和置換運算形成密文組,然後再把密文組拼裝成密文。
我們用Java寫個例子:
運行結果如下:
AES演算法是目前應用最廣泛的對稱加密演算法。
對稱加密演算法在加密和解密時使用的密鑰相同,常見的對稱加密演算法有:DES演算法、3DES演算法、AES演算法。
由於安全性低、加密解密效率低,DES演算法和3DES演算法是不推薦使用的,AES演算法是目前應用最廣泛的對稱加密演算法。
④ 密碼技術(十一)之密鑰
——秘密的精華
在使用對稱密碼、公鑰密碼、消息認證碼、數字簽名等密碼技術使用,都需要一個稱為 密鑰 的巨大數字。然而,數字本身的大小並不重要,重要的是 密鑰空間的大小 ,也就是可能出現的密鑰的總數量,因為密鑰空間越大,進行暴力破解就越困難。密鑰空間的大小是由 密鑰長度 決定的。
對稱密碼DES的密鑰的實質長度為56比特(7個位元組)。
例如,
一個DES密鑰用二進制可以表示為:
01010001 11101100 01001011 00010010 00111101 01000010 00000011
用十六進制則可以表示為:
51 EC 4B 12 3D 42 03
而用十進制則可以表示為:
2305928028626269955
在對稱密碼三重DES中,包括使用兩個DES密鑰的DES-EDE2和使用三個DES密鑰的DES-EDE3這兩種方式。
DES-EDE2的密鑰長度實質長度為112比特(14位元組),比如:
51 EC 4B 12 3D 42 03 30 04 D8 98 95 93 3F
DES-EDE3的密鑰的實質長度為168比特(21位元組),比如:
51 EC 4B 12 3D 42 03 30 04 D8 98 95 93 3F 24 9F 61 2A 2F D9 96
對稱密碼AES的密鑰長度可以從128、192和256比特中進行選擇,當密鑰長度為256比特時,比如:
51 EC 4B 12 3D 42 03 30 04 D8 98 95 93 3F 24 9F 61 2A 2F D9 96
B9 42 DC FD A0 AE F4 5D 60 51 F1
密鑰和明文是等價的 。假設明文具有100萬的價值,那麼用來加密這段明文的密鑰也就是具有100萬元的價值;如果明文值1億元,密鑰也就值1億元;如果明文的內容是生死攸關的,那麼密鑰也同樣是生死攸關的。
在對稱密碼中,加密和解密使用同一個密鑰。由於發送者和接收者需要共享密鑰,因此對稱密碼又稱為共享密鑰密碼。對稱密碼中所使用的密鑰必須對發送者和接收者以外的人保密,否則第三方就能夠解密了。
在消息認證碼中,發送者和接收者使用共享的密鑰來進行認證。消息認證碼只能由持有合法密鑰的人計算出來。將消息認證碼附加在通信報文後面,就可以識別通信內容是否被篡改或偽裝,由於「持有合法的密鑰」就是發送者和接收者合法身份的證明,因此消息認證碼的密鑰必須對發送者以外的人保密,否則就會產生篡改和偽裝的風險。
在數字簽名中,簽名生成和驗證使用不同的密鑰,只有持有私鑰的本人才能夠生成簽名,但由於驗證簽名使用的是公鑰,因此任何人都能夠驗證簽名。
對稱密碼和公鑰密碼的密鑰都是用於確保機密性的密鑰。如果不知道用於解密的合法密鑰,就無法得知明文的內容。
相對地,消息認證碼和數字簽名所使用的密鑰,則是用於認證的密鑰。如果不知道合法的密鑰,就無法篡改數據,也無法偽裝本人的身份。
當我們訪問以https://開頭的網頁時,Web伺服器和瀏覽器之間會進行基於SSL/TLS的加密通信。在這樣的通信中所使用的密鑰是僅限於本次通信的一次密鑰,下次通信時就不能使用了,想這樣每次通信只能使用一次的密鑰稱為 會話密鑰 。
由於會話密鑰只在本次通信中有效,萬一竊聽者獲取了本次通信的會話密鑰,也只能破譯本次通信的內容。
雖然每次通信都會更換會話密鑰,但如果用來生成密鑰的偽隨機數生成器品質不好,竊聽者就有可能預測出下次生成會話密鑰,這樣就會產生通信內容被破譯的風險。
相對於每次通信更換的會話密鑰,一直被重復使用的密鑰稱為 主密鑰 。
一般來說,加密的對象是用戶直接使用的信息,這樣的情況下所使用的密鑰稱為CEK(Contents Encryting Key,內容加密密鑰);相對地,用於加密密鑰的密鑰則稱為KEK(Key Encryting Key,密鑰加密密鑰)。
在很多情況下,之前提到的會話密鑰都是被作為CEK使用的,而主密鑰則是被作為KEK使用的。
生成密鑰的最好方法就是使用隨機數,因為米喲啊需要具備不易被他人推測的性質。在可能的情況下最好使用能夠生成密碼學上的隨機數的硬體設備,但一般我們都是使用偽隨機數生成器這一專門為密碼學用途設計的軟體。
在生成密鑰時,不能自己隨便寫出一些像「3F 23 52 28 E3....」這樣的數字。因為盡管你想生成的是隨機的數字,但無論如何都無法避免人為偏差,而這就會成為攻擊者的目標。
盡管生成偽隨機數的演算法有很多種,但密碼學用途偽隨機生成器必須是專門針對密碼學用途而設計的。例如,有一些偽隨機數生成器可以用於游戲和模擬演算法,盡管這些偽隨機數生成器所生成的數列看起也是隨機的,但只要不是專門為密碼學用途設計的,就不能用來生成密鑰,因為這些偽隨機數生成器不具備不可預測性這一性質。
有時候我們也會使用人類的可以記住的口令(pasword或passphrase)來生成密鑰。口令指的是一種由多個單片語成的較長的password。
嚴格來說,我們很少直接使用口令來作為密鑰使用,一般都是將口令輸入單向散列函數,然後將得到的散列值作為密鑰使用。
在使用口令生成密鑰時,為了防止字典攻擊,需要在口令上附加一串稱為鹽(salt)的隨機數,然後在將其輸入單向散列函數。這種方法稱為「基於口令的密碼(Password Based Encryption,PBE)」。
在使用對稱密碼時,如何在發送者和接收者之間共享密鑰是一個重要的問題,要解決密鑰配送問題,可以採用事先共享密鑰,使用密鑰分配中心,使用公鑰密碼等方法,除了上述方法,之前還提到一種解決密鑰配送的問題的方法稱為Diffie-Hellman密鑰交換。
有一種提供通信機密性的技術稱為 密鑰更新 (key updating),這種方法就是在使用共享密鑰進行通信的過程中,定期更改密鑰。當然,發送者和接收者必須同時用同樣的方法來改變密鑰才行。
在更新密鑰時,發送者和接收者使用單向散列函數計算當前密鑰的散列值,並將這個散列值用作新的密鑰。簡單說,就是 用當前密鑰散列值作為下一個密鑰 。
我們假設在通信過程中的某個時間點上,密鑰被竊聽者獲取了,那麼竊聽者就可以用這個密鑰將之後的通信內容全部解密。但是,竊聽者卻無法解密更新密鑰這個時間點之前的內容,因為這需要用單向散列函數的輸出反算出單向散列函數的輸入。由於單向散列函數具有單向性,因此就保證了這樣的反算是非常困難的。
這種防止破譯過去的通信內容機制,稱為 後向安全 (backward security)。
由於會話密鑰在通信過程中僅限於一次,因此我們不需要保存這種秘密。然而,當密鑰需要重復使用時,就必須要考慮保存密鑰的問題了。
人類是 無法記住具有實用長度的密鑰 的。例如,像下面這樣一個AES的128比特的密鑰,一般人是很難記住的。
51 EC 4B 12 3D 42 03 30 04 DB 98 95 93 3F 24 9F
就算勉強記住了,也只過不是記住一個密鑰而已。但如果要記住多個像這樣的密鑰並且保證不忘記,實際上是非常困難的。
我們記不住密鑰,但如果將密鑰保存下來又可能會被竊取。這真是一個頭疼的問題。這個問題很難得到徹底解決,但我們可以考慮一些合理的解決方法。
將密鑰保存生文件,並將這個文件保存在保險櫃等安全地方。但是放在保險櫃里的話,出門就無法使用了。這種情況,出門時就需要隨身攜帶密鑰。而如果將密鑰放在存儲卡隨身攜帶的話,就會產生存儲卡丟失、被盜等風險。
萬一密鑰被盜,為了能夠讓攻擊者花更多的時間才能真正使用這個密鑰,我們可以使用將密鑰加密後保存的方法,當然,要將密鑰加密,必須需要另一個密鑰。像這樣用於密碼加密的密鑰,一般稱為KEK。
對密鑰進行加密的方法雖然沒有完全解決機密性的問題,但在現實中卻是一個非常有效地方法,因為這樣做可以減少需要保管密鑰的數量。
假設計算機上有100萬個文件,分別使用不同的密鑰進行加密生成100萬個密文,結果我們手上就產生了100萬個密鑰,而要保管100萬個密鑰是很困難的。
於是,我們用一個密鑰(KEK)將這100萬個密鑰進行加密,那麼現在我們只要保管者一個KEK就可以了,這一個KEK的價值相當於簽名的100萬個密鑰的價值的總和。
用1個密鑰來代替多個密鑰進行保管的方法,和認證機構的層級化非常相似。在後者中,我們不需要信任多個認證機構,而只需要信任一個根CA就可以了。同樣的,我們也不需要確保多個密鑰的機密性,而只需要確保一個KEK的機密性就可以了。
密鑰的作廢和生成是同等重要的,這是因為密鑰和明文是等價的。
假設Alice向Bob發送了一封加密郵件。Bob在解密之後閱讀了郵件的內容,這時本次通信所使用的密鑰對於Alice和Bob來說就不需要了。不在需要的密鑰必須妥善刪除,因為如果被竊聽者Eve獲取,之前發送的加密郵件就會被解密。
如果密鑰是計算機上的一個文件,那麼僅僅刪除這個文件是不足以刪除密鑰的,因為有一些技術能夠讓刪除的文件「恢復」。此外,很多情況下文件的內容還會殘留在計算機的內存中,因此必須將這些痕跡完全抹去。簡而言之,要完全刪除密鑰,不但要用到密碼軟體,還需要在設計計算機系統時對信息安全進行充分的考慮
如果包含密鑰的文件被誤刪或者保管密鑰的筆記本電腦損壞了,會怎麼樣?
如果丟失了對稱密鑰密碼的共享密鑰,就無法解密密文了。如果丟失了消息認證碼的密鑰,就無法向通信對象證明自己的身份了。
公鑰密碼中,一般不太會發送丟失公鑰的情況,因為公鑰是完全公開的,很有可能在其他電腦上存在副本。
最大的問題是丟失公鑰密碼的私鑰。如果丟失了公鑰密碼的私鑰,就無法解密用公鑰密碼加密的密文了。此外,如果丟失了數字簽名的私鑰,就無法生成數字簽名了。
Diffie-Hellman密鑰交換(Diffie-Hellman key exchange)是1976年由Whitfield Diffie和Martin Hellman共同發明的一種演算法。使用這種演算法,通信雙方僅通過交換一些可以公開的信息就能夠生成共享秘密數字,而這一秘密數字就可以被用作對稱密碼的密鑰。IPsec 中就使用了經過改良的Diffie-Hellman密鑰交換。
2 Alice 生成一個隨機數A
A是一個1 ~ P-2之間的整數。這個數是一個只有Alice知道的密碼數字,沒有必要告訴Bob,也不能讓Eve知道。
Alice計算出的密鑰=Bob計算出的密鑰
在步驟1-7中,雙方交換數字一共有4個,P、G、G A mod P 和 G B mod P。根據這4個數字計算出Alice和Bob的共享密鑰是非常困難的。
如果Eve能歐知道A和B的任意一個數,那麼計算G A*B 就很容易了,然而僅僅根據上面的4個數字很難求出A和B的。
根據G A mod P 計算出A的有效演算法到現在還沒有出現,這問題成為有限域(finite field) 的 離散對數問題 。
Diffie-Hellman密鑰交換是利用了「離散對數問題」的復雜度來實現密鑰的安全交換的,如果將「離散對數問題」改為「橢圓曲線上離散對數問題」,這樣的演算法就稱為 橢圓曲線Diffie-Hellman 密鑰交換。
橢圓曲線Diffie-Hellman密鑰交換在總體流程上是不變的,只是所利用的數學問題不同而已。橢圓曲線Diffie-Hellman密鑰交換能夠用較短的密鑰長度實現較高的安全性。
基於口令密碼(password based encryption,PBE)就是一種根據口令生成密鑰並用該密鑰進行加密的方法。其中加密和解密使用同一個密鑰。
PBE有很多種實現方法。例如RFC2898和RFC7292 等規范中所描述的PBE就通過Java的javax.crypto包等進行了實現。此外,在通過密碼軟體PGP保存密鑰時,也會使用PBE。
PBE的意義可以按照下面的邏輯來理解。
想確保重要消息的機制性。
↓
將消息直接保存到磁碟上的話,可能被別人看到。
↓
用密鑰(CEK)對消息進行加密吧。
↓
但是這次又需要確保密鑰(CEK)的機密性了。
↓
將密鑰(CEK)直接保存在磁碟上好像很危險。
↓
用另一個密鑰(KEK)對密鑰進行加密(CEK)吧。
↓
等等!這次又需要確保密鑰(KEK)的機密性了。進入死循環了。
↓
既然如此,那就用口令來生成密鑰(KEK)吧。
↓
但只用口令容易遭到字典攻擊
↓
那麼就用口令和鹽共同生成密鑰(KEK)吧。
↓
鹽可以和加密後的密鑰(CEK)一切保存在磁碟上,而密鑰(KEK)可以直接丟棄。
↓
口令就記在自己的腦子里吧。
PBE加密包括下列3個步驟:
鹽是由偽隨機數生成器生成的隨機數,在生成密鑰(KEK)時會和口令一起被輸入單向散列函數。
密鑰(KEK)是根據秘密的口令生成的,加鹽好像沒有什麼意義,那麼鹽到底起到什麼作用呢?
鹽是用來防禦字典攻擊的 。字典攻擊是一種事先進行計算並准備好候選密鑰列表的方法。
我們假設在生成KEK的時候沒有加鹽。那麼主動攻擊者Mallory就可以根據字典數據事先生成大量的候選KEK。
在這里,事先是很重要的一點。這意味著Mallory可以在竊取到加密會話的密鑰之前,就准備好了大量的候選KEK。當Mallory竊取加密的會話密鑰後,就需要嘗試將它解密,這是准備好了大量事先生成的候選KEK,就能夠大幅度縮短嘗試的時間,這就是 字典攻擊 (dictionary attack)。
如果在生成KEK時加鹽,則鹽的長度越大,候選KEK的數量也會隨之增大,事先生成的的候選KEK就會變得非常困難。只要Mallory還沒有得到鹽,就無法生成候選KEK。這是因為加鹽之後,候選KEK的數量會變得非常巨大。
具有充足長度的密鑰是無法用人腦記憶的。口令也是一樣,我們也無法記住具有充足比特數的口令。
在PBE中,我們通過口令生成密鑰(KEK),在用這個密鑰來加密會話密鑰(CEK)。由於通過口令生成的密鑰(KEK)強度不如由偽隨機數生成器生成的會話密鑰(CEK),這就好像是將一個牢固的保險櫃的鑰匙放在了一個不怎麼牢固的保險櫃保管,因此在使用基於口令的密鑰時,需要將鹽和加密後的CEK通過物理方法進行保護。例如將鹽和加密後的CEK保存到存儲卡隨身攜帶。
在生成KEK時,通過多次使用單向散列函數就可以提高安全性。例如,將鹽和口令輸入單向散列函數,進行1000次的散列函數所得到的散列值作為KEK來使用,是一個不錯的方法。
像這樣將單向散列函數進行多次迭代的方法稱為 拉伸 (stretching)。
該系列的主要內容來自《圖解密碼技術第三版》
我只是知識的搬運工
文章中的插圖來源於原著
⑤ 04.現代常見分組加密演算法
1.Triple DES
2.IDEA
3.RC6
4.RC6
5.ASE
其實就是有3個密鑰k1,k2,k3,如果m表示明文,C表示密文,他們是這樣操作的:
DES1(m)=>C1
DES2(C1)=>C2
DES3(C3)=>C3
DES密鑰太短是其短板,3DES密鑰長度為k1+k2+k3 = 56*3 = 168bit
既然都Triple自然就有double,為什麼不用Double DES呢?
我們先來看下double des:
首先根據DESC密鑰太短的特點,的確是有了double desc,可用中間相遇攻擊破解(老師坑爹沒講什麼是中間相遇攻擊,日後補上),經過加密有2^64個可能的密文,密鑰長度為112bit(56+56),所以選擇密鑰的可能性達到2^112,於是對給定一個明文P加密成密文有2^112/2^64 = 2^48種可能,對於給定兩個明文密文對,虛警率降為2^(46-64)=2^-16,用中間相遇攻擊大概可用2^57 可暴力破解
那麼如何解決中間相遇攻擊呢?於是設計出了Triple des,它一共有四種模式:
1.DES-EEE3:3個不同的密鑰,順序用三次加密演算法
2.DES-EDE3:3個不同的密鑰, 加密-解密-加密
3.DES-EEE2:兩個不同的密鑰,k1,k2,k1,依次k1加密,k2加密,k1加密
4.DES-EDE2:兩個不同的密鑰,k1,k2,k1,依次k1加密,k2解密,k1加密
這里我們著重介紹第四種,DES-EDE2
同DES相比有如下特點:
1.3DES安全性高,密鑰長度大於DES
2.3DES可抵抗中間相遇攻擊
3.可向下兼容,我們設k2=k1,則密鑰均為k1,上圖中A過程加密後在B過程解密,最後在C過程又加密,相當於僅用k1加密一次,兼容了DES,解密同理
4.相比於DES效率低些
要求:1.效率比3DES高
2.至少和3DES一樣安全,數據分組長度128bit
它有如下特點:
1.不屬於Feistel結構,屬於SP網路
2.加密,解密相似但不對稱
3.支持128/32=Nb數據塊大小
4.支持128/192/256(/32=Nk)密鑰長度
5.結構簡單速度快
什麼是Feistel結構?
Feistel 的優點在於:由於它是對稱的密碼結構,所以對信息的加密和解密的過程就極為相似,甚至完全一樣。這就使得在實施的過程中,對編碼量和線路傳輸的要求就減少了幾乎一半
什麼是SP網路結構?
在這種密碼的每一輪中,輪輸入首先被一個由子密鑰控制的可逆函數S作用,然後再對所得結果用置換(或可逆線性變換)P作用,S和P分別被稱為混亂層和擴散層,主要起混亂和擴散作用
通過置換和替換迭代加密(最後一輪沒有列混淆)
⑥ 下面哪種演算法不需要密鑰1.Aes2.Rsa3,Rca4,Md5
是md5,它是一種簽名演算法,MD5碼以512位分組來處理輸入的信息,且每一分組又被劃分為16個32位子分組,經過了一系列的處理後,演算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位散列值。