使用iOS加密;用.Net解密

时间:2014-03-26 14:37:28

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

我需要在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方法加密的字符串。

我尽可能地密切关注大卫的代码,但经过一些试验和错误后可能会改变一些事情。这是加密代码(密码和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()NSStringxmlFileText匹配后返回的XML字符串除前16个字符外。我怀疑问题是我加密以获取NSData * encryptedData的方式,或者我将其转换为Base64编码字符串并将其写入文件的方式,或方式我正在解密byte[] RawBytes,或者我将解密的csD转换回字符串的方式。如果有人能看到我出错的地方,我将不胜感激。

更新:在David的评论之后,我仔细研究了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 }

这些可能不相同。

1 个答案:

答案 0 :(得分:2)

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

在代码的一端,一串" 0"字符用作IV。在另一端,在IV处使用0值字节的字节数组。这些不一样; a' 0' 0 char不一定是0字节值。你必须使IVs相同。