一.前言html
AES(Advanced Encryption Standard),高級加密標準,是美國政府用於替換DES的一種加密算法標準,Java SDK中包含了部分AES的實現,但javadoc對於算法的描述很是少,本文將解釋Java AES實現的使用和原理。java
二.示例代碼算法
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class AesECB { public static byte[] Encrypt(byte[] text, byte[] key) throws Exception { SecretKeySpec aesKey = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // default, same as "AES" // Cipher cipher = Cipher.getInstance("AES"); // same as above cipher.init(Cipher.ENCRYPT_MODE, aesKey); return cipher.doFinal(text); } public static byte[] Decrypt(byte[] text, byte[] key) throws Exception { SecretKeySpec aesKey = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, aesKey); return cipher.doFinal(text); } public static String bytes2hex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String temp = (Integer.toHexString(bytes[i] & 0XFF)); if (temp.length() == 1) { temp = "0" + temp; } sb.append(temp); sb.append(" "); } return sb.toString().toUpperCase(); } public static void main(String[] args) { try { String key = args[0]; String text = args[1]; System.out.printf("text : %s\n", bytes2hex(text.getBytes())); byte[] enc = AesECB.Encrypt(text.getBytes(), key.getBytes()); System.out.printf("encrypt: %s\n", bytes2hex(enc)); byte[] dec = AesECB.Decrypt(enc, key.getBytes()); System.out.printf("decrypt: %s\n", bytes2hex(dec)); } catch (Exception e) { e.printStackTrace(); } } }
三.代碼分析api
JDK AES加密主要是幾個步驟:oracle
1.key變換app
將傳入的明文key作變換,AES的key固定爲128bit,但變換後的key爲加密位數的一倍,128bit的加密變換後key爲256bit。注意加密和解密的key變換不同。ide
2.加密解密函數
選擇加密的模式和補齊填充方法生成加密實例,加密獲得密文。ui
四.密碼塊工做模式編碼
塊密碼工做模式(Block cipher mode of operation),是對於按塊處理密碼的加密方式的一種擴充,不單單適用於AES,包括DES, RSA等加密方法一樣適用。
名稱 |
英文 |
全名 |
方法 |
優勢 |
缺點 |
ECB |
Electronic codebook |
電子密碼本 |
每塊獨立加密 |
1.分塊能夠並行處理 |
1.一樣的原文獲得相同的密文,容易被*** |
CBC |
Cipher-block chaining |
密碼分組連接 |
每塊加密依賴於前一塊的密文 |
1.一樣的原文獲得不一樣的密文 |
1.加密須要串行處理 |
PCBC |
Propagating cipher-block chaining |
填充密碼塊連接 |
CBC的擴種,較少使用 |
1.一樣的原文獲得不一樣的密文 |
1.加密須要串行處理 |
CFB |
Cipher feedback |
密文反饋 |
|||
OFB |
Output feedback |
輸出反饋模式 |
加密後密文與原文異或XOR |
1.可以對密文進行校驗 |
|
CTR |
Counter mode |
計數器模式 |
增長一個序列函數對全部密文快作XOR |
五.填充
填充(Padding),是對須要按塊處理的數據,當數據長度不符合塊處理需求時,按照必定方法填充滿塊長的一種規則。
名稱 |
方法 |
示例 |
Zero padding |
最多見的方式,全填充0x00 |
AA AA AA AA 00 00 00 00 |
ANSI X.923 |
Zero的改進,最後一個字節爲填充字節個數 |
AA AA AA AA 00 00 00 04 |
ISO 10126 |
隨機填充 |
AA AA AA AA 81 A6 23 04 |
PKCS7 |
ANSI X.923的變體 |
AA AA AA AA AA AA AA 01 |
ISO/IEC 7816-4 |
以0x80開始做爲填充開始標記,後續全填充0x00 |
AA AA AA AA AA AA AA 80 |
六.JDK AES實現
1.實現支持
AES理論上支持128,192,256三種長度的密鑰,幾乎所有密碼塊工做模式和填充方法,但JDK 7中只實現以下四種AES加密算法:
(1)AES/CBC/NoPadding (128)
(2)AES/CBC/PKCS5Padding (128)
(3)AES/ECB/NoPadding (128)
(4)AES/ECB/PKCS5Padding (128)
2.使用須知
(1)缺省模式和填充爲「AES/ECB/PKCS5Padding」,Cipher.getInstance(「AES」)與Cipher.getInstance(「AES/ECB/PKCS5Padding」)等效。
(2)JDK的PKCS5Padding實際是上述的PKCS7的實現。
(3)因爲AES是按照16Byte爲塊進行處理,對於NoPadding而言,若是須要加密的原文長度不是16Byte的倍數,將沒法處理拋出異常,實際上是由用戶本身選擇Padding的算法。密文則必然是16Byte的倍數,不然密文確定異常。
(4)若是加密爲PKCS5Padding,解密能夠選擇NoPadding,也能解密成功,內容爲原文加上PKCS5Padding以後的結果。
(5)若是原文最後一個字符爲>=0x00&&<=0x10的內容,PKCS5Padding的解密將會出現異常,要麼是符合PKCS5Padding,最後的內容被刪除,要麼不符合,則解密失敗拋出異常。對此有兩種思路,一是原文經過Base64編碼爲可見字符,二是原文自帶長度使用NoPadding解密。
七.參考
(1)AES(Wiki)
(2)Block cipher mode of operation(Wiki)
(3)塊密碼的工做模式(Wiki)
(4)Padding(Wiki)
(5)PKCS(Wiki)
(6)JAVA 7 Cipher