【问题标题】:Encrypt with iOS; Decrypt with .Net使用 iOS 加密;使用 .Net 解密
【发布时间】:2014-05-05 01:14:15
【问题描述】:

我需要在 iPhone 或 iPad 上加密一个字符串(实际上是一个 XML 文件),然后使用 .Net 应用程序对其进行解密。感谢 David Veksler 的问题 AES interoperability between .Net and iPhone? 和博客文章 http://automagical.rationalmind.net/2009/02/12/aes-interoperability-between-net-and-iphone/,我想我已经非常接近实现这一目标了。

但在 C# 方法返回的解密字符串 (XML) 中,前 16 个字符是乱码。从第17个字符开始,解密后的字符串与objective-c方法加密后的字符串匹配。

我尽可能地遵循 David 的代码,但经过反复试验后,我可能更改了一些内容。这是加密代码(密码和initVector现在只是硬编码在那里):

    CCCryptorStatus result = CCCryptorCreate(kCCEncrypt,
                                         kCCAlgorithmAES128,
                                         kCCOptionPKCS7Padding, // 0x0000 or kCCOptionPKCS7Padding
                                         (const void *)[@"1234567891123456" dataUsingEncoding:NSUTF8StringEncoding].bytes,
                                         [@"1234567891123456" dataUsingEncoding:NSUTF8StringEncoding].length,
                                         (const void *)[@"0000000000000000" dataUsingEncoding:NSUTF8StringEncoding].bytes,
                                         &thisEncipher
                                         );

    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t remainingBytes = 0;
    size_t movedBytes = 0;
    size_t plainTextBufferSize = 0;
    size_t totalBytesWritten = 0;
    uint8_t *ptr;

    NSData *plainText = [xmlFileText dataUsingEncoding:NSASCIIStringEncoding];

    plainTextBufferSize = [plainText length];
    bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
    bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    ptr = bufferPtr;
    remainingBytes = bufferPtrSize;

    result = CCCryptorUpdate(thisEncipher,
                         (const void *)[plainText bytes],
                         plainTextBufferSize,
                         ptr,
                         remainingBytes,
                         &movedBytes
                         );

    ptr += movedBytes;
    remainingBytes -= movedBytes;
    totalBytesWritten += movedBytes;

    result = CCCryptorFinal(thisEncipher,
                        ptr,
                        remainingBytes,
                        &movedBytes
                        );

    totalBytesWritten += movedBytes;

    if (thisEncipher)
    {
        (void) CCCryptorRelease(thisEncipher);
        thisEncipher = NULL;
    }

    if (result == kCCSuccess)
    {
        NSData *encryptedData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
        [[encryptedData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn] writeToFile:docFile atomically:NO encoding:NSUTF8StringEncoding error:nil];

        NSLog(@"%d:%d:%d:%@:%@", xmlFileText.length,
                                 encryptedData.length,
                                 [encryptedData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn].length,
                                 encryptedData,
                                 [encryptedData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]);

        if (bufferPtr)
            free(bufferPtr);
        return;
}

这里是解密代码:

    public static string DecryptString(string base64StringToDecrypt, string passphrase)
    {
        //Set up the encryption objects
        using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passphrase)))
        {   
            byte[] RawBytes = Convert.FromBase64String(base64StringToDecrypt);

            ICryptoTransform ictD = acsp.CreateDecryptor();

            //RawBytes now contains original byte array, still in Encrypted state

            //Decrypt into stream
            MemoryStream msD = new MemoryStream(RawBytes, 0, RawBytes.Length);
            CryptoStream csD = new CryptoStream(msD, ictD, CryptoStreamMode.Read);
            //csD now contains original byte array, fully decrypted

            //return the content of msD as a regular string
            return (new StreamReader(csD)).ReadToEnd();
        }
    }

从现场比较几个来看,似乎 NSData, encryptedData 包含与byte[], RawBytes 相同的值。但StreamReader.ReadToEnd() 之后返回的 XML 字符串与 NSStringxmlFileText 匹配,但前 16 个字符除外。我怀疑问题出在我加密获取NSData *encryptedData 的方式,或者我将其转换为Base64 编码字符串并将其写入文件的方式,或者我解密@987654330 的方式@ RawBytes,或者我将解密的 csD 转换回字符串的方式。如果有人能看出我哪里出错了,我将不胜感激。

更新:在大卫的 cmets 之后,我正在仔细研究 IV。我现在尝试使用 16 个零。

在 iOS 上,我正在使用:

(const void *)[@"0000000000000000" dataUsingEncoding:NSUTF8StringEncoding].bytes

在 .Net 上我正在使用:

new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

这些可能不相等。

【问题讨论】:

  • 我猜你没有在两端都使用 save IV,但这主要是一个猜测。
  • 谢谢,大卫。我当然在尝试使用相同的 IV(现在全为 0)。如果我不是,看来我不会只有 16 个字符才能成功。但我会仔细检查。
  • IV只影响第一块数据;这就是为什么我怀疑它。 :)
  • 好的,大卫,我认为你的方向是正确的。在 C# 方面,无论我使用什么 16 字节 IV,我都会胡言乱语。请参阅我的更新。我敢希望你知道如何使这些东西等效吗?
  • 感谢领导!我正在这个方向做更多的研究。

标签: c# ios .net objective-c encryption


【解决方案1】:

如果您的消息的第一部分是乱码,那么很可能您的 IV(初始化向量)在加密和解密结束时并不相同。 IV 会影响第一个数据块,因此使用错误的 IV 会导致您的第一个数据块错误但其余数据正确是有道理的。

在代码的一端,使用一串“0”字符作为 IV。在另一端,在 IV 处使用 0 值字节的字节数组。这些不一样; '0' 字符不一定是 0 字节值。您必须使 IV 相同。

【讨论】:

  • 谢谢!!我发现 16 个 0 的字符串的 UTF8 编码是 16 个十六进制 30。所以我将该字节数组更改为 16 48s 并取回我的整个加密字符串。我应该可以从这里拿走它。 :)
猜你喜欢
  • 1970-01-01
  • 2013-06-22
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多