JAVA基礎◆淺談3DES加密解密


淺談3DES加密解密
 
(注:本文不深入探討3DES的加密原理,只着重說明在Java中使用3DES加密解密以及常見問題)
 
 
 
從數據安全談起

 
    當你使用網銀時,是否擔心你的銀行卡會被盜用?
    當你和朋友用QQ進行聊天時,是否擔心你的隱私會被泄露?
    作為開發者,編寫安全的代碼比編寫優雅的代碼更重要,因為安全是一切應用之根本!為了確保數據不被侵犯,數據加密/解密技術運用而生。    ——摘錄自《Java加密解密的藝術》
 
    所以為了確保數據傳輸和數據存儲的安全,我們可以通過特定的算法,將數據明文加密成復雜的密文。
    眾多的加密手段大致可以分為單項加密和雙向加密。單項加密指通過對數據進行摘要計算生成密文,密文不可逆推還原,比如有Base64、MD5、SHA等;雙向加密則相反,指可以把密文逆推還原成明文,其中雙向加密又分為對稱加密和非對稱加密。對稱加密是指數據使用者必須擁有同樣的密鑰才可以進行加密解密,就像大家共同約定了一組暗號一樣,對稱加密的手段有DES、3DES、AES、IDEA、RC4、RC5等;而非對稱加密相對於對稱加密而言,無需擁有同一組密鑰,它是一種“信息公開的密鑰交換協議”。非對稱加密需要公開密鑰和私有密鑰兩組密鑰,公開密鑰和私有密鑰是配對起來的,也就是說使用公開密鑰進行數據加密,只有對應的私有密鑰才能進行解密。此類的加密手段有RSA、DSA等。
                                                                                            
【密碼學常用術語】
    明文:未加密的數據
    密文:明文經過加密后的數據
    加密:將明文轉換為密文的過程
    解密:將密文轉換為明文的過程    
    加密算法:將明文轉換為密文的轉換算法        
    解密算法:將密文轉換為明文的轉換算法
    加密密鑰:用於加密算法進行加密操作的密鑰
    解密密鑰:用於解密算法進行解密操作的密鑰
    
 
 
初識3DES

    3DES,也稱為3DESede或TripleDES,是三重數據加密,且可以逆推的一種算法方案。
    1975年美國IBM公司成功研究並發布了DES加密算法,但DES密碼長度容易被暴力破解,通過對DES算法進行改進,針對每個數據塊進行三次DES加密,也就是3DES加密算法。
    但由於3DES的算法是公開的,所以算法本身沒什么秘密可言,主要依靠唯一密鑰來確保數據加密解密的安全。
    有人可能會問,那3DES到底安不安全呢?!目前為止,還沒有人能破解3DES,所以你要是能破解它,都足以震驚整個信息安全界了……
 
【Java使用3DES加密解密的流程】
     ①傳入共同約定的密鑰(keyBytes)以及算法(Algorithm),來構建SecretKey密鑰對象
         SecretKey deskey = new SecretKeySpec(keyBytesAlgorithm);    
     ②根據算法實例化Cipher對象。它負責加密/解密
        Cipher c1 = Cipher.getInstance(Algorithm);    
     ③傳入加密/解密模式以及SecretKey密鑰對象,實例化Cipher對象
        c1.init(Cipher.ENCRYPT_MODE, deskey);    
     ④傳入字節數組,調用Cipher.doFinal()方法,實現加密/解密,並返回一個byte字節數組
        c1.doFinal(src);
 
 
 
3DES案例

 
—SecretUtils.java(3DES加密解密的工具類)—
 1 package my3des;
 2  
 3 import java.io.UnsupportedEncodingException;
 4  
 5 import javax.crypto.Cipher;
 6 import javax.crypto.SecretKey;
 7 import javax.crypto.spec.SecretKeySpec;
 8  
 9  
