更新:找到了解决方案。我将很快用实际的工作代码和命令更新这个问题。
客户端正在使用C ++加密文件服务器端,我需要在iPhone应用程序中对其进行解密。
我的客户端可以在他身边加密和解密,我在iPhone上也是如此,但是我们无法解密彼此加密的文件。 我在SO上看到了许多相关的问题,但是没有一个可以帮助我找到一个在两边都以相同方式工作的实现。
我想输出一些我们将接受的样本值作为常见实现。
我尝试使用openssl加密文件并使用cocoa解密,但不能。
以下是我用于加密的内容:
echo "123456789ABCDEFG" | openssl enc -aes-128-ecb -nosalt -K "41414141414141414141414141414141" -iv 0 > hello.txt.bin
将选项-p添加到openssl调用会显示使用了预期的键和iv:
key=41414141414141414141414141414141
iv =00000000000000000000000000000000
对于可可解密(在NSData类别中):
- (NSData *)AESDecryptWithKey:(NSString *)key {
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
char iv[32];
for (int i = 0; i < 32; i++) {
iv[i] = 0;
}
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
iv, //"00000000000000000000000000000000" /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
这样叫:
- (void)testBinaryFileDecryption {
NSString *databasePath = [[NSBundle mainBundle] pathForResource:@"hello" ofType:@"txt.bin"];
NSData *data = [NSData dataWithContentsOfFile:databasePath];
NSAssert(nil != data, @"Encrypted data, freshly loaded from file should not be nil");
NSData *plain = [data AESDecryptWithKey:@"AAAAAAAAAAAAAAAA"];
NSAssert(nil != plain, @"Decrypted plain data should not be nil");
NSLog(@"Result: '%@'", [[NSString alloc] initWithData:plain encoding:NSASCIIStringEncoding]);
}
结果日志:
Result: '4¨µ¢Ä½Pk£N
我忘记了什么选择? NSData的编码是否返回了NSASCIIStringEncoding以外的其他内容?
答案 0 :(得分:2)
我对iPhone开发一无所知,但看看这段代码,你似乎正在尝试使用实际密钥的ascii-of-hex编码来解密数据包。 OpenSSL的enc需要十六进制编码,因为它将十六进制转换为字节。当直接转换为ascii时,实际键看起来更像是这样。
["\037", " ", "!", "\"", "#", "$", "%", "&", "'", "\036", "\037", " ", "!", "\"", "#", "$"]
(所有这些都可能是钝的。如果您要将用于解密的字符串编码为OpenSSL enc接受的相同格式,则密钥为3331333233333334333533363337333833393330333133323333333433353336
。)
尝试将41414141414141414141414141414141
的密钥规范用于OpenSSL,并在iPhone代码中使用AAAAAAAAAAAAAAAA
。
另外,我强烈建议您使用N * 16字节长的数据进行初始测试。 OpenSSL enc使用PKCS#5填充(除非您使用-nopad
),并且您的iPhone代码使用PKCS#7填充。粗略地看一下RFC,它们似乎是相同的填充机制,但我可能是错的。
我知道你只是在这里尝试,但在实际的生产代码中,请不要使用ECB mode。
答案 1 :(得分:2)
我正在使用Crypt :: OpenSSL :: AES来加密在我的iOS应用中解密的文件,这些文件使用CommonCryptor解密。
cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0,
keyPtr, kCCKeySizeAES256,
IVECTOR /* initialization vector (optional) -- was NULL*/,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
初始化IVECTOR我正在使用bzero。
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
要在perl中的OpenSSL下加密,我这样做:
my $cipher = Crypt::CBC->new( -key => $key,
-literal_key => 1,
-header => 'none',
-iv => '0000000000000000',
-cipher => 'Crypt::OpenSSL::AES' );
OpenSSL似乎接受'0000000000000000'IV与ASCII 0(null)字符相同。回想起来似乎看似合理,但它需要大量的头发拉动,因为每个加密失败看起来像其他所有加密失败:垃圾出来。