高級加密標准(Advanced Encryption Standard,簡寫AES),是一種用來替代DES的對稱加密算法,相比DES,AES安全性更高,加密速度更快,因此被廣泛使用。
理論上看,AES可被破解,但是就目前的硬件性能來看,目前AES還是安全的,在開發工程中,如果要使用對稱加密算法,應該首選AES。
下面使用介紹各語言中的DES加密解密實現:
聲明
1、加密解密過程分別使用比較多的ECB和CBC兩種方式來實現,ECB性能更快,但是安全性沒有CBC好,所以目前CBC用的比較多 2、加密解密填充方式采用PKCS7,或者PKCS5,這兩者在這里的加密解密過程中的結果可以認為是一樣的
3、CBC模式需要秘鑰及初始向量,而ECB模式只需要秘鑰即可,所以為了方便,下面封裝的方法或者函數將通過判斷是否存在初始向量來決定是使用CBC模式還是使用ECB模式
Java
首先,做一個封裝:

import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AesUtil { /** * DES加密 * * @param value * 待機加密明文 * @param secretKey * 秘鑰 * @param iv * 初始向量,如果未空,則將采用ECB模式,否則采用CBC模式 * * @return 密文 */ public static String aesEncrypt(String value, String secretKey, String iv) throws Exception { if (value == null || value.length() == 0) return ""; Cipher cipher = initCipher(Cipher.ENCRYPT_MODE, secretKey, iv); byte[] buffer = cipher.doFinal(value.getBytes("utf-8")); // 使用hex格式數據輸出 StringBuffer result = new StringBuffer(); for (int i = 0; i < buffer.length; i++) { result.append(String.format("%02x", buffer[i])); } return result.toString(); } /** * DES解密 * * @param value * 密文 * @param secretKey * 秘鑰 * @param iv * 初始向量,如果未空,則將采用ECB模式,否則采用CBC模式 * * @return 解密后的明文 */ public static String aesDecrypt(String value, String secretKey, String iv) throws Exception { if (value == null || value.length() == 0) return ""; // 轉換hex格式數據未byte數組 int length = value.length(); byte[] buffer = new byte[length / 2]; for (int i = 0; i < buffer.length; i++) { buffer[i] = (byte) Integer.parseInt( value.substring(i * 2, i * 2 + 2), 16); } Cipher cipher = initCipher(Cipher.DECRYPT_MODE, secretKey, iv); buffer = cipher.doFinal(buffer); return new String(buffer, "utf-8"); } private static Cipher initCipher(int mode, String secretKey, String iv) throws Exception { try { // 獲取秘鑰數組 byte[] secretBytes = secretKey.getBytes("utf-8"); byte[] keyBytes = new byte[16]; System.arraycopy(secretBytes, 0, keyBytes, 0, Math.min(secretBytes.length, keyBytes.length)); Key key = new SecretKeySpec(keyBytes, "AES"); if (iv == null || iv.length() == 0) { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// 采用ECB方式 cipher.init(mode, key); return cipher; } else { // 初始向量數組 byte[] ivBytes = iv.getBytes("utf-8"); byte[] ivKeyBytes = new byte[16]; System.arraycopy(ivBytes, 0, ivKeyBytes, 0, Math.min(ivBytes.length, ivKeyBytes.length)); IvParameterSpec ivp = new IvParameterSpec(ivKeyBytes); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// 采用CBC方式 cipher.init(mode, key, ivp); return cipher; } } catch (Exception e) { e.printStackTrace(); throw e; } } }
然后測試調用:
public static void main(String[] args) { String text = "上山打老虎"; String key = "123456"; String iv = "abcdefg"; try { String encryptText1 = AesUtil.aesEncrypt(text, key, iv); System.out.printf("【%s】經過【AES-CBC】加密后:%s\n", text, encryptText1); String decryptText1 = AesUtil.aesDecrypt(encryptText1, key, iv); System.out.printf("【%s】經過【AES-CBC】解密后:%s\n", encryptText1, decryptText1); String encryptText2 = AesUtil.aesEncrypt(text, key, null); System.out.printf("【%s】經過【AES-ECB】加密后:%s\n", text, encryptText2); String decryptText2 = AesUtil.aesDecrypt(encryptText2, key, null); System.out.printf("【%s】經過【AES-ECB】解密后:%s\n", encryptText2, decryptText2); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
執行結果:
C#
同樣先做一個封裝類:

using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; namespace ConsoleApp1 { public class AesHelper { #region AES /// <summary> /// 創建算法操作對象 /// </summary> /// <param name="secretKey"></param> /// <param name="iv"></param> /// <returns></returns> private static RijndaelManaged CreateRijndaelManaged(string secretKey, string iv) { RijndaelManaged rijndaelManaged = new RijndaelManaged(); rijndaelManaged.Padding = PaddingMode.PKCS7; rijndaelManaged.KeySize = 128; rijndaelManaged.BlockSize = 128; rijndaelManaged.Mode = CipherMode.CBC; byte[] secretBytes = Encoding.UTF8.GetBytes(secretKey); byte[] keyBytes = new byte[16]; Array.Copy(secretBytes, keyBytes, Math.Min(secretBytes.Length, keyBytes.Length)); rijndaelManaged.Key = keyBytes; if (string.IsNullOrEmpty(iv)) { rijndaelManaged.Mode = CipherMode.ECB; } else { rijndaelManaged.Mode = CipherMode.CBC; byte[] array = Encoding.UTF8.GetBytes(iv); byte[] ivBytes = new byte[keyBytes.Length]; Array.Copy(array, ivBytes, Math.Min(array.Length, ivBytes.Length)); rijndaelManaged.IV = ivBytes; } return rijndaelManaged; } /// <summary> /// Aes加密 /// </summary> /// <param name="value"></param> /// <param name="secretKey"></param> /// <param name="iv"></param> /// <returns></returns> public static string AesEncrypt(string value, string secretKey, string iv) { if (string.IsNullOrEmpty(value)) return string.Empty; using (RijndaelManaged rijndaelManaged = CreateRijndaelManaged(secretKey, iv)) { using (ICryptoTransform iCryptoTransform = rijndaelManaged.CreateEncryptor()) { byte[] buffer = Encoding.UTF8.GetBytes(value); buffer = iCryptoTransform.TransformFinalBlock(buffer, 0, buffer.Length); //使用hex格式輸出數據 StringBuilder result = new StringBuilder(); foreach (byte b in buffer) { result.AppendFormat("{0:x2}", b); } return result.ToString(); //或者使用下面的輸出 //return BitConverter.ToString(buffer).Replace("-", "").ToLower(); } } } /// <summary> /// Aes解密 /// </summary> /// <param name="value"></param> /// <param name="secretKey"></param> /// <param name="iv"></param> /// <returns></returns> public static string AesDecrypt(string value, string secretKey, string iv) { if (string.IsNullOrEmpty(value)) return string.Empty; using (RijndaelManaged rijndaelManaged = CreateRijndaelManaged(secretKey, iv)) { using (ICryptoTransform iCryptoTransform = rijndaelManaged.CreateDecryptor()) { //轉換hex格式數據為byte數組 byte[] buffer = new byte[value.Length / 2]; for (var i = 0; i < buffer.Length; i++) { buffer[i] = (byte)Convert.ToInt32(value.Substring(i * 2, 2), 16); } buffer = iCryptoTransform.TransformFinalBlock(buffer, 0, buffer.Length); return Encoding.UTF8.GetString(buffer); } } } #endregion } }
測試代碼:
static void Main(string[] args) { string text = "上山打老虎"; string key = "123456"; string iv = "abcdefg"; string encryptText1 = AesHelper.AesEncrypt(text, key, iv); Console.WriteLine($"【{text}】經過【AES-CBC】加密后:{encryptText1}"); string decryptText1 = AesHelper.AesDecrypt(encryptText1, key, iv); Console.WriteLine($"【{encryptText1}】經過【AES-CBC】解密后:{decryptText1}"); string encryptText2 = AesHelper.AesEncrypt(text, key, null); Console.WriteLine($"【{text}】經過【AES-ECB】加密后:{encryptText2}"); string decryptText2 = AesHelper.AesDecrypt(encryptText2, key, null); Console.WriteLine($"【{encryptText2}】經過【AES-ECB】解密后:{decryptText2}"); }
執行結果:
Golang
加密解密函數如下:

package main import ( "bytes" "crypto/aes" "crypto/cipher" "fmt" "strconv" ) //AES加密 //iv為空則采用ECB模式,否則采用CBC模式 func AesEncrypt(value, secretKey, iv string) (string, error) { if value == "" { return "", nil } //根據秘鑰生成16位的秘鑰切片 keyBytes := make([]byte, aes.BlockSize) copy(keyBytes, []byte(secretKey)) //獲取block block, err := aes.NewCipher(keyBytes) if err != nil { return "", err } blocksize := block.BlockSize() valueBytes := []byte(value) //填充 fillsize := blocksize - len(valueBytes)%blocksize repeat := bytes.Repeat([]byte{byte(fillsize)}, fillsize) valueBytes = append(valueBytes, repeat...) result := make([]byte, len(valueBytes)) //加密 if iv == "" { temp := result for len(valueBytes) > 0 { block.Encrypt(temp, valueBytes[:blocksize]) valueBytes = valueBytes[blocksize:] temp = temp[blocksize:] } } else { //向量切片 ivBytes := make([]byte, aes.BlockSize) copy(ivBytes, []byte(iv)) encrypter := cipher.NewCBCEncrypter(block, ivBytes) encrypter.CryptBlocks(result, valueBytes) } //以hex格式數值輸出 encryptText := fmt.Sprintf("%x", result) return encryptText, nil } //AES解密 //iv為空則采用ECB模式,否則采用CBC模式 func AesDecrypt(value, secretKey, iv string) (string, error) { if value == "" { return "", nil } //根據秘鑰生成8位的秘鑰切片 keyBytes := make([]byte, aes.BlockSize) copy(keyBytes, []byte(secretKey)) //獲取block block, err := aes.NewCipher(keyBytes) if err != nil { return "", err } //將hex格式數據轉換為byte切片 valueBytes := []byte(value) var encryptedData = make([]byte, len(valueBytes)/2) for i := 0; i < len(encryptedData); i++ { b, err := strconv.ParseInt(value[i*2:i*2+2], 16, 10) if err != nil { return "", err } encryptedData[i] = byte(b) } result := make([]byte, len(encryptedData)) if iv == "" { blocksize := block.BlockSize() temp := result for len(encryptedData) > 0 { block.Decrypt(temp, encryptedData[:blocksize]) encryptedData = encryptedData[blocksize:] temp = temp[blocksize:] } } else { //向量切片 ivBytes := make([]byte, aes.BlockSize) copy(ivBytes, []byte(iv)) //解密 blockMode := cipher.NewCBCDecrypter(block, ivBytes) blockMode.CryptBlocks(result, encryptedData) } //取消填充 unpadding := int(result[len(result)-1]) result = result[:(len(result) - unpadding)] return string(result), nil }
單元測試:
package main import ( "fmt" "testing" ) func TestAes(t *testing.T) { text := "上山打老虎" key := "123456" iv := "abcdefg" encryptText1, _ := AesEncrypt(text, key, iv) fmt.Printf("【%s】經過【AES-CBC】加密后:%s\n", text, encryptText1) decryptText1, _ := AesDecrypt(encryptText1, key, iv) fmt.Printf("【%s】經過【AES-CBC】解密后:%s\n", encryptText1, decryptText1) encryptText2, _ := AesEncrypt(text, key, "") fmt.Printf("【%s】經過【AES-ECB】加密后:%s\n", text, encryptText2) decryptText2, _ := AesDecrypt(encryptText2, key, "") fmt.Printf("【%s】經過【AES-ECB】解密后:%s\n", encryptText2, decryptText2) }
測試結果:
Python
python的AES加密相對簡單,同樣的,需要安裝pycrypto,可以使用pip安裝:pip install pycryptodome(如果安裝不了,先卸載舊版本再安裝:pip uninstall pycrypto)。
直接上代碼:
# 需要安裝pycrypto,可以使用pip安裝:pip install pycryptodome
from Crypto.Cipher import AES BLOCK_SIZE = 16 def init_cipher(secret_key, iv_key): secret_bytes = secret_key.encode(encoding='utf-8') key_bytes = [] if len(secret_bytes) >= BLOCK_SIZE: key_bytes = secret_bytes[:BLOCK_SIZE] else: key_bytes.extend(secret_bytes) key_bytes.extend([0 for x in range(0, BLOCK_SIZE - len(secret_bytes))]) if iv_key is None or len(iv_key) == 0: cipher = AES.new(bytes(key_bytes), AES.MODE_ECB) return cipher else: iv_bytes = iv_key.encode(encoding='utf-8') iv_key_bytes = [] if len(iv_bytes) >= BLOCK_SIZE: iv_key_bytes = iv_bytes[:BLOCK_SIZE] else: iv_key_bytes.extend(iv_bytes) iv_key_bytes.extend([0 for x in range(0, BLOCK_SIZE - len(iv_bytes))]) cipher = AES.new(bytes(key_bytes), AES.MODE_CBC, bytes(iv_key_bytes)) return cipher def aes_encrypt(value, secret_key, iv_key): cipher = init_cipher(secret_key, iv_key) buffer = value.encode(encoding="utf-8") bufferList = list(buffer) # 數據進行 PKCS5Padding 的填充 padding = BLOCK_SIZE - len(bufferList) % BLOCK_SIZE bufferList.extend([padding for x in range(0, padding)]) buffer = cipher.encrypt(bytes(bufferList)) return buffer.hex() # 使用hex格式輸出 def aes_decrypt(value, secret_key, iv_key): cipher = init_cipher(secret_key, iv_key) buffer = bytes.fromhex(value) # 讀取hex格式數據 buffer = cipher.decrypt(buffer) result = buffer.decode("utf-8") # 去掉 PKCS5Padding 的填充 return result[:-ord(result[len(result) - 1:])] text = "上山打老虎" key = "123456" iv = "abcdefg" encryptText1 = aes_encrypt(text, key, iv) print("【", text, "】經過【AES-CBC】加密后:", encryptText1) decryptText1 = aes_decrypt(encryptText1, key, iv) print("【", encryptText1, "】經過【AES-CBC】解密后:", decryptText1) encryptText2 = aes_encrypt(text, key, None) print("【", text, "】經過【AES-ECB】加密后:", encryptText2) decryptText2 = aes_decrypt(encryptText2, key, None) print("【", encryptText2, "】經過【AES-ECB】解密后:", decryptText2)
執行結果: