iOS& .NET生成不同的AES256结果

时间:2015-01-13 21:04:40

标签: c# ios .net encryption aes

我已经在这几天了。我最初(也是最终)的目标是在iOS上使用CommonCrypto来加密具有给定IV和密钥的密码,然后使用.NET成功解密它。经过大量的研究和失败,我已经缩小了我的目标,即在iOS和.NET上简单地生成相同的加密字节,然后从那里开始。

我在.NET(C#,framework 4.5)和iOS(8.1)中创建了简单的测试项目。请注意,以下代码并非旨在保证安全,而是在较大的流程中将变量放大。此外, iOS是此处的变量。最终的.NET加密代码将由客户端部署,因此我可以将iOS加密排除在外。除非确认不可能,否则.NET代码不会被更改。

相关的.NET加密代码:

    static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
    {
        byte[] encrypted;
        // Create an Aes object 
        // with the specified key and IV. 
        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.KeySize = 256;
            aesAlg.BlockSize = 128;

            // Create an encryptor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(Key, IV);

            // Create the streams used for encryption. 
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        return encrypted;
    }

相关的iOS加密代码:

+(NSData*)AES256EncryptData:(NSData *)data withKey:(NSData*)key iv:(NSData*)ivector
{
Byte keyPtr[kCCKeySizeAES256+1]; // Pointer with room for terminator (unused)
// Pad to the required size
bzero(keyPtr, sizeof(keyPtr));

// fetch key data
[key getBytes:keyPtr length:sizeof(keyPtr)];

// -- IV LOGIC
Byte ivPtr[16];
bzero(ivPtr, sizeof(ivPtr));
[ivector getBytes:ivPtr length:sizeof(ivPtr)];

// Data length
NSUInteger dataLength = data.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,
                                      keyPtr, kCCKeySizeAES256,
                                      ivPtr,
                                      data.bytes, dataLength,
                                      buffer, bufferSize,
                                      &numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}

free(buffer);
return nil;
}

在.NET中传递pass,key和IV以及打印结果的相关代码:

byte[] c_IV = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
byte[] c_Key = { 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
String passPhrase = "X";

// Encrypt
byte[] encrypted = EncryptStringToBytes_Aes(passPhrase, c_Key, c_IV);
// Print result
for (int i = 0; i < encrypted.Count(); i++)
{
    Console.WriteLine("[{0}] {1}", i, encrypted[i]);
}

传递参数并在iOS中打印结果的相关代码:

Byte c_iv[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
Byte c_key[16] = { 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
NSString* passPhrase = @"X";
// Convert to data
NSData* ivData = [NSData dataWithBytes:c_iv length:sizeof(c_iv)];
NSData* keyData = [NSData dataWithBytes:c_key length:sizeof(c_key)];
// Convert string to encrypt to data
NSData* passData = [passPhrase dataUsingEncoding:NSUTF8StringEncoding];
NSData* encryptedData = [CryptoHelper AES256EncryptData:passData withKey:keyData iv:ivData];

long size = sizeof(Byte);
for (int i = 0; i < encryptedData.length / size; i++) {
    Byte val;
    NSRange range = NSMakeRange(i * size, size);
    [encryptedData getBytes:&val range:range];
    NSLog(@"[%i] %hhu", i, val);
}

运行.NET代码后,它会在加密后输出以下字节:

  

[0] 194
  [1] 154
  [2] 141
  [3] 238
  [4] 77
  [5] 109
  [6] 33
  [7] 94
  [8] 158
  [9] 5
  [10] 7
  [11] 187
  [12] 193
  [13] 165
  [14] 70
  [15] 5

相反,iOS会在加密后打印以下内容:

  

[0] 77
  [1] 213
  [2] 61
  [3] 190
  [4] 197
  [5] 191
  [6] 55
  [7] 230
  [8] 150
  [9] 144
  [10] 5
  [11] 253
  [12] 253
  [13] 158
  [14] 34
  [15] 138

我不能为我的生活决定造成这种差异的原因。我已经证实了一些事情:

  1. iOS和.NET都可以成功解密其加密数据。

  2. .NET项目中的代码行:

    aesAlg.Padding = PaddingMode.PKCS7;
    aesAlg.KeySize = 256;
    aesAlg.BlockSize = 128;

  3. 不要影响结果。它们可以被注释,输出也是一样的。我认为这意味着它们是默认值。我只是让他们明白我在这个例子中尽可能地匹配iOS的加密属性。

    1. 如果我打印出iOS NSData对象“ivData”和“keyData”中的字节,它会生成我用它们创建的相同字节列表 - 所以我不认为这是C&lt; - &GT; ObjC初始参数的桥接问题。

    2. 如果我打印出iOS变量“passData”中的字节,它会打印与.NET相同的单字节(88)。所以我很确定他们正在使用完全相同的数据开始加密。

    3. 由于.NET代码的简洁性,我已经没有明显的实验途径了。我唯一的想法是,有人可能能够在我的“AES256EncryptData:withKey:iv:”方法中指出问题。该代码已经从无处不在的iOS AES256代码中进行了修改,因为我们提供的密钥是字节数组 - 而不是字符串。我在ObjC学习的时间很多,但对C语言没那么熟悉 - 所以我当然可能已经弄错了所需的修改。

      非常感谢所有帮助或建议。

2 个答案:

答案 0 :(得分:3)

我注意到你使用的是AES256但是有128位密钥! 16字节x 8位。你不能指望各种功能来填充相同的键,这是未定义的。

答案 1 :(得分:0)

您可能正在处理字符串编码问题。在你的iOS代码中,我看到你将字符串作为UTF-8传递,这将产生一个单字节的字符串&#34; X&#34;。 .NET默认使用UTF-16,这意味着你有一个两字节的字符串&#34; X&#34;。

您可以使用How to convert a string to UTF8?将字符串转换为.NET中的UTF-8字节数组。您可以尝试在两种情况下写出纯文本字符串的字节数组,以确定您实际上是在传递相同的字节。