【发布时间】: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 字符串与 NSString、xmlFileText 匹配,但前 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