KMM项目iOS端CCCrypt解密AES报错4301问题排查
问题排查与解决方案
错误码4301说明
状态码4301对应kCCDecodeError,核心原因是解密时的参数、数据格式与加密端(PHP/Android)不匹配,或CCCrypt调用参数配置错误。
核心排查步骤
1. 核对加密参数一致性
确保iOS端的AES配置与Android/PHP完全对齐:
- 加密模式:Android用
CBC则iOS必须设kCCModeCBC,不能用ECB或其他模式; - 填充方式:Android的
PKCS5Padding与iOS的kCCOptionPKCS7Padding等价(块大小16位时无差异),若PHP/Android用NoPadding,iOS需设kCCOptionPKCS7Padding为0,且加密数据长度必须是16字节的整数倍; - 密钥长度:AES-128对应16字节密钥,AES-256对应32字节,需与服务端生成逻辑一致,避免密钥截断/填充差异。
2. 验证密钥、IV的字节转换逻辑
- 确认密钥、IV的编码方式(如UTF-8)与Android端完全相同,不能混用ASCII、UTF-16等编码;
- 若密钥是字符串转字节,需保证两端转换规则一致(比如PHP用
utf8_encode($key),iOS用[key dataUsingEncoding:NSUTF8StringEncoding])。
3. 检查加密数据完整性
即使Base64解码无报错,也要验证解码后的字节数组长度:
- 用PKCS7填充时,数据长度必须是16字节的整数倍;
- 若服务端加密后添加了额外校验(如HMAC),需先剥离校验部分再解密。
修正后的Objective-C解密示例
如果必须保留Objective-C实现,以下是符合标准AES-CBC+PKCS7填充的正确调用:
+ (NSData *)aesCBCDecrypt:(NSData *)encryptedData withKey:(NSData *)key iv:(NSData *)iv { NSUInteger dataLength = encryptedData.length; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t bytesDecrypted = 0; CCCryptorStatus status = CCCrypt( kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key.bytes, key.length, iv.bytes, encryptedData.bytes, encryptedData.length, buffer, bufferSize, &bytesDecrypted ); if (status == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:bytesDecrypted]; } free(buffer); return nil; }
注意:key和iv必须是NSData类型,且长度分别符合对应AES规格(16/24/32字节)、16字节。
更优替代方案:KMM统一加密逻辑
避免跨语言调用的参数差异,直接用Kotlin Multiplatform的加密库实现两端统一解密:
1. 添加依赖
在项目根build.gradle.kts中引入:
sourceSets { val commonMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-crypto-core:0.3.0") } } }
2. 统一解密代码
import kotlinx.crypto.ciphers.Cipher import kotlinx.crypto.ciphers.CipherMode import kotlinx.crypto.ciphers.Padding import kotlinx.crypto.ciphers.aes.AesCipher import kotlinx.crypto.core.SecretKey import kotlinx.crypto.core.toSecretKey fun decryptAesCbc(encryptedBytes: ByteArray, keyBytes: ByteArray, ivBytes: ByteArray): ByteArray { val secretKey = keyBytes.toSecretKey(AesCipher) val cipher = Cipher.getInstance(AesCipher, CipherMode.CBC, Padding.PKCS7) cipher.init(Cipher.Operation.DECRYPT, secretKey, ivBytes) return cipher.doFinal(encryptedBytes) }
这段代码可直接在Android和iOS端复用,彻底消除两端参数不一致的问题。
内容的提问来源于stack exchange,提问作者Bahaa Qurini
相关产品推荐
相关产品推荐

