对称加密算法 - Java加密与安全
生活随笔
收集整理的這篇文章主要介紹了
对称加密算法 - Java加密与安全
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對稱加密算法什么是對稱加密算法呢?1. 對稱加密算法就是加密和解密使用同一個密鑰,例如我們使用WinRAR,對文件進行打包的時候,我們可以設置一個秘密,在解壓的時候需要使用同一個密碼,才能夠正確的解壓,WinRAR使用的加密算法就是一種對稱加密算法
對稱加密算法在加密的時候,我們需要輸入一個key,和原始數據message,然后得到密文s,在解密的時候,我們需要通過密鑰key,和密文s,獲得原文message
常用的對稱加密算法有DES,AES,IDEA等,他們的密鑰長度,各不相同,密鑰長度直接決定著加密的長度,另外工作模式和填充模式可以看成是對稱加密的參數和格式選擇,JDK提供的算法并沒有包括所有的這些模式和所有的填充模式,但是通常我們只需要選用常用的就可以了,最后我們要注意,DES算法,因為密鑰過短,可以在短時間內被暴力破解,所以現在已經不安全了
package com.learn.securl;import java.nio.charset.StandardCharsets;
import java.util.Base64;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;/*** 如何使用AES的ECB模式進行加密* @author Leon.Sun**/
public class AES_ECB_Cipher {/*** 我們需要指定工作模式為ECB* 他的填充模式為PKCS5Padding* 這是JDK支持的一種加密模式*/static final String CIPHER_NAME = "AES/ECB/PKCS5Padding";/*** 加密:* 然后在encrypt方法中傳入AES的key,* 它是一個byte數組* 我們在傳入input也是一個byte數組* @throws Exception */public static byte[] encrypt(byte[] key,byte[] input) throws Exception {/*** 傳入加密算法的名字* 我們就得到一個Cipher實例*/Cipher cipher = Cipher.getInstance(CIPHER_NAME);/*** 緊接著我們通過創建一個SecretKeySpec* 然后把byte數組轉為一個AES的key*/SecretKeySpec keySpec = new SecretKeySpec(key, "AES");/*** 緊接著我們使用cipher.init* 初始化為加密模式* 然后傳入key*/cipher.init(Cipher.ENCRYPT_MODE, keySpec);/*** 最后我們通過doFinal* 就得到了加密以后的加密數組*/return cipher.doFinal(input);}/*** 對于解密代碼是類似的* 只要傳入key以及加密的輸入* @throws Exception */public static byte[] decrypt(byte[] key,byte[] input) throws Exception {/*** 我們仍然通過Cipher.getInstance獲得一個Cipher實例*/Cipher cipher = Cipher.getInstance(CIPHER_NAME);/*** 然后通過把字節數組的key變為一個SecretKeySpec的實例*/SecretKeySpec keySpec = new SecretKeySpec(key, "AES");/*** 在解密的時候我們調用init方法,* 傳入的是ENCRYPT_MODE*/cipher.init(Cipher.DECRYPT_MODE, keySpec);/*** 最后用doFinal方法就可以 把密文翻譯為明文*/return cipher.doFinal(input);}/*** 最后我們來編寫一個main方法來測試* @throws Exception */public static void main(String[] args) throws Exception {/*** 原文:* * 我們的原文是一個String*/String message = "Hello, world! encrypted using AES!";System.out.println("Message: " + message);/*** 128位密鑰 = 16 bytes Key:* * 而我們的密鑰是要一個128位的密鑰* 也就是16個字節* 我們把字符串轉換為字節數組* 然后進行加密*/byte[] key = "1234567890abcdef".getBytes("UTF-8");/*** 加密:*/byte[] data = message.getBytes(StandardCharsets.UTF_8);byte[] encrypted = encrypt(key, data);/*** 我們通過Base64把密文轉化為Base64編碼* 6ofAje3dbEseeIBkwKEonQIUi09dPO9fVx4OgZ7ozsE7BWtJJdcJs1+N58l1mWqh* 以Base64加密后的密文*/System.out.println("Encrypted data: " + Base64.getEncoder().encodeToString(encrypted));/*** 解密:* * 緊接著我們調用decrypt方法進行解密*/byte[] decrypted = decrypt(key, encrypted);/*** 我們把字節數組打印為原始的字符串* * Decrypted data: Hello, world! encrypted using AES!* 解密后得到的數據和原始的數據是一致的*/System.out.println("Decrypted data: " + new String(decrypted, "UTF-8"));}}
package com.learn.securl;import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;public class AES_CBC_Cipher {/*** 在使用CBC模式的時候* 我們使用的算法是AES/CBC/PKCS5Padding*/static final String CIPHER_NAME = "AES/CBC/PKCS5Padding";public static byte[] encrypt(byte[] key,byte[] input) throws Exception {Cipher cipher = Cipher.getInstance(CIPHER_NAME);SecretKeySpec keySpec = new SecretKeySpec(key, "AES");/*** CBC模式需要生成一個16 bytes的Initialization vector:* * 我們通過SecureRandom.getInstance可以獲得一個SecureRandom的值*/SecureRandom sr = SecureRandom.getInstanceStrong();/*** 我們注意在使用CBC模式的時候需要* 這個向量就是一個64字節的隨機數* * 我們可以通過generateSeed可以獲得一個64字節的向量*/byte[] iv = sr.generateSeed(16);/*** 把字節數組轉換為IvParameterSpec對象*/IvParameterSpec ivps = new IvParameterSpec(iv);/*** 就是在加密的時候傳入ENCRYPT_MODE,keySpec,ivps向量*/cipher.init(Cipher.ENCRYPT_MODE, keySpec,ivps);/*** 然后通過doFinal方法得到密文*/byte[] data = cipher.doFinal(input);/*** IV不需要保密,把IV和密文一起返回* * 在這里需要注意的是iv變量是不需要保密的* 所以我們把iv和密文data拼在一起返回*/return join(iv, data);}/*** 由于input包含的是iv和密文* 所以我們把它分割成16字節的iv以及密文本身* @param key* @param input* @return* @throws Exception*/public static byte[] decrypt(byte[] key,byte[] input) throws Exception {/*** 把input分割成IV和密文:*/byte[] iv = new byte[16];byte[] data = new byte[input.length - 16];System.arraycopy(input, 0, iv, 0, 16);System.arraycopy(input, 16, data, 0, data.length);/*** 解密:*/Cipher cipher = Cipher.getInstance(CIPHER_NAME);SecretKeySpec keySpec = new SecretKeySpec(key, "AES");IvParameterSpec ivps = new IvParameterSpec(iv);/*** 然后我們可以設置DECRYPT_MODE進行解析* 代碼和Encrtypt_mode是一樣的*/cipher.init(Cipher.DECRYPT_MODE, keySpec,ivps);/*** 這里傳入的是data而不是input*/return cipher.doFinal(data);}public static byte[] join(byte[] bs1, byte[] bs2) {byte[] r = new byte[bs1.length + bs2.length];System.arraycopy(bs1, 0, r, 0, bs1.length);System.arraycopy(bs2, 0, r, bs1.length, bs2.length);return r;}/*** 最后我們編寫一個main方法來測試* @param args* @throws Exception*/public static void main(String[] args) throws Exception {String message = "Hello, world! encrypted using AES!";System.out.println("Message: " + message);byte[] key = "1234567890abcdef".getBytes("UTF-8");byte[] data = message.getBytes(StandardCharsets.UTF_8);byte[] encrypted = encrypt(key, data);System.out.println("Encrypted data: " + Base64.getEncoder().encodeToString(encrypted));byte[] decrypted = decrypt(key, encrypted);/*** 得到解密以后的明文* Decrypted data: Hello, world! encrypted using AES!*/System.out.println("Decrypted data: " + new String(decrypted, "UTF-8"));}}
package com.learn.securl;import java.nio.charset.StandardCharsets;
import java.util.Base64;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;/*** 在ECB模式下加密* @author Leon.Sun**/
public class AES256_ECB_Cipher {/*** 在這里我們把加密模式指定為AES/ECB/PKCS5Padding*/static final String CIPHER_NAME = "AES/ECB/PKCS5Padding";/*** 加密*/public static byte[] encrypt(byte[] key, byte[] input) throws Exception{Cipher cipher = Cipher.getInstance(CIPHER_NAME);SecretKeySpec keySpec = new SecretKeySpec(key, "AES");cipher.init(Cipher.ENCRYPT_MODE, keySpec);return cipher.doFinal(input);}/*** 解密*/public static byte[] decrpty(byte[] key, byte[] input) throws Exception{Cipher cipher = Cipher.getInstance(CIPHER_NAME);SecretKeySpec keySpec = new SecretKeySpec(key, "AES");cipher.init(Cipher.DECRYPT_MODE, keySpec);return cipher.doFinal(input);}public static void main(String[] args) throws Exception{// 原文:String message = "Hello, world! encrypted using AES!";System.out.println("Message: " + message);// 256位密鑰 = 32 bytes Key:/*** 然后我們在生成密鑰的時候使用32字節的密鑰* 就是256位的密鑰* InvalidKeyException: Illegal key size or default parameters* 這個時候我們發現JDK報錯他告訴我們一個InvalidKeyException* 當我們遇到這個錯誤的時候并不是因為JDK不支持256位AES加密* 而是默認安裝的JDK他不允許你使用256位加密* 我們需要打開瀏覽器我們搜索jdk8 jce policy* 然后找到ORACLE的官方網站* https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html* 我們打開這個界面* 我們需要下載* Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8 Download* 文件* AES256* 使用256位加密需要修改JDK的policy文件* https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html下載,* 切換到目錄C:\Program Files\Java\jdk1.8.0_151\jre\lib\security下添加 local_policy.jar * 和 US_export_policy.jar* 這樣我們的AES的256算法就正常運行了* 我們之所以要替換這兩個policy文件* 因為受到美國出口法律的限制* ORCALE提供的JDK中他把加密算法限制在256位以下* 我們只需要替換local_policy這個文件* 就可以實現256位以上和更長的加密長度*/byte[] key = "1234567890abcdef1234567890abcdef".getBytes("UTF-8");// 加密:byte[] data = message.getBytes(StandardCharsets.UTF_8);byte[] encrypted = encrypt(key, data);System.out.println("Enctypted data: " + Base64.getEncoder().encodeToString(encrypted));// 解密:byte[] decrypted = decrpty(key, encrypted);System.out.println("Decrypted data: " + new String(decrypted, "UTF-8"));}
}
最后我們總結一下:1. 對稱加密算法是指使用同一個密鑰進行加密和解密2. 常用的算法有DES/AES/IDEA等3. 密鑰長度由算法設計的時候決定,AES的密鑰長度是128位,192位,或者是256位4. 使用256位加密的時候,我們需要修改JDK的policy文件5. 使用對稱加密算法我們還需要指定算法的名稱,工作模式,和填充模式,也就是加解密的雙方需要約定好參數
?
總結
以上是生活随笔為你收集整理的对称加密算法 - Java加密与安全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hmac - Java加密与安全
- 下一篇: 口令加密算法 - Java加密与安全