两种AES算法之间的互操作性 [英] Interoperability between two AES algorithms

查看:127
本文介绍了两种AES算法之间的互操作性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚加密,我正在构建一些测试应用程序来尝试了解它的基础知识。我不是从头开始构建算法,而是尝试使两个不同的AES-256实现对话。



我有一个数据库这是由存储在Base64中的此Javascript实现填充的。现在,我试图获得一个Objective-C方法来解密它的内容,但是对于实现方面的差异,我有点失落。我可以在Javascript中进行加密/解密,我可以在Cocoa中进行加密/解密,但是不能使用Cocoa解密的Javascript加密字符串,反之亦然。



我猜测它与初始化向量,nonce,counter操作模式或所有这些相关,坦白说,这不符合我的意图。



这是我在Objective-C中使用的,主要从这个这个

  @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 *)输入键:(NSString *)键doEncrypt:(BOOL)doEncrypt {
//'key' 32位字节用于AES256,否则将为零填充
char keyPtr [kCCKeySizeAES256 + 1]; //用于终结器的空间(未使用)
bzero(keyPtr,sizeof(keyPtr)); //填充零(用于填充)
//获取密钥数据
[key getCString:keyPtr maxLength:sizeof(keyPtr)encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [输入长度];
//参见文档:对于块密码,输出大小始终小于或等于输入大小加上一个块的大小。
//这就是为什么我们需要在这里添加一个块的大小
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,//初始化vector(可选)
[input bytes],dataLength,// input
buffer,bufferSize,//输出
& numBytesCrypted
);
if(cryptStatus == kCCSuccess){
//返回的NSData获取缓冲区的所有权,并在释放后释放它
return [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
}
free(buffer); //释放缓冲区;
return nil;
}

@end

当然,输入是Base64预先解码。



我看到,Javascript中具有相同密钥和相同内容的每个加密都提供了不同的加密字符串,Objective-C实现不是这样总是给出相同的加密字符串。我已经阅读了这篇文章的答案,它让我相信我'对于关于向量初始化的一些事情,我需要你的帮助来准确地确定发生了什么。



谢谢!

解决方案

Yup,有一些两个实现之间的差异。




  • 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代码分布在多个帖子中,我没有找到相关代码。



I'm new to cryptography and I'm building some test applications to try and understand the basics of it. I'm not trying to build the algorithms from scratch but I'm trying to make two different AES-256 implementation talk to each other.

I've got a database that was populated with this Javascript implementation stored in Base64. Now, I'm trying to get an Objective-C method to decrypt its content but I'm a little lost as to where the differences in the implementations are. I'm able to encrypt/decrypt in Javascript and I'm able to encrypt/decrypt in Cocoa but cannot make a string encrypted in Javascript decrypted in Cocoa or vice-versa.

I'm guessing it's related to the initialization vector, nonce, counter mode of operation or all of these, which quite frankly, doesn't speak to me at the moment.

Here's what I'm using in Objective-C, adapted mainly from this and this:

@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

Of course, the input is Base64 decoded beforehand.

I see that each encryption with the same key and same content in Javascript gives a different encrypted string, which is not the case with the Objective-C implementation that always give the same encrypted string. I've read the answers of this post and it makes me believe I'm right about something along the lines of vector initialization but I'd need your help to pinpoint what's going on exactly.

Thank you!

解决方案

Yup, there are a number of differences between the two implementations.

  • The Javascript implementation uses CTR mode while the Objective-C implementation uses ECB mode (ECB is weak and should not be used.)

  • The Javascript implemenation uses a key expansion. I.e. it transforms the key before passing it to the AES code. Not sure about the Objective-C implementation. Anyway, you can almost be sure that the two implementations are not using the same key for the encryption.

  • The Javascript implementation uses the current time to generate a 8 byte IV that is prepended to the ciphertext. This IV is used to initialize the counter for the CTR mode. Because of the IV changes, encrypting the same plaintext twice will result in different ciphertexts. Also using the current time for generating an IV for CTR mode is ok, as long as you don't encrypt two ciphertexts within the same clock tick(). The Objective-C implementation doesn't use an IV (since it uses ECB mode).

  • The Objective-C code uses PKCS #7 padding, the Javascript code uses none. This is a consequence of using distinct encryption modes.

  • Furthermore, you also have to check, how the ciphertext is encoded. The Javascript code uses Base64 encoding. The Objective-C code is too much distributed over several postings, that I didn't find the relevant code.

这篇关于两种AES算法之间的互操作性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