1. 程式人生 > >java、android、ios、js資料傳遞加密演算法之AES加密

java、android、ios、js資料傳遞加密演算法之AES加密

場景描述

我們在做專案的時候,寫介面經常會遇到這樣的情況,就是和app端、web端互動的時候傳輸資料需要進行加密,不能用明文操作。資料傳輸加密最關鍵的就是前後端傳輸的資料最終能被正確的解密出來,今天就來講講使用AES加密傳輸的時候前後端使用的程式碼。

解決方案

  • 首先來看一下後端java的AES加解密工具類

    // 注意,為了能與 iOS 統一,這裡的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成

/**
 * <p>
 * 引數加密解密工具,不要和DESEncrypt弄混了
 * </p>
 *
 * @author
ZhaoHang * @date 2017-09-1 11:55 */
public class AESUtils { public static final Logger LOGGER = LoggerFactory.getLogger(AESUtils.class); private static final String AES = "AES"; private static final String CRYPT_KEY = "y2W89L6BkRAFljhN"; private static final String IV_STRING = "dMitHORyqbeYVE0o"
; /** * 加密 * * @param content 加密內容 * @return 密文 * @throws Exception e */ public static String encrypt(String content) { byte[] encryptedBytes = new byte[0]; try { byte[] byteContent = content.getBytes("UTF-8"); // 注意,為了能與 iOS 統一
// 這裡的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成 byte[] enCodeFormat = CRYPT_KEY.getBytes(); SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, AES); byte[] initParam = IV_STRING.getBytes(); IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam); // 指定加密的演算法、工作模式和填充方式 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); encryptedBytes = cipher.doFinal(byteContent); // 同樣對加密後資料進行 base64 編碼 } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { LOGGER.error("AES encrypt Exception,content = {},Exception = {}", content, e.getStackTrace()); } return new BASE64Encoder().encode(encryptedBytes); } /** * 解密 * * @param content 密文 * @return 明文 * @throws Exception e */ public static String decrypt(String content) { // base64 解碼 try { byte[] encryptedBytes = new BASE64Decoder().decodeBuffer(content); byte[] enCodeFormat = CRYPT_KEY.getBytes(); SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, AES); byte[] initParam = IV_STRING.getBytes(); IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec); byte[] result = cipher.doFinal(encryptedBytes); return new String(result, "UTF-8"); } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { LOGGER.error("AES decrypt Exception,content = {},Exception = {}", content, e.getStackTrace()); } return null; } }
  • android端使用同上與後端java一致
  • ios端的程式碼如下
//先定義一個初始向量的值。
NSString *const kInitVector = @"dMitHORyqbeYVE0o";
NSString *const key= @"y2W89L6BkRAFljhN";
//確定金鑰長度,這裡選擇 AES-128。
size_t const kKeySize = kCCKeySizeAES128;
/**
 AES加密方法

 @param content 需要加密的字串
 @param key key
 @return 加密後的字串
 */
+ (NSString *)encryptAES:(NSString *)content{
    NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = contentData.length;
    // 為結束符'\\0' +1
    char keyPtr[kKeySize + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    // 密文長度 <= 明文長度 + BlockSize
    size_t encryptSize = dataLength + kCCBlockSizeAES128;
    void *encryptedBytes = malloc(encryptSize);
    size_t actualOutSize = 0;
    NSData *initVector = [kInitVector dataUsingEncoding:NSUTF8StringEncoding];
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,  // 系統預設使用 CBC,然後指明使用 PKCS7Padding
                                          keyPtr,
                                          kKeySize,
                                          initVector.bytes,
                                          contentData.bytes,
                                          dataLength,
                                          encryptedBytes,
                                          encryptSize,
                                          &actualOutSize);
    if (cryptStatus == kCCSuccess) {
        // 對加密後的資料進行 base64 編碼
        return [[NSData dataWithBytesNoCopy:encryptedBytes length:actualOutSize] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    }
    free(encryptedBytes);
    return nil;
}
/**
 AES解密方法

 @param content 需要解密的字串
 @param key key
 @return 解密後的字串
 */
+ (NSString *)decryptAES:(NSString *)content{
    // 把 base64 String 轉換成 Data
    NSData *contentData = [[NSData alloc] initWithBase64EncodedString:content options:NSDataBase64DecodingIgnoreUnknownCharacters];
    NSUInteger dataLength = contentData.length;
    char keyPtr[kKeySize + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    size_t decryptSize = dataLength + kCCBlockSizeAES128;
    void *decryptedBytes = malloc(decryptSize);
    size_t actualOutSize = 0;
    NSData *initVector = [kInitVector dataUsingEncoding:NSUTF8StringEncoding];
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kKeySize,
                                          initVector.bytes,
                                          contentData.bytes,
                                          dataLength,
                                          decryptedBytes,
                                          decryptSize,
                                          &actualOutSize);
    if (cryptStatus == kCCSuccess) {
        return [[NSString alloc] initWithData:[NSData dataWithBytesNoCopy:decryptedBytes length:actualOutSize] encoding:NSUTF8StringEncoding];
    }
    free(decryptedBytes);
    return nil;
}
<script type="text/javascript" src="./CryptoJS/crypto-js.js"></script>  
<script>
    //直接上程式碼
    var key = CryptoJS.enc.Utf8.parse('y2W89L6BkRAFljhN');
    var iv  = CryptoJS.enc.Utf8.parse('dMitHORyqbeYVE0o');
    var source = '要加密的字串';
    var password=CryptoJS.enc.Utf8.parse(source);
    console.log("原始字串:"+source);
    console.log("utf8處理後:"+password);

    var encrypted = CryptoJS.AES.encrypt(password, key, { iv: iv,mode:CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7});  //CryptoJS.pad.Pkcs7
    var decrypted = CryptoJS.AES.decrypt(encrypted, key, { iv: iv,mode:CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7});  //CryptoJS.pad.Pkcs7

   console.log("加密後base64:"+encrypted);   
   var encryptedStr=encrypted.ciphertext.toString();
   console.log("加密後16進位制:"+encryptedStr);   
   console.log("解密後utf8:"+decrypted); 
   console.log("解密後原始字串:"+decrypted.toString(CryptoJS.enc.Utf8));     
</script>

js測試截圖
這裡寫圖片描述
使用js加密的結果在java中解密如下:
這裡寫圖片描述
ios的同理,有興趣的童鞋可以親測一下,這些都是專案中實際親測的希望有用~