【问题标题】:Interoperability between two AES algorithms两种 AES 算法之间的互操作性
【发布时间】:2011-02-01 13:17:25
【问题描述】:

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

我有一个数据库,其中填充了this Javascript implementation,存储在 Base64 中。现在,我正在尝试使用 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 的答案,这让我相信我对向量初始化方面的一些事情是正确的,但我需要你的帮助来确定到底发生了什么。

谢谢!

【问题讨论】:

  • 你找到让两人说话的方法了吗?我面临着完全相同的问题,但我无法找到一种方法来完成这项工作。感谢任何帮助。谢谢。
  • @Ipfavreau,我遇到了和你一样的问题。你解决了吗?谢谢!
  • @AlexR,不,我没有解决它。 Accipitridae 说的是真的:两种实现方式存在差异,并没有走这条路线。

标签: javascript objective-c cocoa encryption aes


【解决方案1】:

对于测试,您应该考虑使用来自NIST website for AESFIPS 197 的测试值。

【讨论】:

  • 我如何解释结果?如果我已经知道两种实现的结果加密字符串不同,我将从这些值中学到什么?
【解决方案2】:

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

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

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

  • Javascript 实现使用当前时间生成一个 8 字节的 IV,该 IV 被添加到密文中。该 IV 用于初始化 CTR 模式的计数器。 由于 IV 的变化,对相同的明文进行两次加密会产生不同的密文。也可以使用当前时间为 CTR 模式生成 IV,只要您不在同一时钟 tick() 内加密两个密文。 Objective-C 实现不使用 IV(因为它使用 ECB 模式)。

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

  • 此外,您还必须检查密文的编码方式。 Javascript 代码使用 Base64 编码。 Objective-C 代码过于分散在几个帖子中,我没有找到相关代码。

【讨论】:

  • 我还注意到您的 Objective-C 代码显示 kCCAlgorithmAES128,但您的文本显示您正在尝试实现 AES-256。您是否不小心使用了较小的块大小?
  • 感谢您的回答。关于块大小,我在 Objective-C 中看到的所有 AES256 实现(使用默认的 CCCrypt)都使用 kCCAlgorithmAES128 作为块大小,我知道没有可用的 kCCAlgorithmAES256。我对密码学了解不多,我不能说这是否会产生影响或者是否是标准做法。关于编码,两者都使用 Base64 作为生成的加密文本。
  • AES 的块大小始终为 128 位。但是,密钥大小可能会有所不同。 IE。密钥大小可以是 128、192 或 256 位。因此,上面关于块和​​密钥大小的规范看起来没问题。
猜你喜欢
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-09-13
  • 2011-03-16
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多