Java 加解密技術系列之 DES
阿新 • • 發佈:2019-02-03
序
前幾篇文章講的都是單向加密演算法,其中涉及到了 BASE64、MD5、SHA、HMAC 等幾個比較常見的加解密演算法。這篇文章,以及後面幾篇,打算介紹幾個對稱加密演算法,比如:DES、3DES(TripleDES)、AES 等。那麼,這篇文章主要是對 DES 大概講一下。背景
在討論 DES 之前,首先了解一下什麼是對稱加密演算法吧。對於對稱加密演算法,他應用的時間比較早,技術相對來說比較成熟,在對稱加密演算法中,資料發信方將明文(原始資料)和加密金鑰一起經過特殊加密演算法處理後,使其變成複雜的加密密文傳送出去。收信方收到密文後,若想解讀原文,則需要使用加密用過的金鑰及相同演算法的逆演算法對密文進行解密,才能使其恢復成可讀明文。在對稱加密演算法中,使用的金鑰只有一個,發收信雙方都使用這個金鑰對資料進行加密和解密,這就要求解密方事先必須知道加密金鑰。對稱加密演算法的特點是演算法公開、計算量小。不足之處是,交易雙方都使用同樣鑰匙,安全性得不到保證。
概念
那麼,什麼是 DES?他是怎麼來的?相信很多人都很感興趣,因為以前在開發的時候,對進度的要求比較嚴,很多時候根本就沒有時間來了解這些東西。因此,今天專門來研究研究這個東西。 DES,全稱為“Data Encryption Standard”,中文名為“資料加密標準”,是一種使用金鑰加密的塊演算法。DES 演算法為密碼體制中的對稱密碼體制,又被稱為美國資料加密標準,是 1972 年美國 IBM 公司研製的對稱密碼體制加密演算法。 明文按 64 位進行分組,金鑰長 64 位,金鑰事實上是 56 位參與 DES 運算(第8、16、24、32、40、48、56、64 位是校驗位, 使得每個金鑰都有奇數個 1)分組後的明文組和 56 位的金鑰按位替代或交換的方法形成密文組的加密方法。基本原理
主要流程
DES 演算法把 64 位的明文輸入塊變為 64 位的密文輸出塊,它所使用的金鑰也是 64 位,其演算法主要分為兩步:- 初始置換
- 逆置換
分組模式
- ECB模式
- CBC模式
- CFB模式
- OFB模式
- CTR模式
程式碼實現
<span style="font-family:Comic Sans MS;"><span style="font-size:12px;">package com.sica.des;
import com.google.common.base.Strings;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
/**
* Created by xiang.li on 2015/2/28.
* DES 加解密工具類
*
* <pre>
* 支援 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
* DES key size must be equal to 56
* DESede(TripleDES) key size must be equal to 112 or 168
* AES key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
* Blowfish key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
* RC2 key size must be between 40 and 1024 bits
* RC4(ARCFOUR) key size must be between 40 and 1024 bits
* 具體內容 需要關注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
* </pre>
*/
public class DES {
/**
* 定義加密方式
*/
private final static String KEY_DES = "DES";
private final static String KEY_AES = "AES"; // 測試
/**
* 全域性陣列
*/
private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
/**
* 初始化金鑰
* @return
*/
public static String init() {
return init(null);
}
/**
* 初始化金鑰
* @param seed 初始化引數
* @return
*/
public static String init(String seed) {
SecureRandom secure = null;
String str = "";
try {
if (null != secure) {
// 帶引數的初始化
secure = new SecureRandom(decryptBase64(seed));
} else {
// 不帶引數的初始化
secure = new SecureRandom();
}
KeyGenerator generator = KeyGenerator.getInstance(KEY_DES);
generator.init(secure);
SecretKey key = generator.generateKey();
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
/**
* 轉換金鑰
* @param key 金鑰的位元組陣列
* @return
*/
private static Key byteToKey(byte[] key) {
SecretKey secretKey = null;
try {
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DES);
secretKey = factory.generateSecret(dks);
// 當使用其他對稱加密演算法時,如AES、Blowfish等演算法時,用下述程式碼替換上述三行程式碼
// secretKey = new SecretKeySpec(key, KEY_DES);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return secretKey;
}
/**
* DES 解密
* @param data 需要解密的字串
* @param key 金鑰
* @return
*/
public static String decryptDES(String data, String key) {
// 驗證傳入的字串
if (Strings.isNullOrEmpty(data)) {
return "";
}
// 呼叫解密方法完成解密
byte[] bytes = decryptDES(hexString2Bytes(data), key);
// 將得到的位元組陣列變成字串返回
return new String(bytes);
}
/**
* DES 解密
* @param data 需要解密的位元組陣列
* @param key 金鑰
* @return
*/
public static byte[] decryptDES(byte[] data, String key) {
byte[] bytes = null;
try {
Key k = byteToKey(decryptBase64(key));
Cipher cipher = Cipher.getInstance(KEY_DES);
cipher.init(Cipher.DECRYPT_MODE, k);
bytes = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
/**
* DES 加密
* @param data 需要加密的字串
* @param key 金鑰
* @return
*/
public static String encryptDES(String data, String key) {
// 驗證傳入的字串
if (Strings.isNullOrEmpty(data)) {
return "";
}
// 呼叫加密方法完成加密
byte[] bytes = encryptDES(data.getBytes(), key);
// 將得到的位元組陣列變成字串返回
return byteArrayToHexString(bytes);
}
/**
* DES 加密
* @param data 需要加密的位元組陣列
* @param key 金鑰
* @return
*/
public static byte[] encryptDES(byte[] data, String key) {
byte[] bytes = null;
try {
Key k = byteToKey(decryptBase64(key));
Cipher cipher = Cipher.getInstance(KEY_DES);
cipher.init(Cipher.ENCRYPT_MODE, k);
bytes = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
/**
* BASE64 解密
* @param key 需要解密的字串
* @return 位元組陣列
* @throws Exception
*/
public static byte[] decryptBase64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
/**
* BASE64 加密
* @param key 需要加密的位元組陣列
* @return 字串
* @throws Exception
*/
public static String encryptBase64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
/**
* 將一個位元組轉化成十六進位制形式的字串
* @param b 位元組陣列
* @return 字串
*/
private static String byteToHexString(byte b) {
int ret = b;
//System.out.println("ret = " + ret);
if (ret < 0) {
ret += 256;
}
int m = ret / 16;
int n = ret % 16;
return hexDigits[m] + hexDigits[n];
}
/**
* 轉換位元組陣列為十六進位制字串
* @param bytes 位元組陣列
* @return 十六進位制字串
*/
private static String byteArrayToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
sb.append(byteToHexString(bytes[i]));
}
return sb.toString();
}
/**
* 轉換十六進位制字串為位元組陣列
* @param hexstr 十六進位制字串
* @return
*/
public static byte[] hexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
/**
* 轉換字元型別資料為整型資料
* @param c 字元
* @return
*/
private static int parse(char c) {
if (c >= 'a')
return (c - 'a' + 10) & 0x0f;
if (c >= 'A')
return (c - 'A' + 10) & 0x0f;
return (c - '0') & 0x0f;
}
/**
* 測試方法
* @param args
*/
public static void main(String[] args) {
String key = DES.init();
System.out.println("DES金鑰:\n" + key);
String word = "123";
String encWord = encryptDES(word, key);
System.out.println(word + "\n加密後:\n" + encWord);
System.out.println(word + "\n解密後:\n" + decryptDES(encWord, key));
}
}</span><span style="font-size: 14px;">
</span></span>