您好,登錄后才能下訂單哦!
Java使用AES加密和解密的實例詳解
前言:
AES的基本要求是,采用對稱分組密碼體制,密鑰長度的最少支持為128、192、256,分組長度128位,算法應易于各種硬件和軟件實現。1998年NIST開始AES第一輪分析、測試和征集,共產生了15個候選算法。1999年3月完成了第二輪AES2的分析、測試。2000年10月2日美國政府正式宣布選中比利時密碼學家Joan Daemen 和 Vincent Rijmen 提出的一種密碼算法RIJNDAEL 作為 AES. 在應用方面,盡管DES在安全上是脆弱的,但由于快速DES芯片的大量生產,使得DES仍能暫時繼續使用,為提高安全強度,通常使用獨立密鑰的三級DES。但是DES遲早要被AES代替。流密碼體制較之分組密碼在理論上成熟且安全,但未被列入下一代加密標準。
AES加密數據塊和密鑰長度可以是128比特、192比特、256比特中的任意一個。
AES加密有很多輪的重復和變換。大致步驟如下:
1、密鑰擴展(KeyExpansion),
2、初始輪(Initial Round),
3、重復輪(Rounds),每一輪又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,
4、最終輪(Final Round),最終輪沒有MixColumns。
AES是一種對稱的加密算法,可基于相同的密鑰進行加密和解密。Java采用AES算法進行加解密的邏輯大致如下:
1、生成/獲取密鑰
2、加/解密
1.1生成密鑰
密鑰的生成是通過KeyGenerator來生成的。通過獲取一個KeyGenerator實例,然后調用其generateKey()方法即可生成一個SecretKey對象。大致邏輯一般如下:
private SecretKey geneKey() throws Exception { //獲取一個密鑰生成器實例 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); SecureRandom random = new SecureRandom(); random.setSeed("123456".getBytes());//設置加密用的種子,密鑰 keyGenerator.init(random); SecretKey secretKey = keyGenerator.generateKey(); return secretKey; }
上述生成密鑰的過程中指定了固定的種子,每次生成出來的密鑰都是一樣的。還有一種形式,我們可以通過不指定SecureRandom對象的種子,即不調用其setSeed方法,這樣每次生成出來的密鑰都可能是不一樣的。
private SecretKey geneKey() throws Exception { //獲取一個密鑰生成器實例 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); SecureRandom random = new SecureRandom(); keyGenerator.init(random); SecretKey secretKey = keyGenerator.generateKey(); return secretKey; }
通過KeyGenerator的init(keySize)方法進行初始化,而不是通過傳遞SecureRandom對象進行初始化也可以達到上面的效果,每次生成的密鑰都可能是不一樣的。但是對應的keySize的指定一定要正確,AES算法的keySize是128。
private SecretKey geneKey() throws Exception { //獲取一個密鑰生成器實例 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); keyGenerator.init(128); SecretKey secretKey = keyGenerator.generateKey(); return secretKey; }
但是這種每次生成出來的密鑰都是不同的情況下,我們需要把加密用的密鑰存儲起來,以供解密的時候使用,不然就沒法進行解密了。
1.2密鑰的存儲
密鑰SecretKey里面最核心的內容就是其中的密鑰對應的字節數組,可以通過SecretKey的getEncoded()方法獲取。然后把它存儲起來即可。最簡單的方式就是直接寫入一個文件中。
//把上面的密鑰存起來 Path keyPath = Paths.get("D:/aes.key"); Files.write(keyPath, secretKey.getEncoded());
1.3獲取存儲的密鑰
獲取存儲的密鑰的核心是把密鑰的字節數組轉換為對應的SecretKey。這可以通過SecretKeySpec來獲取,其實現了SecretKey接口,然后構造參數里面將接收密鑰的字節數組。
private SecretKey readKey(Path keyPath) throws Exception { //讀取存起來的密鑰 byte[] keyBytes = Files.readAllBytes(keyPath); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM); return keySpec; }
1.4加解密
Java采用AES算法進行加解密的過程是類似的,具體如下:
1、指定算法,獲取一個Cipher實例對象
Cipher cipher = Cipher.getInstance(ALGORITHM);//算法是AES
2、生成/讀取用于加解密的密鑰
SecretKey secretKey = this.geneKey();
3、用指定的密鑰初始化Cipher對象,同時指定加解密模式,是加密模式還是解密模式。
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
4、通過update指定需要加密的內容,不可多次調用。
cipher.update(content.getBytes());
5、通過Cipher的dofinal()進行最終的加解密操作。
byte[] result = cipher.doFinal();//加密后的字節數組
通過以上幾步就完成了使用AES算法進行加解密的操作了。其實第4、5步是可以合在一起的,即在進行doFinal的時候傳遞需要進行加解密的內容。但是如果update指定了加密的內容,而doFinal的時候也指定了加密的內容,那最終加密出來的結果將是兩次指定的加密內容的和對應的加密結果。
byte[] result = cipher.doFinal(content.getBytes());
以下是一次加解密操作的完整示例。
public class AESTest { private static final String ALGORITHM = "AES"; /** * 生成密鑰 * @return * @throws Exception */ private SecretKey geneKey() throws Exception { //獲取一個密鑰生成器實例 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); SecureRandom random = new SecureRandom(); random.setSeed("123456".getBytes());//設置加密用的種子,密鑰 keyGenerator.init(random); SecretKey secretKey = keyGenerator.generateKey(); //把上面的密鑰存起來 Path keyPath = Paths.get("D:/aes.key"); Files.write(keyPath, secretKey.getEncoded()); return secretKey; } /** * 讀取存儲的密鑰 * @param keyPath * @return * @throws Exception */ private SecretKey readKey(Path keyPath) throws Exception { //讀取存起來的密鑰 byte[] keyBytes = Files.readAllBytes(keyPath); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM); return keySpec; } /** * 加密測試 */ @Test public void testEncrypt() throws Exception { //1、指定算法、獲取Cipher對象 Cipher cipher = Cipher.getInstance(ALGORITHM);//算法是AES //2、生成/讀取用于加解密的密鑰 SecretKey secretKey = this.geneKey(); //3、用指定的密鑰初始化Cipher對象,指定是加密模式,還是解密模式 cipher.init(Cipher.ENCRYPT_MODE, secretKey); String content = "Hello AES";//需要加密的內容 //4、更新需要加密的內容 cipher.update(content.getBytes()); //5、進行最終的加解密操作 byte[] result = cipher.doFinal();//加密后的字節數組 //也可以把4、5步組合到一起,但是如果保留了4步,同時又是如下這樣使用的話,加密的內容將是之前update傳遞的內容和doFinal傳遞的內容的和。 // byte[] result = cipher.doFinal(content.getBytes()); String base64Result = Base64.getEncoder().encodeToString(result);//對加密后的字節數組進行Base64編碼 System.out.println("Result: " + base64Result); } /** * 解密測試 */ @Test public void testDecrpyt() throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); SecretKey secretKey = this.geneKey(); cipher.init(Cipher.DECRYPT_MODE, secretKey); String content = "pK9Xw4zqTMXYraDadSGJE3x/ftrDxIg2AM/acq0uixA=";//經過Base64加密的待解密的內容 byte[] encodedBytes = Base64.getDecoder().decode(content.getBytes()); byte[] result = cipher.doFinal(encodedBytes);//對加密后的字節數組進行解密 System.out.println("Result: " + new String(result)); } }
1.5使用存儲的密鑰進行加解密示例
@Test public void test() throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); keyGenerator.init(128); SecretKey secretKey = keyGenerator.generateKey(); //把上面的密鑰存起來 Path keyPath = Paths.get("D:/aes.key"); Files.write(keyPath, secretKey.getEncoded()); //讀取存起來的密鑰 SecretKey key = this.readKey(keyPath); cipher.init(Cipher.ENCRYPT_MODE, key); cipher.update("Hello World".getBytes()); //密文 byte[] encryptBytes = cipher.doFinal(); System.out.println(Base64.getEncoder().encodeToString(encryptBytes)); //用取出來的密鑰進行解密 cipher.init(Cipher.DECRYPT_MODE, key); //明文 byte[] decryptBytes = cipher.doFinal(encryptBytes); System.out.println(new String(decryptBytes)); }
在上面的示例中,我們先生成了一個密鑰,然后把它保存到本地文件中,然后再把它讀出來,分別用以加密和解密。而且我們加密和解密都是用的同一個Cipher對象,但是在使用前需要重新通過init方法初始化加解密模式。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。