使用openssl加密并使用AES 128,ecb模式在iPhone上解密

时间:2010-07-05 10:02:42

标签: iphone cocoa encryption aes

更新:找到了解决方案。我将很快用实际的工作代码和命令更新这个问题。


客户端正在使用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以外的其他内容?

2 个答案:

答案 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)字符相同。回想起来似乎看似合理,但它需要大量的头发拉动,因为每个加密失败看起来像其他所有加密失败:垃圾出来。