我有一个令人困惑的问题,即解密使用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),我总是得到相同结果的字节。即使我只从加密文件的中间某处解密加密文件的一些部分块。
这可能与我正在/解密(mp3文件)的实际数据有关吗?
当我只是将实际加密文件的一些任意块传递给解密器时,不应该在该数据块(我没有明确提供为IV)之前需要块来进行正确的解密?我个人可以想到的唯一解释是CCCrypt只使用前16个字节作为IV并且不解密那些但是将它们丢弃在输出中。
编辑2:
输入en / decryption,显示输入数据的前两个块,键和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;
}
答案 0 :(得分:6)
值得指出的是,永远不应该包含带有填充选项的模式。我已经看到了很多这样的事情,而且我实际上陷入了同样的陷阱,试图成为一个尽可能明确的&#34;。
kCCOptionPKCS7Padding | kCCModeCBC
应该是:
kCCOptionPKCS7Padding
有趣的事实1: kCCModeEBC
和kCCOptionPKCS7Padding
共享相同的值:1,实际上会评估为使用kCCOptionPKCS7Padding
,然后默认为kCCModeCBC
。
有趣的事实2:使用kCCOptionPKCS7Padding | kCCModeCBC
评估设置的kCCOptionPKCS7Padding
标记和kCCOptionECBMode
,这实际上导致kCCModeEBC
被使用。
答案 1 :(得分:5)
用于格式化评论。
用iv:
clear data: <4cd9b050 30c04bf9 2a0cb024 19010a31>
iv data: <724a7fc0 0d8ac9d5 f09ff4c1 64d2d1bb>
key data: <78656a1a 337fddd6 fa52e34d 9156d187>
crypt data: <d2c2efee 54e43781 549eec03 9db688e1 7c4248e7 e2ac1d80 7105ffae 4043ffb3>
decrypt data: <4cd9b050 30c04bf9 2a0cb024 19010a31>
iv为0:
clear data: <4cd9b050 30c04bf9 2a0cb024 19010a31>
iv data: <00000000 00000000 00000000 00000000>
key data: <78656a1a 337fddd6 fa52e34d 9156d187>
crypt data: <cf85cdbe 10a87309 a6fb4c4e ce640619 6be7b155 9db3f066 97e461e7 ced7960f>
decrypt data: <4cd9b050 30c04bf9 2a0cb024 19010a31>
很明显,iv代码中没有使用iv。
以上代码:
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt, // kCCEncrypt or kCCDecrypt
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
key.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
dataOut.length = cryptBytes;
答案 2 :(得分:3)
iv仅用于解密的第一个块,更多块使用前一个块的密文,因此它有点自同步。
维基百科图片:
来自维基百科Block cipher mode of operation。
因此,在块边界上的CBC加密流中间拾取解密工作除了第一个块之外。
答案 3 :(得分:0)
您可以在此处阅读正确的答案: http://www.remote-exploit.org/archives/2012/01/09/the_apple_idioten_vektor_iv/
Apple在其加密库中出错,假设如果未提供IV向量,则会自动将IV设置为零向量而不是返回错误。应始终提供IV以确保最佳安全性,并且Apple不应该做出零假设,因为它会大大削弱安全性并使其易受攻击。