老项目里关于AES埋的坑
起因
// YYCategories / NSData+YYAdd / AES256解密方法(虽然方法名写的是AES256,实际上用的是AES128)
- (NSData *)aes256DecryptWithkey:(NSData *)key iv:(NSData *)iv {
if (key.length != 16 && key.length != 24 && key.length != 32) {
return nil;
}
if (iv.length != 16 && iv.length != 0) {
return nil;
}
NSData *result = nil;
size_t bufferSize = self.length + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
if (!buffer) return nil;
size_t encryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
iv.bytes,
self.bytes,
self.length,
buffer,
bufferSize,
&encryptedSize);
if (cryptStatus == kCCSuccess) {
result = [[NSData alloc]initWithBytes:buffer length:encryptedSize];
free(buffer);
return result;
} else {
free(buffer);
return nil;
}
}
一句话真因
可以用的AES256解密方法
// aes256解密
- (NSString *)aes256Decrypt:(NSString *)ciphertext withPassword:(NSString *)password {
if (ciphertext.length == 0 || password.length == 0) {
return nil;
}
NSData *cipherData = [[NSData alloc] initWithBase64EncodedString:ciphertext options:0];
if (!cipherData) {
return nil;
}
const char saltHeader[] = "Salted__"; // OpenSSL salted prefix
NSData *decrypted = nil;
if (cipherData.length > 16 && memcmp(cipherData.bytes, saltHeader, 8) == 0) {
// OpenSSL salted format: "Salted__" + 8 bytes salt + encrypted
NSData *salt = [cipherData subdataWithRange:NSMakeRange(8, 8)];
NSData *encData = [cipherData subdataWithRange:NSMakeRange(16, cipherData.length - 16)];
// Derive key and IV using OpenSSL EVP_BytesToKey (MD5)
NSMutableData *derived = [NSMutableData data];
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *previous = nil;
while (derived.length < (kCCKeySizeAES256 + kCCBlockSizeAES128)) {
// MD5(previous + password + salt) using one-shot CC_MD5; wrap with pragma to silence deprecation diagnostics
NSMutableData *mdInput = [NSMutableData data];
if (previous) {
[mdInput appendData:previous];
}
[mdInput appendData:passwordData];
[mdInput appendData:salt];
unsigned char md[CC_MD5_DIGEST_LENGTH];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CC_MD5(mdInput.bytes, (CC_LONG)mdInput.length, md);
#pragma clang diagnostic pop
previous = [NSMutableData dataWithBytes:md length:CC_MD5_DIGEST_LENGTH];
[derived appendBytes:md length:CC_MD5_DIGEST_LENGTH];
}
NSData *key = [derived subdataWithRange:NSMakeRange(0, kCCKeySizeAES256)];
NSData *iv = [derived subdataWithRange:NSMakeRange(kCCKeySizeAES256, kCCBlockSizeAES128)];
size_t outLength = encData.length + kCCBlockSizeAES128;
void *outBuf = malloc(outLength);
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
iv.bytes,
encData.bytes,
encData.length,
outBuf,
outLength,
&numBytesDecrypted);
if (status == kCCSuccess) {
decrypted = [NSData dataWithBytesNoCopy:outBuf length:numBytesDecrypted freeWhenDone:YES];
} else {
free(outBuf);
return nil;
}
} else {
// Fallback: assume raw AES256-CBC with key = SHA256(password), iv = zeros
NSData *encData = cipherData;
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
unsigned char keybuf[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(passwordData.bytes, (CC_LONG)passwordData.length, keybuf);
unsigned char ivZero[kCCBlockSizeAES128];
memset(ivZero, 0, sizeof(ivZero));
size_t outLength = encData.length + kCCBlockSizeAES128;
void *outBuf = malloc(outLength);
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
keybuf,
kCCKeySizeAES256,
ivZero,
encData.bytes,
encData.length,
outBuf,
outLength,
&numBytesDecrypted);
if (status == kCCSuccess) {
decrypted = [NSData dataWithBytesNoCopy:outBuf length:numBytesDecrypted freeWhenDone:YES];
} else {
free(outBuf);
return nil;
}
}
if (!decrypted) return nil;
NSString *plaintext = [[NSString alloc] initWithData:decrypted encoding:NSUTF8StringEncoding];
return plaintext;
}
Written on September 20, 2025
