AES加密演算法的JAVA實現

爆米花9958發表於2017-01-17

最近公司需要,看了看AES對稱加密演算法,具體原理沒有仔細研究還,先說說用法吧,由於能力有限,不足之處請大家多多指教,好了,不說廢話了,直接上程式碼

/**
 * 加密
 *
 * @param content  需要加密的內容
 * @param password 加密密碼
 * @return
 */
public static byte[] encrypt(String content, String password) {
    KeyGenerator kgen = null;
    try {
        kgen = KeyGenerator.getInstance("AES");
        kgen.init(128, new SecureRandom(password.getBytes()));
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");// 建立密碼器
        cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
        byte[] byteContent = content.getBytes("utf-8");
        byte[] result = cipher.doFinal(byteContent);
        return result;//加密
    } catch (NoSuchAlgorithmException | InvalidKeyException
            | NoSuchPaddingException | BadPaddingException
            | UnsupportedEncodingException | IllegalBlockSizeException e) {
        e.printStackTrace();
    }
    return null;
}

/**
 * 解密
 *
 * @param content  待解密內容
 * @param password 解密金鑰
 * @return
 */
public static byte[] decrypt(byte[] content, String password) {
    KeyGenerator kgen = null;
    try {
        kgen = KeyGenerator.getInstance("AES");
        kgen.init(128, new SecureRandom(password.getBytes()));
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");// 建立密碼器
        cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
        byte[] result = cipher.doFinal(content);
        return result; // 解密
    } catch (NoSuchAlgorithmException | BadPaddingException
            | IllegalBlockSizeException | NoSuchPaddingException
            | InvalidKeyException e) {
        e.printStackTrace();
    }
    return null;

}
我們測試一下效果:
String content = "test";
String password = "123456";
//加密
System.out.println("加密前:" + content);
byte[] encryptResult = encrypt(content, password);
System.out.println("加密後:" + encryptResult.toString());
//解密
byte[] decryptResult = decrypt(encryptResult, password);
System.out.println("解密後:" + new String(decryptResult));


但有一點一定要注意——加密後的byte陣列是不能強制轉換成字串的,我們可以實驗下:
//解密
try {
    String encryptResultStr = new String(encryptResult, "utf-8");
    byte[] decryptResult = decrypt(encryptResultStr.getBytes("utf-8"), password);
    System.out.println("解密後:" + new String(decryptResult));
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
執行後,會報如下錯誤:


具體原因我們就不再詳細解釋了,事實上這種方法也是沒有實際意義的,因為我們要考慮java的跨平臺特性,因此我們使用這句:
kgen.init(128, new SecureRandom(password.getBytes()));
生成隨機金鑰,在別的平臺很可能獲得的金鑰是不相同的,所以這隻裡能當做展示罷了。
網上看了很多文章,發現還是這樣寫合適:
/**
 * 加密
 * @param content
 * @param strKey
 * @return
 * @throws Exception
 */
public static byte[] encrypt(String content,String strKey ) throws Exception {
    SecretKeySpec skeySpec = getKey(strKey);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
    byte[] encrypted = cipher.doFinal(content.getBytes());
    return  encrypted;
}

/**
 * 解密
 * @param strKey
 * @param content
 * @return
 * @throws Exception
 */
public static String decrypt(byte[] content,String strKey ) throws Exception {
    SecretKeySpec skeySpec = getKey(strKey);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
    byte[] original = cipher.doFinal(content);
    String originalString = new String(original);
    return originalString;
}

private static SecretKeySpec getKey(String strKey) throws Exception {
    byte[] arrBTmp = strKey.getBytes();
    byte[] arrB = new byte[16]; // 建立一個空的16位位元組陣列(預設值為0)

    for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
        arrB[i] = arrBTmp[i];
    }

    SecretKeySpec skeySpec = new SecretKeySpec(arrB, "AES");

    return skeySpec;
}
測試就不寫了,我們再對版本功能進行一下加強,對傳輸的資料使用base64進行編碼,先寫base64的編碼和解碼:
/**
 * base 64 encode
 * @param bytes 待編碼的byte[]
 * @return 編碼後的base 64 code
 */
public static String base64Encode(byte[] bytes){
    return new BASE64Encoder().encode(bytes);
}

/**
 * base 64 decode
 * @param base64Code 待解碼的base 64 code
 * @return 解碼後的byte[]
 * @throws Exception
 */
public static byte[] base64Decode(String base64Code) throws Exception{
    return base64Code.isEmpty() ? null : new BASE64Decoder().decodeBuffer(base64Code);
}
接著對AES加密的資料進行base64編碼,對AES解密的資料進行解碼:
/**
 * AES加密為base 64 code
 * @param content 待加密的內容
 * @param encryptKey 加密金鑰
 * @return 加密後的base 64 code
 * @throws Exception
 */
public static String aesEncrypt(String content, String encryptKey) throws Exception {
    return base64Encode(encrypt(content, encryptKey));
}
/**
 * 將base 64 code AES解密
 * @param encryptStr 待解密的base 64 code
 * @param decryptKey 解密金鑰
 * @return 解密後的string
 * @throws Exception
 */
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
    return encryptStr.isEmpty() ? null : decrypt(base64Decode(encryptStr), decryptKey);
}
寫一個測試,看下效果:
public static void main(String[] args) throws Exception {
    String test = "我愛你";
    System.out.println("加密前:" + test);

    String key = "123456";
    System.out.println("金鑰:" + key);

    String encrypt = aesEncrypt(test, key);
    System.out.println("加密後:" + encrypt);

    String decrypt = aesDecrypt(encrypt, key);
    System.out.println("解密後:" + decrypt);

}


好了,受個人水平所限,就先寫這麼多吧,以後有更多內容再往上補充

參考:


相關文章