1.簡介
對稱密鑰算法(英語:Symmetric-key algorithm)又稱為對稱加密、私鑰加密、共享密鑰加密,是密碼學中的一類加密算法。這類算法在加密和解密時使用相同的密鑰,或是使用兩個可以簡單地互相推算的密鑰。事實上,這組密鑰成為在兩個或多個成員間的共同秘密,以便維持專屬的通信聯系。與公開密鑰加密相比,要求雙方擷取相同的密鑰是對稱密鑰加密的主要缺點之一。
常見的對稱加密算法有AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。對稱加密的速度比公鑰加密快很多,在很多場合都需要對稱加密。
- 對稱加密算法消息傳遞圖示

2. 對稱密鑰算法--DES
DES算法在98年之後不斷的被破解,當下DES的加密已經不具備安全性了,是以現在一個新項目或者沒有使用過加密算法的應用,在加密算法選型的時候不用考慮DES算法。DES目前隻出現在一些介紹、案例或者一些遺留的軟體或者硬體中。
在這裡介紹下DES算法,因為DES在加密算法(尤其是對稱加密算法)中的地位是非常高的。
DES(Data Encryption Standard)資料加密标準
密鑰長度 | 預設 | 工作模式 | 填充方式 | 實作方 |
56 | 56 | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128 | NoPadding、 PKCS5Padding、 ISO10126Padding | JDK |
64 | 56 | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128 | PKCS7Padding、 SO10126d2Padding、 X032Padding、 ISO7816d4Padding、 ZeroBytePadding | Bouncy Castle |
DES加密示例:
package com.bity.des;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import static java.lang.System.*;
/**
* <p>Title: JdkDes</p >
* <p>Description: DES加密算法 </p >
* <p>Company: http://www.agree.com</p >
* <p>Project: security</p >
*
* @author <a href="mailto:[email protected]">WEIQI</a>
* @version 1.0
* @date 2022-04-26 20:21
*/
public class JdkDes {
private static final String SRC = "I'm DES encryption algorithm";
public static void main(String[] args) {
jdkDes();
}
/**
* JDK-DES對稱密鑰算法實作
*
* @author: <a href="mailto:[email protected]">WEIQI</a>
* @date: 2022-04-26 20:41
*/
private static void jdkDes() {
try {
// generator KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(56);
SecretKey secretKey = keyGenerator.generateKey();
byte[] bytesKey = secretKey.getEncoded();
// convert KEY
DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
Key convertSecureKey = secretKeyFactory.generateSecret(desKeySpec);
// encryption
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, convertSecureKey);
byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
out.println("encryption result is : " + Hex.encodeHexString(result));
//decrypt
cipher.init(Cipher.DECRYPT_MODE, convertSecureKey);
result = cipher.doFinal(result);
out.println("decrypt result is : " + new String(result));
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
}
運作結果如下:
encryption result is : 97919bd6b4d1590e773fdc1100564f1fecb6d585cb80015b080bb75c29f15d4d
decrypt result is : I'm DES encryption algorithm
DES加密算法消息傳遞如下所示:
3. 對稱密鑰算法--3重DES
3重DES的出現是因為DES算法是半公開的,這點恰好違反了柯克霍夫原則,安全性也有問題。3重DES對密碼長度做了增強、疊代次數進行了提高,是目前實際應用中用得最多的。
3DES(Triple DESDESede)
密鑰長度 | 預設 | 工作模式 | 填充方式 | 實作方 |
112 、 168 | 168 | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128 | NoPadding、 PKCS5Padding、 ISO10126Padding | JDK |
128 、 192 | 168 | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128 | PKCS7Padding、 SO10126d2Padding、 X032Padding、 ISO7816d4Padding、 ZeroBytePadding | Bouncy Castle |
3DES加密示例:
package com.bity.des;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import static java.lang.System.out;
/**
* <p>Title: Jdk3Des</p >
* <p>Description: 3DES加密算法實踐 </p >
* <p>Company: http://www.agree.com</p >
* <p>Project: security</p >
*
* @author <a href="mailto:[email protected]">WEIQI</a>
* @version 1.0
* @date 2022-04-26 20:55
*/
public class Jdk3Des {
private static final String SRC = "I'm 3DES encryption algorithm";
public static void main(String[] args) {
jdk3Des();
}
/**
* JDK-DES對稱密鑰算法實作
*
* @author: <a href="mailto:[email protected]">WEIQI</a>
* @date: 2022-04-26 20:41
*/
private static void jdk3Des() {
try {
// generator KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(168);
SecretKey secretKey = keyGenerator.generateKey();
byte[] bytesKey = secretKey.getEncoded();
// convert KEY
DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
Key convertSecureKey = secretKeyFactory.generateSecret(desKeySpec);
// encryption
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, convertSecureKey);
byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
out.println("encryption result is : " + Hex.encodeHexString(result));
//decrypt
cipher.init(Cipher.DECRYPT_MODE, convertSecureKey);
result = cipher.doFinal(result);
out.println("decrypt result is : " + new String(result));
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
}
運作結果:
encryption result is : c44fb80f098ba6d601032abd18b71cee83f7b533b053c227350cfc89892143cb
decrypt result is : I'm 3DES encryption algorithm
4. 對稱密鑰算法--AES
由于DES安全性沒有了保證,3DES性能比較低,是以出現了AES對稱加密算法。AES是目前使用最多的對稱加密算法,AES至今尚未被破解。該算法通常用于移動通信系統的加密以及基于SSH協定的軟體。
AES(Advanced Encryption Standard)
密鑰長度 | 預設 | 工作模式 | 填充方式 | 實作方 |
128、192、256 | 128 | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128 | NoPadding、 PKCS5Padding、 ISO10126Padding | JDK |
128、192、256 | 128 | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128 | PKCS7Padding、 ZeroBytePadding | Bouncy Castle |
這裡注意:JDK實作方256位密鑰需要獲得無政策限制權限檔案。無政策限制檔案是指因為某些國家的進口管制限制,Java釋出的運作環境包中的加解密有一定的限制。
AES加密示例:
package com.bity.aes;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import static java.lang.System.*;
/**
* <p>Title: JdkAes</p >
* <p>Description: </p >
* <p>Company: http://www.agree.com</p >
* <p>Project: security</p >
*
* @author <a href="mailto:[email protected]">WEIQI</a>
* @version 1.0
* @date 2022-04-26 21:09
*/
public class JdkAes {
private static final String SRC = "I'm AES encryption algorithm";
public static void main(String[] args) {
jdkAes();
}
/**
* JDK-AES加密實作
*
* @author: <a href="mailto:[email protected]">WEIQI</a>
* @date: 2022-04-26 21:17
*/
private static void jdkAes() {
try {
// generator KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
byte[] bytesKey = secretKey.getEncoded();
// convert KEY
Key key = new SecretKeySpec(bytesKey, "AES");
// encryption
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
out.println("aes encryption result is : " + Base64.encodeBase64String(result));
//decrypt
cipher.init(Cipher.DECRYPT_MODE, key);
result = cipher.doFinal(result);
out.println("aes decrypt result is : " + new String(result));
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
}
運作結果:
aes encryption result is : zbnnZOB0dwJH4V/zeNVbOEjDR5/ltFZXkqqZY7Y+JHw=
aes decrypt result is : I'm AES encryption algorithm
5. 對稱密鑰算法--PBE
PBE算法結合了消息摘要算法和對稱加密算法的優點,對已有算法進行包裝,形成了一個特殊的對稱加密算法。
PBE算法消息通信
PBE(Password Based Encryption)基于密碼的加密
算法 | 密鑰長度 | 預設 | 工作方式 | 填充方式 | 實作 |
PBEWithMD5AndDES | 64 | 64 | CBC | PKCS5Padding PKCS7Padding ISO10126Padding ZeroBytePadding | BC |
PBEWithMD5AndRC2 | 112 | 112 | |||
PBEWithSHA1AndDES | 64 | 64 | |||
PBEWithSHA1AndRC2 | 128 | 128 | |||
PBEWithSHAAndIDEA-CBC | 128 | 128 | |||
PBEWithSHAAnd2-KeyTripleDES-CBC | 128 | 128 | |||
PBEWithSHAAnd3-KeyTripleDES-CBC | 128 | 128 |
PBE加密示例
package com.bity.pbe;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
/**
* <p>Title: JdkPbe</p >
* <p>Description: PBE算法實作 </p >
* <p>Company: http://www.agree.com</p >
* <p>Project: security</p >
*
* @author <a href="mailto:[email protected]">WEIQI</a>
* @version 1.0
* @date 2022-04-26 21:37
*/
public class JdkPbe {
private static final String SRC = "I'm PBE encryption algorithm";
public static void main(String[] args) {
jdkPbe();
}
private static void jdkPbe() {
try {
// 初始化鹽
SecureRandom random = new SecureRandom();
byte[] salt = random.generateSeed(8);
// 密碼和密鑰
String token = "Abcd1234!@#$";
PBEKeySpec pbeKeySpec = new PBEKeySpec(token.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
Key key = factory.generateSecret(pbeKeySpec);
// 加密
PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 100);
Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES");
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParameterSpec);
byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
System.out.println("pbe encryption result is : " + Base64.encodeBase64String(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, key, pbeParameterSpec);
result = cipher.doFinal(result);
System.out.println("pbe decrypt reult is : " + new String(result));
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
}
運作結果:
pbe encryption result is : 1VcN0rTwdFxFgtKtedxnD2Zr3em8/tKWmg0vW1W6Abk=
pbe decrypt reult is : I'm PBE encryption algorithm