.Net和iPhone之间的AES互操作性?

时间:2009-02-11 19:40:34

标签: .net iphone encryption aes

我需要加密iPhone上的字符串并将其发送到.Net Web服务进行解密。我能够在iPhone和.Net上加密/解密,但是来自iPhone的加密字符串不能被.Net解密。我得到的错误是“填充无效,无法删除。”

.Net代码来自: http://blog.realcoderscoding.com/index.php/2008/07/dot-net-encryption-simple-aes-wrapper/

iPhone代码使用以下示例代码:http://nootech.wordpress.com/2009/01/17/symmetric-encryption-with-the-iphone-sdk/

AFAIK我的关键设置是相同的:

result.BlockSize = 128; // iPhone: kCCBlockSizeAES128
result.KeySize = 128; // kCCBlockSizeAES128
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.PKCS7; // kCCOptionPKCS7Padding

我尝试了不同的生成密文的方法。你好/你好是:

e0PnmbTg / 3cT3W + 92CDw1Q == in .Net

iPhone上的

yrKe5Z7p7MNqx9 + CbBvNqQ ==

和“openssl enc -aes-128-cbc -nosalt -a -in hello.txt -pass pass:hello”生成:QA + Ul + r6Zmr7yHipMcHSbQ ==

更新:I've posted the working code for this here

3 个答案:

答案 0 :(得分:16)

至少,您使用的是不同的初始化向量(IV)。

  • .Net代码使用IV的密钥。

    private static AesCryptoServiceProvider GetProvider(byte[] key)
    {
        //Set up the encryption objects
        AesCryptoServiceProvider result = new AesCryptoServiceProvider();
        byte[] RealKey = Encryptor.GetKey(key, result);
        result.Key = RealKey;
        result.IV = RealKey;
        return result;
    }

    private static byte[] GetKey(byte[] suggestedKey, AesCryptoServiceProvider p)
    {
        byte[] kRaw = suggestedKey;
        List kList = new List();
        for (int i = 0; i < p.LegalKeySizes[0].MinSize; i += 8 )
        {
            kList.Add(kRaw[i % kRaw.Length]);
        }
        byte[] k = kList.ToArray();
        return k;
    }

    应该是:kList.Add(kRaw[(i / 8) % kRaw.Length]);。否则,长度为%8 == 0的密钥将重复使用相同的字母,doh!

    因此.Net使用的IV(和密钥)是:hleolhleolhleolh。这不是API的一部分,而是由于您指向的包装代码(其中存在严重错误......)。

  • iPhone代码使用0代表IV。

    // Initialization vector; dummy in this case 0's.
    uint8_t iv[kChosenCipherBlockSize];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));
  • 默认情况下,openssl会预先添加一个随机生成的盐(这就是输出更长的原因!)。

openssl输出更安全,因为它预先添加了一个随机初始化向量。看起来base64解码字符串的前几个字节是“Salted__”。您也可以要求openssl不使用盐(-naltalt)和/或提供IV(-iv)。

基本上,openssl,.Net和iPhone使用相同的加密,您只需要小心如何使用加密密钥和初始化向量初始化API。

答案 1 :(得分:2)

您确定在测试中使用相同的AES密钥吗?你帖子中的OpenSSL示例使用的密码是OpenSSL从中获取密钥和IV(也可能使用盐。

生成一个随机的128位密钥,并以十六进制格式将此密钥指定给OpenSSL:

openssl enc -aes-128-cbc -a -in hello.txt -K KEY_IN_HEX -iv 0

您不应该在任何安全系统中使用IV = 0,但为了测试互操作性,这是可以的。

答案 2 :(得分:2)

在c#

void test(){
   string ctB64 = encrypt("hola");
   Console.WriteLine(ctB64);  // the same as in objective-c
}

string encrypt(string input)
        {
            try
            {
                // Create a new instance of the AesManaged class.  This generates a new key and initialization vector (IV).
                AesManaged myAes = new AesManaged();

                // Override the cipher mode, key and IV
                myAes.Mode = CipherMode.CBC;
                myAes.IV = new byte[16] { 0x10, 0x16, 0x1F, 0xAD, 0x10, 0x10, 0xAA, 0x22, 0x12, 0x51, 0xF1, 0x1E, 0x15, 0x11, 0x1B, 0x10 }; // must be the same as in objective-c
                myAes.Key = Encoding.UTF8.GetBytes(“0123456789123456”);
                //CipherKey;  // Byte array representing the key
                myAes.Padding = PaddingMode.PKCS7;

                // Create a encryption object to perform the stream transform.
                ICryptoTransform encryptor = myAes.CreateEncryptor();

                // perform the encryption as required...
                MemoryStream ms = new MemoryStream();
                CryptoStream ct = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
                byte[] binput = Encoding.UTF8.GetBytes(input);
                ct.Write(binput, 0, binput.Length);
                ct.Close();
                byte [] result = ms.ToArray();
                return Convert.ToBase64String(result);
            }
            catch (Exception ex)
            {
                // TODO: Log the error 
                Console.WriteLine(ex);
                throw ex;
            }

        }

·在objective-c中, 从https://github.com/kelp404/CocoaSecurity

添加CocoaSecurity库
#import "CocoaSecurity.h"
#import "Base64.h"

…

- (void) test{
 unsigned char bytes[] = { 0x10, 0x16, 0x1F, 0xAD, 0x10, 0x10, 0xAA, 0x22, 0x12, 0x51, 0xF1, 0x1E, 0x15, 0x11, 0x1B, 0x10 }; // must be the same as in c#

    NSData *iv = [NSData dataWithBytesNoCopy:bytes length:16 freeWhenDone:YES];
    NSData* key =   [@"0123456789123456" dataUsingEncoding:NSUTF8StringEncoding];

    CocoaSecurityResult *result = [CocoaSecurity aesEncrypt:@"hola" key:key iv:iv];
   NSLog(@"%@", result.base64); // the same as in c#


    NSData *data = [NSData dataWithBase64EncodedString:result.base64];
    CocoaSecurityResult *result2 = [CocoaSecurity aesDecryptWithData:data key:key iv:iv];

    NSLog(@"%@", result2.utf8String); // show "hola"

}