iOS JAVA互通AES加解密实现

背景:由于业务需要,对移动端页面中的链接需要做加解密处理。后端加密完成后前端(iOS、Android)解密。Android拿着key成功解密,十分钟搞定(这不简简单单~)。iOS拿着key解密,不是解密出来乱码,就是nil,半天过去了还没搞定(真的栓Q)。

下边放上经过不懈努力成功解密的代码,iOS、Android、JAVA可以互相加解密,有需要的直接复制使用。

一、iOS加解密

AESUtil.h

#import 
#import 
NS_ASSUME_NONNULL_BEGIN

@interface AESUtil : NSObject

/**
 * AES加密
 */
+ (NSString *)encryptAES:(NSString *)content;
 
/**
 * AES解密
 */
+ (NSString *)decryptAES:(NSString *)content;


@end

NS_ASSUME_NONNULL_END

2、AESUtil.m

#import "AESUtil.h"

//key
static NSString *const PSW_AES_KEY = @"--32位字母数字组成的字符串--";
//偏移量
NSString *const kInitVector = @"--16位字母数字组成的字符串--";
//密钥长度
size_t const kKeySize = kCCKeySizeAES256;//kCCKeySizeAES128
@implementation AESUtil

+ (NSString *)encryptAES:(NSString *)content {
    NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = contentData.length;
    // 为结束符'\\0' +1
    char keyPtr[kKeySize + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [PSW_AES_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;
}

+ (NSString *)decryptAES:(NSString *)content{
    NSData *contentData = [[NSData alloc] initWithBase64EncodedString:content options:NSDataBase64DecodingIgnoreUnknownCharacters];
    NSUInteger dataLength = contentData.length;
    char keyPtr[kKeySize + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [PSW_AES_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;
}

@end

注意:解密后的字符串包含看不见的字符"\0",需要替换为"",如下

NSString *result = [decryptContent stringByReplacingOccurrencesOfString:@"\0" withString:@""];

二、Android、JAVA加解密

public class AESUtil {
    private static final String AES = "AES";
    private static final String Mode = "AES/CBC/PKCS5Padding";

    private static Cipher cipherEncrypt;
    private static Cipher cipherDecrypt;
    /**
      * AES加密
      */
    public static String encrypt(String aPlaintext, String aKey) {
        String originalString = "";
        try {
            String tmpIv = aKey.substring(16, 32);
            SecretKeySpec keyspec = new SecretKeySpec(aKey.getBytes(), AES);
            IvParameterSpec ivspec = new IvParameterSpec(tmpIv.getBytes());
            cipherEncrypt = Cipher.getInstance(Mode);
            cipherEncrypt.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);

            byte[] encrypted = null;
            int blockSize = cipherEncrypt.getBlockSize();
            byte[] dataBytes = aPlaintext.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

            try {
                encrypted = cipherEncrypt.doFinal(plaintext);
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            if (encrypted == null) {
                LogUtils.e("算法加密错误!返回无结果");
                return null;
            }
            originalString = Base64.encodeToString(encrypted, Base64.DEFAULT);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }

        return originalString.trim();
    }
    /**
      * AES解密
      */
    public static String decrypt(String aCiphertext, String aKey) {
        String originalString = "";
        try {
            String tmpIv = aKey.substring(16, 32);
            SecretKeySpec keyspec = new SecretKeySpec(aKey.getBytes(), AES);
            IvParameterSpec ivspec = new IvParameterSpec(tmpIv.getBytes());
            cipherDecrypt = Cipher.getInstance(Mode);
            cipherDecrypt.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
            byte[] sourcebyte = Base64.decode(aCiphertext, Base64.DEFAULT);
            byte[] original = null;
            original = cipherDecrypt.doFinal(sourcebyte);
            try {
                originalString = new String(original, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            LogUtils.e("设置算法错误!");
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            LogUtils.e("解密算法密钥设置错误!");
            LogUtils.e("解密算法密钥长度不够,过长!");
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            LogUtils.e("算法解密过程错误!");
            LogUtils.e("块大小设置错误!密文长度不够或太长!");
            e.printStackTrace();
        } catch (BadPaddingException e) {
            LogUtils.e("解密算法解密过程错误!");
            LogUtils.e("解密填充方式错误!");
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return originalString.trim();
    }
}

如果文章对你有帮助,别忘了点个赞再走呀~

你可能感兴趣的:(个人笔记,AES加解密,iOS,java,android)