Java、Android、ios、js數據傳遞AES加密算法

在app開發中我們遇到一個需要將用戶的賬戶密碼加密問題,便是我們這篇文章的來源了。

爲了保持我們三個前端的一致性我們一定要將key和位移保持一致,否則會導致bug。

首先還是直接來看一下我們的Java後端代碼,其實就是加密和解密算法了。Android直接拿到這個工具類就好了,爲什麼麼?你懂的。

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

@SuppressWarnings("restriction")
public class AESUtils {

    private static final String AES = "AES";

    private static final String CRYPT_KEY = "";//你自己的key

    private static final String IV_STRING = "";//你自己的位移
    /**
     * 加密
     *
     * @param content 加密內容
     * @return 密文
     * @throws Exception e
     */
    public static String encrypt(String content) throws Exception {
        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 (Exception e) {
        	throw new Exception(e);
        }


        return new BASE64Encoder().encode(encryptedBytes);
    }

    /**
     * 解密
     *
     * @param content 密文
     * @return 明文
     * @throws Exception e
     */
    public static String decrypt(String content) throws Exception {
        // 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 (Exception e) {
        	throw new Exception(e);
        }
    }

}
接下來就是ios,同樣的需要我們定義和Android及Java後端一致的key和位移:

//先定義一個初始向量的值。
NSString *const kInitVector = @"";
NSString *const key= @"";
//確定密鑰長度,這裏選擇 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;
}
js端,js文件哪裏找,樓主的資源鏈接如下點擊打開鏈接

<script type="text/javascript" src="./CryptoJS/crypto-js.js"></script>  
<script>
    //直接上代碼
    var key = CryptoJS.enc.Utf8.parse('');//key
    var iv  = CryptoJS.enc.Utf8.parse('');//位移
    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>
方法已經在樓主參與的app中已應用。放心大膽的用吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章