Java加密與解密筆記(一) Base64和數據摘要算法


對加密解密下面的內容一定要先理解:

甲乙雙方要通信,中間的連接可能被人竊聽甚至篡改。解決辦法就是把傳輸的內容進行加密,用密文去傳輸,這樣即使被監聽也沒辦法知道信息的具體內容。

加密時,甲乙雙方可以約定一個密碼A,甲用A加密,乙用A解密,這就是對稱加密。對稱加密的一個問題是:密鑰怎么傳遞給對方?

貌似沒解,於是就出現了非對稱加密,非對稱加密時有兩個密鑰,就是公鑰也私鑰。用公鑰加密的只能用私鑰解密,反之用私鑰加密的則只能用公鑰解密。這樣在流程上有點兒變化了。

原先在對稱加密中,密鑰沒法傳遞,現在好了,密鑰不用傳遞,因為公鑰是公開的,誰都可以拿到。流程如下:

  1. 甲要給乙發送信息,那么甲需要知道乙的公鑰;
  2. 甲用乙的公鑰進行加密,將數據傳遞給乙;
  3. 乙用自己的私鑰進行解密,從而獲得數據

過程中:

  1. 如果有人竊聽到了數據,因為這個人沒有乙的私鑰,所以沒法解密,所以查看不到數據內容;
  2. 如果有人想篡改數據呢?答案也做不到,因為連甲發的什么內容都不知道所以就談不上篡改了。

這里有點兒要注意的細節是,甲要發送數據時,不是自己造公鑰,而是問接收方要公鑰。

 

上述過程中還漏掉了一個問題:雖然篡改不了問題,那我總可以冒名發數據吧?

因為乙的公鑰是公開的,那我就可以拿着乙的公鑰給乙想發什么就發什么?

乙怎么知道數據甲發過來的呢?答案是用數字簽名來驗證。

非對稱加密RSA就支持數字簽名,流程是:

  1. 甲用自己的私鑰個數據生成一個簽名;
  2. 甲在給乙發送數據的時候,把簽名也一並發送過去;
  3. 乙在收到數據的時候,用甲公布的公鑰來驗證接收到的簽名;

 總的來說,對應於安全問題的解決辦法如下:

  1. 數據完整性問題:數據摘要驗證
  2. 數據保密性問題:對稱加密&非對稱加密
  3. 身份驗證問題:數字簽名

簡單數據轉換

Base64

將數據轉換為不便於識別的數據算是一種最簡單的加密了,比如Base64編碼:

public class Base64Util {
    
    public static void main(String[] args) throws Exception{
        
        
        String str = "Hello";
        byte[] bytes = str.getBytes();
        String encodedStr = encode(bytes);
        System.out.println(encodedStr);
        
        byte[] decodedBytes = decode(encodedStr);
        System.out.println(new String(decodedBytes));
        
    }
    
    public static String encode(byte[] bytes){
        return new BASE64Encoder().encode(bytes);
    }
    
    public static byte[] decode(String encodeStr) throws IOException{
        return new BASE64Decoder().decodeBuffer(encodeStr);
    }

}

Java8內置Base64的實現,可以通過java.util.Base64工具類來使用。

輸出如下:

SGVsbG8=

Hello

這種編碼是可逆的,因此加密的數據越長,則得到的結果越長,因為數據中存儲了所有原始數據的細節。另外一些,比如MD5算法,是不可逆的,則屬於內容摘要,多長的數據拿過來,最終得到的摘要結果長度都是一樣的。因為這個特性所以經常用於校驗文件是否被修改過。

數據摘要算法

MD5

public class MD5Util {

    public static void main(String[] args) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        String pwd = "a";
        
        byte[] md5Bytes = md.digest(pwd.getBytes("UTF-8"));
        System.out.println(new String(Hex.encode(md5Bytes)));
        System.out.println(Base64Util.encode(md5Bytes));
        
        
    }
}

MD5一般和Base64配合使用,用來加密得到固定長度的Base64碼。如果不用Base64編碼,Spring的Hex對MD5數據進行了友好的輸出。

 MD是Message Digest Algorithm的簡稱,中文名消息摘要算法,目前最新為第五版即MD5,歷史版本有MD4、MD2等,由於存在缺陷都已不再使用。消息摘要算法各個版本間的結果是不一樣的。

MD2算法產生於1989年;
MD4算法產生於1990年;
MD5算法產生於1991年。

MD5是目前廣泛使用的版本,不過其安全性多年前就開始被質疑(碰撞算法)。於是在2008年提出了MD6算法,其后MD6歷經數次改進,目前還是試行方案階段,未被正式使用。

另外,從JDK的API來看,除了MDx家族外,還有其他一些消息摘要算法:

 SHA

SHA的全稱叫安全散列算法(Secure Hash Algorithm),它是比MD5更安全消息摘要算法。

public class SHAUtil {
    public static void main(String[] args) throws Exception{
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        String str = "Hello";
        String str2 = Base64Util.encode(md.digest(str.getBytes()));
        System.out.println(str2);
    }
}

HMAC 

 HMAC的全稱是哈希消息認證碼(Hash Message Authentication Code)。個人覺得,所有的消息摘要無非是要做數據驗證。一個重要的例子,我們不會在數據庫中保存明文的用戶密碼,而保存密碼的摘要。因為摘要算法是透明的,那么為了防止撞庫,就需要在摘要時“加鹽”。所加的鹽其實也是有講究的,隨機數?當期系統時間?其實都很容易被猜測。HMAC正是來解決這個問題的。它不管具體的消息摘要是怎樣的,既可以用MD5也可以用SHA。它關注的是怎樣生成這個隨機的鹽,也就是密鑰。在HMAC中,摘要時是需要秘鑰的,從而保證了摘要的隱蔽性,因此不容易被撞庫。

public class HMACUtil {

    public static void main(String[] args) throws Exception {
        
        String data = "Hello";
        String key = getKey();
        System.out.println("key:" + key);
        
        String mac = encryptHmac(key.getBytes(), data.getBytes());
        System.out.println(mac);
        
        System.out.println(encryptHmac(key.getBytes(), "Hello2".getBytes()));
        
    }
    
    public static String getKey()throws Exception{
        KeyGenerator generator = KeyGenerator.getInstance("HmacMD5");
        SecretKey key = generator.generateKey();
        byte[] bytes = key.getEncoded();
        return Base64Util.encode(bytes);
    }
    
    public static String encryptHmac(byte[] key,byte[] data)throws Exception{
        SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");
        Mac mac = Mac.getInstance("HmacMD5");
        mac.init(secretKey);
        
        byte[] resultBytes = mac.doFinal(data);
        String resultString = Base64Util.encode(resultBytes);
        return resultString;
    }
}

 HMAC可用的摘要算法名稱:

加密解密領域到處都有“秘鑰”(Key),索性JDK自己實現了生成很多算法的秘鑰的方法(KeyGenerator ),這些算法包括:

 

其他相關文章:
 
 

 參考資料:

http://snowolf.iteye.com/blog/379860

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM