背景:由于业务需要,对移动端页面中的链接需要做加解密处理。后端加密完成后前端(iOS、Android)解密。Android拿着key成功解密,十分钟搞定(这不简简单单~)。iOS拿着key解密,不是解密出来乱码,就是nil,半天过去了还没搞定(真的栓Q)。
下边放上经过不懈努力成功解密的代码,iOS、Android、JAVA可以互相加解密,有需要的直接复制使用。
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
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();
}
}