如何将此加密函数从 Swift 转换为 Objective-C?

How can I convert this encryption function from Swift to Objective-C?

我正在为 iOS Objective-C 应用程序 编写一个辅助函数,它应该使用 AES-128算法.

我已经在 Swift 中实现了此功能,但我正在努力 将其翻译Objective-C。该函数不考虑任何初始化向量,它被硬编码为空字符串:这是有意的。

这是按预期工作的 Swift 代码:

@objc func AES128(_ string: String, withKey: String) -> String {
    let data = string.data(using: String.Encoding.utf8)!
    let keyData = withKey.data(using: String.Encoding.utf8)!
    let ivData = "".data(using: String.Encoding.utf8)!
    
    let cryptLength = size_t(data.count + kCCBlockSizeAES128)
    var cryptData = Data(count: cryptLength)
    let keyLength = size_t(kCCKeySizeAES128)
    let options = CCOptions(kCCOptionPKCS7Padding)
    var numBytesEncrypted: size_t = 0

    let cryptStatus = cryptData.withUnsafeMutableBytes { cryptBytes in
        data.withUnsafeBytes { dataBytes in
            ivData.withUnsafeBytes { ivBytes in
                keyData.withUnsafeBytes { keyBytes in
                    CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), options, keyBytes, keyLength, ivBytes, dataBytes, data.count, cryptBytes, cryptLength, &numBytesEncrypted)
                }
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)
    }

    return cryptData.base64EncodedString();
}

这个函数就像一个魅力,用密钥 ABCDEFGHIJKLMNOP 加密字符串 Hello World 得到一个 base64 编码的字符串 3G4OU62dM9zXhkbXy8pmuA==.

我翻译成Objective-C:

+(NSString *)AES128:(NSString *)string withKey:(NSString *)key {
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [@"" dataUsingEncoding:NSUTF8StringEncoding];
    
    size_t cryptLength  = data.length + kCCBlockSizeAES128;
    NSMutableData *cryptData = [NSMutableData dataWithLength:cryptLength];
    size_t keyLength = kCCKeySizeAES128;
    CCOptions options = kCCOptionPKCS7Padding;
    size_t numBytesEncrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES, options, keyData.bytes, keyLength, ivData.bytes, data.bytes, data.length, cryptData.mutableBytes, cryptLength, &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess) {
        [cryptData replaceBytesInRange:NSMakeRange(numBytesEncrypted, cryptData.length - numBytesEncrypted) withBytes:NULL length:0];
    }

    return [cryptData base64EncodedStringWithOptions:0];
}

问题是 Objective-C 版本提供了错误的结果,我会说是随机结果,生成相同的 Hello World + ABCDEFGHIJKLMNOP 不同加密值的组合。 7m+HH5NusyA1VAfZ78KYCw==NY5p8XtYLoAE/4VbCCrPIg== 是其中的一些错误值。 如果你解密这些字符串,你将分别得到 Hello WoldHello Worod

翻译时我做错了什么?

感谢您的热心帮助!

这似乎是您处理初始化向量的问题。如果您注意到,CCCrypt 函数接受一个指向您的 IV 的字节缓冲区内容的指针,但您没有提供长度参数。这意味着缓冲区的长度是已知的。

根据维基百科 (https://en.wikipedia.org/wiki/Initialization_vector),IV 的长度“通常是密码的块大小”。

所以基本上,当你在做的时候

NSData *ivData = [@"" dataUsingEncoding:NSUTF8StringEncoding];

ivData.bytes 属性 现在会指向某个地方,在最好的情况下,它的全长会是 0x00,但很可能不会。 CCCrypt() 函数将从您传递的内存地址(指向空数组的指针)开始,并使用它在那里找到的任何随机数据继续读取下一个 [IV Length] 字节。

要解决此问题,您需要以某种方式确保将指针传递给包含所有零的预期内容的缓冲区。

我只是用

做了这个
void* ivBuffer = calloc(1, kCCBlockSizeAES128);

它分配一个 128 位(16 字节)的块并用全零初始化它。

你对 CCCrypt() 的调用就变成了

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES, options, keyData.bytes, keyLength, ivBuffer, data.bytes, data.length, cryptData.mutableBytes, cryptLength, &numBytesEncrypted);

你只需要记住调用 free(ivBuffer) 来释放分配给这个缓冲区的内存。

另外,当你处理成功状态时,你可以这样做

if (cryptStatus == kCCSuccess)
{
    cryptData.length = numBytesEncrypted;
}

它会将数据截断为您要使用的部分。由您决定,因为结果与您已经拥有的结果相同。