两种AES算法之间的互操作性

时间:2010-03-27 15:12:37

标签: javascript objective-c cocoa encryption aes

我是密码学的新手,我正在构建一些测试应用程序来尝试理解它的基础知识。我不打算从头开始构建算法,但我试图让两个不同的AES-256实现相互通信。

我有一个数据库,其中填充了存储在Base64中的this Javascript implementation。现在,我正在尝试使用Objective-C方法来解密其内容,但我对实现中的差异在哪里有点迷失。我能够在Javascript中加密/解密,我能够在Cocoa中加密/解密,但不能在Cocoa中解密的Javascript中加密字符串,反之亦然。

我猜它与初始化向量,nonce,计数器操作模式或所有这些有关,坦率地说,此刻并没有对我说话。

以下是我在Objective-C中使用的内容,主要适用于thisthis

@implementation NSString (Crypto)

- (NSString *)encryptAES256:(NSString *)key {
    NSData *input = [self dataUsingEncoding: NSUTF8StringEncoding]; 
    NSData *output = [NSString cryptoAES256:input key:key doEncrypt:TRUE];  
    return [Base64 encode:output];
}

- (NSString *)decryptAES256:(NSString *)key {
    NSData *input = [Base64 decode:self];
    NSData *output = [NSString cryptoAES256:input key:key doEncrypt:FALSE];
    return [[[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding] autorelease];
}

+ (NSData *)cryptoAES256:(NSData *)input key:(NSString *)key doEncrypt:(BOOL)doEncrypt {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256 + 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 = [input 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 numBytesCrypted = 0;
    CCCryptorStatus cryptStatus =
        CCCrypt(doEncrypt ? kCCEncrypt : kCCDecrypt,
            kCCAlgorithmAES128,
            kCCOptionECBMode | kCCOptionPKCS7Padding,
            keyPtr, kCCKeySizeAES256,
            nil, // initialization vector (optional)
            [input bytes], dataLength, // input
            buffer, bufferSize, // output
            &numBytesCrypted
        );  
    if (cryptStatus == kCCSuccess) {
        // the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
    }   
    free(buffer); // free the buffer;
    return nil;
}

@end

当然,输入是事先解码的Base64。

我看到Javascript中具有相同密钥和相同内容的每个加密都给出了不同的加密字符串,而Objective-C实现总是提供相同的加密字符串。我已经阅读了this post的答案,这让我相信我对矢量初始化的某些方面是正确的,但是我需要你的帮助来确定究竟发生了什么。

谢谢!

2 个答案:

答案 0 :(得分:3)

是的,两种实现之间存在许多差异。

  • Javascript实现使用CTR模式,而Objective-C实现使用ECB模式(ECB很弱,不应使用。)

  • Javascript实现使用密钥扩展。即它在将密钥传递给AES代码之前转换密钥。不确定Objective-C的实现。无论如何,您几乎可以确定这两个实现没有使用相同的密钥进行加密。

  • Javascript实现使用当前时间生成一个前缀为密文的8字节IV。此IV用于初始化CTR模式的计数器。 由于IV的变化,两次加密相同的明文将导致不同的密文。只要不在同一时钟tick()内加密两个密文,也可以使用当前时间为CTR模式生成IV。 Objective-C实现不使用IV(因为它使用ECB模式)。

  • Objective-C代码使用PKCS#7填充,Javascript代码不使用。这是使用不同加密模式的结果。

  • 此外,您还必须检查密文是如何编码的。 Javascript代码使用Base64编码。 Objective-C代码分布在多个帖子上,我找不到相关的代码。

答案 1 :(得分:0)

为了进行测试,您应该考虑使用NIST website for AESFIPS 197中的测试值。