iOS上的AES-256加密不会产生与openssl相同的结果

时间:2021-11-10 03:29:53

I have been looking and looking at this for hours. I am desperately trying to get iOS to encrypt a short piece of text using AES-256 encryption that can then be decrypted by openssl.

我已经看了几个小时了。我迫切地想让iOS用AES-256加密一段短文本,然后用openssl解密。

Straight forward? Nope.

直接吗?不。

The code I've found for iOS is not compatible with the keys and IVs for openssl, so I've had to adapt it, but it's plainly not working.

我为iOS找到的代码与openssl的密钥和IVs不兼容,所以我不得不对它进行调整,但它显然不起作用。

So here is the code to encrypt I am using... passing in a string to encrypt (dataString) a string key (key) and a string initialisation vector (iv)...

这是我正在使用的加密代码。传递一个字符串来加密(dataString)一个字符串键(key)和一个字符串初始化向量(iv)…

- (NSData *)AES256Encrypt:(NSString *)dataString WithKey:(NSString *)key iv:(NSString *)iv {

    // '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];

    //NSLog(@"keyPtr: '%s'", keyPtr);

    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"keyPtr: '%s'", keyData.bytes);
    NSData *dataToEncrypt = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [iv dataUsingEncoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [dataToEncrypt 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;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyData.bytes, kCCKeySizeAES256,
                                          ivData.bytes, // initialisation vector
                                          dataToEncrypt.bytes, 
                                          dataToEncrypt.length, /* 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;
}

For the same string to encode, this does not produce the same value as when using openssl with the same key and iv... e.g. this command line:

对于要编码的相同字符串,这不会产生与使用带有相同键和iv的openssl时相同的值……例如,这个命令行:

openssl enc -aes-256-cbc -e -in secrets.txt -a -iv 0000 -K 0000 -p

secrets.txt is just a text file containing the string to be encrypted

的秘密。txt是一个包含要加密的字符串的文本文件

This outputs something like this:

输出如下所示:

salt=3C66000000000000
key=0000000000000000000000000000000000000000000000000000000000000000
iv =00000000000000000000000000000000
qTMfgtAxbF8Yyh27ZDrcIQ==

And to decrypt, do the opposite operation (assuming the encrypted last line of data above is in test.secrets.out)

要解密,则执行相反的操作(假设上面加密的最后一行数据在test. secre. out中)

openssl enc -aes-256-cbc -d -in test.secrets.out -a -iv 0000 -K 0000 -p 
salt=3C66000000000000
key=0000000000000000000000000000000000000000000000000000000000000000
iv =00000000000000000000000000000000
< text of the secrets.txt file >

Now, if I use the key and iv of 4 chars, this doesn't encode correctly in iOS. If I use the full length key and iv, this doesn't encode correctly either.

现在,如果我使用4个字符的键和iv,这在iOS中不能正确编码。如果我使用全长键和iv,这也不能正确编码。

Basically, this is a check to see that if I send a piece of encrypted data it is the right piece of data.

基本上,这是一个检查,如果我发送一个加密数据它就是正确的数据。

What am I missing?

我缺少什么?

Some code I've looked through to try to find an answer...

我看过的一些代码试图找到答案……

http://robnapier.net/blog/aes-commoncrypto-564

http://robnapier.net/blog/aes - commoncrypto - 564

https://github.com/rnapier/RNCryptor

https://github.com/rnapier/RNCryptor

http://pastie.org/426530

http://pastie.org/426530

Have searched extensively on here too and cannot find an answer.

在这里也搜了很多遍,找不到答案。

Any help appreciated.

任何帮助表示赞赏。

1 个解决方案

#1


2  

OpenSSL has a unique (read "not close to any standard, and also not particularly secure") method for converting passwords into IV and key. If you look at RNOpenSSLCryptor, you'll see the algorithm used:

OpenSSL有一个独特的(读作“不接近任何标准,也不是特别安全”)方法,用于将密码转换为IV和key。如果你观察RNOpenSSLCryptor,你会看到算法的使用:

// For aes-128:
//
// key = MD5(password + salt)
// IV = MD5(Key + password + salt)

//
// For aes-256:
//
// Hash0 = ''
// Hash1 = MD5(Hash0 + Password + Salt)
// Hash2 = MD5(Hash1 + Password + Salt)
// Hash3 = MD5(Hash2 + Password + Salt)
// Hash4 = MD5(Hash3 + Password + Salt)
//
// Key = Hash1 + Hash2
// IV = Hash3 + Hash4
//

// File Format:
//
// |Salted___|<salt>|<ciphertext>|
//

Using RNOpenSSLCryptor allows RNCryptor support for the OpenSSL format. I am currently in the midst of reworking this code on the async branch to support async operations, and that branch doesn't yet support OpenSSL, but I do plan to rework that shortly (by mid-July 2012).

使用RNOpenSSLCryptor允许RNCryptor支持OpenSSL格式。我目前正在修改异步分支上的代码,以支持异步操作,而该分支还不支持OpenSSL,但我确实计划在不久之后(到2012年7月中旬)进行修改。

If you want code that implements this for your own use, look at keyForPassword:salt: and IVForKey:password:salt:.

如果您想要实现此功能的代码,请查看keyForPassword:salt和IVForKey:password:salt:。

Note that the the OpenSSL file format has several security problems and I don't recommend it if you can avoid it. It does not use a very good KDF to generate its key, does not have as random an IV as it should, and provides no HMAC for authentication. These security problems are why I designed a different file format, much as I hated creating "yet another incompatible container."

注意,OpenSSL文件格式有几个安全问题,如果可以避免,我不建议这样做。它不使用一个非常好的KDF来生成它的密钥,不像它应该的那样具有任意的IV,并且不提供用于身份验证的HMAC。这些安全问题就是为什么我设计了不同的文件格式,就像我讨厌创建“另一个不兼容的容器”一样。

#1


2  

OpenSSL has a unique (read "not close to any standard, and also not particularly secure") method for converting passwords into IV and key. If you look at RNOpenSSLCryptor, you'll see the algorithm used:

OpenSSL有一个独特的(读作“不接近任何标准,也不是特别安全”)方法,用于将密码转换为IV和key。如果你观察RNOpenSSLCryptor,你会看到算法的使用:

// For aes-128:
//
// key = MD5(password + salt)
// IV = MD5(Key + password + salt)

//
// For aes-256:
//
// Hash0 = ''
// Hash1 = MD5(Hash0 + Password + Salt)
// Hash2 = MD5(Hash1 + Password + Salt)
// Hash3 = MD5(Hash2 + Password + Salt)
// Hash4 = MD5(Hash3 + Password + Salt)
//
// Key = Hash1 + Hash2
// IV = Hash3 + Hash4
//

// File Format:
//
// |Salted___|<salt>|<ciphertext>|
//

Using RNOpenSSLCryptor allows RNCryptor support for the OpenSSL format. I am currently in the midst of reworking this code on the async branch to support async operations, and that branch doesn't yet support OpenSSL, but I do plan to rework that shortly (by mid-July 2012).

使用RNOpenSSLCryptor允许RNCryptor支持OpenSSL格式。我目前正在修改异步分支上的代码,以支持异步操作,而该分支还不支持OpenSSL,但我确实计划在不久之后(到2012年7月中旬)进行修改。

If you want code that implements this for your own use, look at keyForPassword:salt: and IVForKey:password:salt:.

如果您想要实现此功能的代码,请查看keyForPassword:salt和IVForKey:password:salt:。

Note that the the OpenSSL file format has several security problems and I don't recommend it if you can avoid it. It does not use a very good KDF to generate its key, does not have as random an IV as it should, and provides no HMAC for authentication. These security problems are why I designed a different file format, much as I hated creating "yet another incompatible container."

注意,OpenSSL文件格式有几个安全问题,如果可以避免,我不建议这样做。它不使用一个非常好的KDF来生成它的密钥,不像它应该的那样具有任意的IV,并且不提供用于身份验证的HMAC。这些安全问题就是为什么我设计了不同的文件格式,就像我讨厌创建“另一个不兼容的容器”一样。