objective-c - 即使没有 IV,AES CBC 中的 CCCrypt 解密也能正常工作

标签 objective-c cryptography commoncrypto

我有一个令人困惑的问题,在解密使用 CCCrypt 的 AES-CBC 模式和随机的 16 字节 IV 加密的文件时,无论我传入用于加密的相同正确 IV 还是根本没有传递,都会产生完全相同的输出。

我期望的是:使用 NULL IV 进行解密不应导致正确的解密。 我观察到:使用 NULL IV 会产生与用于加密的 IV 相同的结果。

为了完整起见,下面是重要的代码片段,iv 作为 16 字节安全随机化的 NSData 传入。

我在这里不明白什么? CCCrypt 是否以某种方式自行从加密数据中计算出 IV?我在文档中找不到任何相关内容。

- (NSData *)encryptedDataForData:(NSData *)rawData
                         withKey:(NSData *)key
                              iv:(NSData *)iv
                           error:(NSError __autoreleasing**)error
{
    size_t outLength;
    NSMutableData *cipherData = [NSMutableData dataWithLength:rawData.length + kAlgorithmBlockSize];

    CCCryptorStatus result = CCCrypt(kCCEncrypt,
                                     kCCAlgorithmAES128,
                                     kCCOptionPKCS7Padding | kCCModeCBC,
                                     key.bytes,
                                     key.length,
                                     iv.bytes,
                                     rawData.bytes,
                                     rawData.length,
                                     cipherData.mutableBytes,
                                     cipherData.length,
                                     &outLength);
    if (result == kCCSuccess) {
        cipherData.length = outLength;
        return cipherData;
    } else {
        return nil;
    }
}

- (NSData *)decryptedDataForData:(NSData *)encryptedData withKey:(NSData *)key error:(NSError __autoreleasing**)error
{
    size_t outLength;
    NSMutableData *decryptedData = [NSMutableData dataWithLength:encryptedData.length];

    // this line is just to illustrate how setting the exact same iv here - if this one
    // was used for encryption - results in same output as when passing iv = NULL
    NSData *iv = [Cryptor dataForHex:@"724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb"];

    CCCryptorStatus result = CCCrypt(kCCDecrypt,
                                     kCCAlgorithmAES128,
                                     kCCOptionPKCS7Padding | kCCModeCBC,
                                     key.bytes,
                                     key.length,
                                     iv.bytes, // iv OR NULL --> same result o_O
                                     encryptedData.bytes,
                                     encryptedData.length,
                                     decryptedData.mutableBytes,
                                     decryptedData.length,
                                     &outLength);
    if (result == kCCSuccess) {
        decryptedData.length = outLength;
        return decryptedData;
    } else {
        return nil;
    }
}

编辑:

为了详细说明这一点,无论我使用哪个 IV 进行解密(尝试了几个不同的随机 IV),我总是逐字节得到相同的结果。即使我只解密加密文件中间某处的部分加密文件 block 。

这可能与我正在加密/解密的实际数据(mp3 文件)有关吗?

当我只是将实际加密文件的任意 block 传递给解密器时,它不应该要求该 block 数据(我没有明确提供为 IV)之前的 block 来进行正确的解密吗?我个人能想到的唯一解释是 CCCrypt 总是使用前 16 个字节作为 IV 并且不解密它们而是将它们丢弃在输出中。

编辑 2:

加密/解密的输出,显示输入和输出数据的前两个 block , key 和 iv:

# encryption
data <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>
iv <724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb>
key <78656a1a 337fddd6 fa52e34d 9156d187>
encrypted <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>

# decryption with correct IV
data <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>
iv <724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb>
key <78656a1a 337fddd6 fa52e34d 9156d187>
decrypted <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>

# decryption with zero IV
data <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>
iv <00000000 00000000 00000000 00000000>
key <78656a1a 337fddd6 fa52e34d 9156d187>
decrypted <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>

# decryption with different IV
data <cf85cdbe 10a87309 a6fb4c4e ce640619 8f445b70 3738018a e78291a7 b4ea26ce>
iv <12345678 9abcdef1 23456789 abcdef12>
key <78656a1a 337fddd6 fa52e34d 9156d187>
decrypted <4cd9b050 30c04bf9 2a0cb024 19010a31 400c2261 0069196a d77bcae6 9799ae26>

编辑 3:

-dataForHex: 的代码是:

+ (NSData *)dataForHex:(NSString *)hex
{
    NSString *hexNoSpaces = [[[hex stringByReplacingOccurrencesOfString:@" " withString:@""]
            stringByReplacingOccurrencesOfString:@"<" withString:@""]
            stringByReplacingOccurrencesOfString:@">" withString:@""];

    NSMutableData *data = [[NSMutableData alloc] init];
    unsigned char whole_byte = 0;
    char byte_chars[3] = {'\0','\0','\0'};
    for (NSUInteger i = 0; i < [hexNoSpaces length] / 2; i++) {
        byte_chars[0] = (unsigned char) [hexNoSpaces characterAtIndex:(NSUInteger) (i * 2)];
        byte_chars[1] = (unsigned char) [hexNoSpaces characterAtIndex:(NSUInteger) (i * 2 + 1)];
        whole_byte = (unsigned char)strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];
    }
    return data;
}

最佳答案

还值得指出的是,永远不要将模式与填充选项一起包含在内。我已经看到很多这样的事情了,实际上我也陷入了同样的陷阱,试图成为一个“尽可能明确的人”。

kCCOptionPKCS7Padding | kCCModeCBC

应该是:

kCCOptionPKCS7Padding

有趣的事实 1: kCCModeEBCkCCOptionPKCS7Padding 共享相同的值:1,并且实际上评估为使用 kCCOptionPKCS7Padding,然后默认为 kCCModeCBC

有趣的事实 2: 使用 kCCOptionPKCS7Padding | kCCModeCBC 评估为 kCCOptionPKCS7Padding 标志和 kCCOptionECBMode 被设置,这实际上导致 kCCModeEBC 被使用。

关于objective-c - 即使没有 IV,AES CBC 中的 CCCrypt 解密也能正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27014292/

相关文章:

objective-c - 有没有关于如何使用 Cocoa 在 Objective-C 中为 Mac OS X 编写全屏应用程序的示例?

objective-c - 在 Cocoa 应用程序中动态加载自定义插件(库)

php - PHP 的 mcrypt 扩展是否符合 FIPS 197 标准?

ios - 将 CommmonCrypto 库导入 Swift 项目

objective-c - 找不到 kSecRandomDefault?

iphone - 在滑动通知解锁后将用户重定向到我的应用程序的特定屏幕

ios - 如何在 ios-charts 上添加标记?

java - Blowfish GoLang加密与Java解密

cryptography - 如何将 ECDSA 曲线规范从 SEC2 形式转换为 Go 需要的形式?