10 /**
11  * SecretUtils {3DES加密解密的工具類 }
12  * @author William
13  * @date 2013-04-19
14  */
15 public class SecretUtils {
16  
17     //定義加密算法,有DES、DESede(即3DES)、Blowfish
18     private static final String Algorithm = "DESede";    
19     private static final String PASSWORD_CRYPT_KEY = "2012PinganVitality075522628888ForShenZhenBelter075561869839";
20     
21     
22     /**
23      * 加密方法
24      * @param src 源數據的字節數組
25      * @return 
26      */
27     public static byte[] encryptMode(byte[] src) {
28         try {
29              SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);    //生成密鑰
30              Cipher c1 = Cipher.getInstance(Algorithm);    //實例化負責加密/解密的Cipher工具類
31              c1.init(Cipher.ENCRYPT_MODE, deskey);    //初始化為加密模式
32              return c1.doFinal(src);
33          } catch (java.security.NoSuchAlgorithmException e1) {
34              e1.printStackTrace();
35          } catch (javax.crypto.NoSuchPaddingException e2) {
36              e2.printStackTrace();
37          } catch (java.lang.Exception e3) {
38              e3.printStackTrace();
39          }
40          return null;
41      }
42     
43     
44     /**
45      * 解密函數
46      * @param src 密文的字節數組
47      * @return
48      */
49     public static byte[] decryptMode(byte[] src) {      
50         try {
51             SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);
52             Cipher c1 = Cipher.getInstance(Algorithm);
53             c1.init(Cipher.DECRYPT_MODE, deskey);    //初始化為解密模式
54             return c1.doFinal(src);
55         } catch (java.security.NoSuchAlgorithmException e1) {
56             e1.printStackTrace();
57         } catch (javax.crypto.NoSuchPaddingException e2) {
58             e2.printStackTrace();
59         } catch (java.lang.Exception e3) {
60             e3.printStackTrace();
61         }
62         return null;
63      }
64     
65     
66     /*
67      * 根據字符串生成密鑰字節數組 
68      * @param keyStr 密鑰字符串
69      * @return 
70      * @throws UnsupportedEncodingException
71      */
72     public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException{
73         byte[] key = new byte[24];    //聲明一個24位的字節數組,默認里面都是0
74         byte[] temp = keyStr.getBytes("UTF-8");    //將字符串轉成字節數組
75         
76         /*
77          * 執行數組拷貝
78          * System.arraycopy(源數組,從源數組哪里開始拷貝,目標數組,拷貝多少位)
79          */
80         if(key.length > temp.length){
81             //如果temp不夠24位,則拷貝temp數組整個長度的內容到key數組中
82             System.arraycopy(temp, 0, key, 0, temp.length);
83         }else{
84             //如果temp大於24位,則拷貝temp數組24個長度的內容到key數組中
85             System.arraycopy(temp, 0, key, 0, key.length);
86         }
87         return key;
88     } 
89 }

 

—Main.java(測試類)—
 1 package my3des;
 2  
 3 public class Main {
 4  
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         String msg = "3DES加密解密案例";
10         System.out.println("【加密前】:" + msg);
11         
12         //加密
13         byte[] secretArr = SecretUtils.encryptMode(msg.getBytes());    
14         System.out.println("【加密后】:" + new String(secretArr));
15         
16         //解密
17         byte[] myMsgArr = SecretUtils.decryptMode(secretArr);  
18         System.out.println("【解密后】:" + new String(myMsgArr));
19     }
20 }

 

 
 
補充說明

· 3DES的密鑰必須是24位的byte數組
    隨便拿一個String.getBytes()是不行的,會報如下錯誤
         java.security.InvalidKeyException: Invalid key length: 59 bytes
    解決方法有很多,①按密鑰固定長度重新定義字符串;②先把字符串用Base64或者MD5加密,然后截取固定長度的字符轉成byte數組;③字符串轉成Byte數組,針對該數組進行修改,若長度過長則只截取一部分,若長度不夠則補零
 
· 加密結果的編碼方式要一致
    從byte數組轉成字符串,一般有兩種方式,base64處理和十六進制處理。
    
· 參考資料
    3DES在線測試工具: http://www.seacha.com/tools/3des.php
 
 


免責聲明!

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



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