序言
對稱加密算法,加密與解密的密鑰是一樣的,密鑰管理比較困難,容易泄露,一旦泄露就會很容易導致數據不安全。
相關概念
明文: 數據沒有進行加密,原始數據信息。
密文: 加密過後得到的數據, 隱藏了原始數據的含義。
加密 : 將明文轉爲密文的過程。
解密 : 將密文轉爲明文的過程。
密鑰: 是一種參數,是在加密或解密中輸入的參數。
對稱加密
定義: 指的是加密與解密使用相同的密鑰。這種加密方式稱爲對稱加密。
對稱加密一般有: DES 、 3DES 、 AES 、 PBE
- DES(Data Encryption Standard): 數據加密標準,速度較快,適用於加密大量數據的場合。
- 3DES(Triple DES): 基於DES, 對一塊數據用三個不同的密鑰進行三次加密,強度更高。
- AES(Advanced Encryption Standard): 高級加密標準,是下一代的加密算法標準,速度快,安全級別高,支持128、192、256、512位密鑰的加密。
- PBE(Password Based Encryption): 是一種基於口令的加密算法,其特點是使用口令代替了密鑰,而口令由用戶自己掌管,採用隨機數雜湊多重加密等方法保證數據的安全性。
對稱加密特徵:
- 加密方和解密方使用同一個密鑰。
- 加密與解密的速度較快。
- 密鑰傳輸過程不安全,且容易被破解,密鑰管理也很麻煩。
代碼實現:
DES算法
/**
* @program
* @Desc
* @Author 遊戲人日常
* @CreateTime 2019/08/11--2:21
*/
public class DesTest {
//轉化格式
public static final String TRAMSFORMATION = "DES/ECB/PKCS5Padding";
//算法 DES
public static final String ALGORITHM = "DES";
//待加密的源串
public static final String msg = "helloWorld";
//密鑰
public static final String key = "123456789";
public static void main(String args[]) {
System.out.println("待加密數據: " + msg);
byte[] encryptStr = encrypt(msg, key);
System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
byte[] decryptStr = decrypt(encryptStr, key);
System.out.println("解密後的結果:" + new String(decryptStr));
}
/**
* 解密
* @param encryptionStr 加密的數據
* @param key 密鑰
* @return
*/
private static byte[] decrypt(byte[] encryptionStr, String key) {
try {
//1.KEY轉換
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());//實例化DESKey祕鑰的相關內容
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);//實例一個祕鑰工廠,指定加密方式
Key convertKey = factory.generateSecret(desKeySpec);
//2.解密 DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
cipher.init(Cipher.DECRYPT_MODE, convertKey );
byte[] result = cipher.doFinal(encryptionStr);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param encryptionStr 待加密的串
* @param key 密鑰
* @return
*/
public static byte[] encrypt(String encryptionStr, String key) {
try {
//1.KEY轉換
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());//實例化DESKey祕鑰的相關內容
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);//實例一個祕鑰工廠,指定加密方式
Key convertKey = factory.generateSecret(desKeySpec);
//2.加密 DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
cipher.init(Cipher.ENCRYPT_MODE, convertKey );
byte[] result = cipher.doFinal(encryptionStr.getBytes());//輸入要加密的內容
return result;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
輸出結果
待加密數據: helloWorld
加密後以十六進制輸出的結果: -60fd73ff69e3352e5e2e976c55e6ed92
解密後的結果:helloWorld
3DES算法
/**
* @program
* @Desc
* @Author 遊戲人日常
* @CreateTime 2019/08/11--14:45
*/
public class DES3Test {
//轉化格式
public static final String TRAMSFORMATION = "DESEde/ECB/PKCS5Padding";
//算法 DES
public static final String ALGORITHM = "DESEde";
//待加密的源串
public static final String msg = "helloWorld";
//密鑰
public static final String key = "1234567812345678123456789";
public static void main(String[] args) {
System.out.println("待加密數據: " + msg);
byte[] encryptStr = encrypt(msg, key);
System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
byte[] decryptStr = decrypt(encryptStr, key);
System.out.println("解密後的結果:" + new String(decryptStr));
}
/**
* 解密
*
* @param encryptionStr 加密的數據
* @param key 密鑰
* @return
*/
private static byte[] decrypt(byte[] encryptionStr, String key) {
try {
//1.生成KEY
DESedeKeySpec desKeySpec = new DESedeKeySpec(key.getBytes());//實例化DESKey祕鑰的相關內容
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);//實例一個祕鑰工廠,指定加密方式
Key convertKey = factory.generateSecret(desKeySpec);
//2.解密 DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
cipher.init(Cipher.DECRYPT_MODE, convertKey );
byte[] result = cipher.doFinal(encryptionStr);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] encrypt(String encryptionStr, String key) {
try {
//1.轉換KEY
DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(key.getBytes());
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
Key convertKey = factory.generateSecret(deSedeKeySpec);
//2.加密
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, convertKey);
byte[] result = cipher.doFinal(encryptionStr.getBytes());
return result;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
輸出結果
待加密數據: helloWorld
加密後以十六進制輸出的結果: -60fd73ff69e3352e5e2e976c55e6ed92
解密後的結果:helloWorld
AES算法
/**
* @program
* @Desc
* @Author 遊戲人日常
* @CreateTime 2019/08/11--15:16
*/
public class AESTest {
//轉化格式
public static final String TRAMSFORMATION = "AES/ECB/PKCS5Padding";
//算法 DES
public static final String ALGORITHM = "AES";
//待加密的源串
public static final String msg = "helloWorld";
//密鑰
public static final String key = "1234567812345678";
public static void main(String[] args) {
System.out.println("待加密數據: " + msg);
byte[] encryptStr = encrypt(msg, key);
System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
byte[] decryptStr = decrypt(encryptStr, key);
System.out.println("解密後的結果:" + new String(decryptStr));
}
/**
* 解密
*
* @param encryptionStr 加密的數據
* @param key 密鑰
* @return
*/
private static byte[] decrypt(byte[] encryptionStr, String key) {
try {
//1.轉換KEY
Key convertKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
//2.解密 DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
cipher.init(Cipher.DECRYPT_MODE, convertKey);
byte[] result = cipher.doFinal(encryptionStr);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] encrypt(String encryptionStr, String key) {
try {
//1.轉換KEY
Key convertKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
//2.加密
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, convertKey);
byte[] result = cipher.doFinal(encryptionStr.getBytes());
return result;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
輸出結果
待加密數據: helloWorld
加密後以十六進制輸出的結果: -680bb3194a04ff1ece4e28227012ad33
解密後的結果:helloWorld
PBE算法
/**
* @program
* @Desc
* @Author 遊戲人日常
* @CreateTime 2019/08/11--15:55
*/
public class PBETest {
//轉化格式
public static final String TRAMSFORMATION = "PBEWITHMD5andDES";
//待加密的源串
public static final String msg = "helloWorld";
//密鑰
public static final String key = "123456789";
public static void main(String args[]) {
byte[] salt=initSalt();//初始化salt
System.out.println("待加密數據: " + msg);
byte[] encryptStr = encrypt(salt,msg,key);
System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
byte[] decryptStr = decrypt(salt,encryptStr, key);
System.out.println("解密後的結果:" + new String(decryptStr));
}
public static byte[] initSalt(){
SecureRandom secureRandom = new SecureRandom();
byte[] salt = secureRandom.generateSeed(8);
return salt;
}
/**
* 解密
* @param salt
* @param encryptionStr 加密的數據
* @param key 這個是加密用的口令
* @return
*/
private static byte[] decrypt(byte[] salt, byte[] encryptionStr, String key) {
try {
//1.轉換KEY
PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance(TRAMSFORMATION);
Key convertKey = factory.generateSecret(pbeKeySpec);
//2.解密
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);//100是你選擇迭代的次數
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, convertKey, parameterSpec);
byte[] result = cipher.doFinal(encryptionStr);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 加密
* @param salt
* @param encryptionStr 待加密的串
* @param key 這個是加密用的口令
* @return
*/
public static byte[] encrypt(byte[] salt,String encryptionStr,String key) {
try {
//1.轉換KEY
PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance(TRAMSFORMATION);
Key convertKey = factory.generateSecret(pbeKeySpec);
//2. 加密
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);//100是你選擇迭代的次數
Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, convertKey, parameterSpec);
byte[] result = cipher.doFinal(encryptionStr.getBytes());
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
輸出結果
待加密數據: helloWorld
加密後以十六進制輸出的結果: 450056595e1fbcc4f35bf855bd18dee2
解密後的結果:helloWorld
總結
- 這些對稱算法全是JDK自帶的API實現,也可以用第三方(BouncyCastle)的實現。
- 不同的算法對key的長度有要求,通過查看jdk代碼發現DES的key必須大於8,3DES大於24等等。 否則會拋異常:Wrong key size
- 這些對稱算法的底層原理是怎麼實現的本文沒有敘述,具體怎麼實現請查看其它的資料。
對稱算法優缺點
優點
速度快,通常在消息發送方需要加密大量數據時使用,算法公開、計算量小、加密速度快、加密效率高。
缺點
在數據傳輸前,發送和接收方必須確定好密鑰,然後雙方都能保存這個密鑰,一旦泄露那麼數據的傳輸這個過程就很不安全。