到目前为止,我已经花了两天时间来研究我所能利用的所有资源,所以这是最后的办法。
我有一个X509证书,它的公钥存储在iPhone的钥匙链中(目前仅限模拟器)。在ASP.NET方面,我已经在证书存储中获得了带有私钥的证书。当我在iPhone上加密一个字符串并在服务器上解密它时,我得到一个
CryptographicException
“坏数据。”我尝试了
Array.Reverse
建议在
RSACryptoServiceProvider
一页在一个长卷上,但没有帮助。
我比较了两边的base-64字符串,它们是相等的。我比较了解码后的原始字节数组,它们也是相等的。如果我使用公钥在服务器上加密,字节数组与iPhone的版本不同,并且很容易使用私钥进行解密。原始纯文本字符串是115个字符,因此它在2048位密钥的256字节限制范围内。
这是iPhone加密方法(相当多来自
CryptoExercise sample app
的
wrapSymmetricKey
方法:
+ (NSData *)encrypt:(NSString *)plainText usingKey:(SecKeyRef)key error:(NSError **)err
{
size_t cipherBufferSize = SecKeyGetBlockSize(key);
uint8_t *cipherBuffer = NULL;
cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
memset((void *)cipherBuffer, 0x0, cipherBufferSize);
NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];
OSStatus status = SecKeyEncrypt(key, kSecPaddingNone,
(const uint8_t *)[plainTextBytes bytes],
[plainTextBytes length], cipherBuffer,
&cipherBufferSize);
if (status == noErr)
{
NSData *encryptedBytes = [[[NSData alloc]
initWithBytes:(const void *)cipherBuffer
length:cipherBufferSize] autorelease];
if (cipherBuffer)
{
free(cipherBuffer);
}
NSLog(@"Encrypted text (%d bytes): %@",
[encryptedBytes length], [encryptedBytes description]);
return encryptedBytes;
}
else
{
*err = [NSError errorWithDomain:@"errorDomain" code:status userInfo:nil];
NSLog(@"encrypt:usingKey: Error: %d", status);
return nil;
}
}
下面是服务器端C解密方法:
private string Decrypt(string cipherText)
{
if (clientCert == null)
{
// Get certificate
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (var certificate in store.Certificates)
{
if (certificate.GetNameInfo(X509NameType.SimpleName, false) == CERT)
{
clientCert = certificate;
break;
}
}
}
using (var rsa = (RSACryptoServiceProvider)clientCert.PrivateKey)
{
try
{
var encryptedBytes = Convert.FromBase64String(cipherText);
var decryptedBytes = rsa.Decrypt(encryptedBytes, false);
var plaintext = Encoding.UTF8.GetString(decryptedBytes);
return plaintext;
}
catch (CryptographicException e)
{
throw(new ApplicationException("Unable to decrypt payload.", e));
}
}
}
我怀疑平台之间存在一些编码问题。
我知道一个是大尾数,另一个是小尾数,但我不知道该说哪一个或如何克服差异。
Mac OS X、Windows和iPhone都是小endian,所以这不是问题所在。
新理论:如果将OAEP填充布尔值设置为false,则默认为pkcs 1 1.5填充。
SecKey
只有
SecPadding
定义
PKCS1
,
PKCS1MD2
,
PKCS1MD5
和
PKCS1SHA1
. 也许是微软的PKC 11.5!=apple的pkcs1,因此填充会影响加密的二进制输出。我试着用
kSecPaddingPKCS1
与
fOAEP
设置为
false
但它仍然不起作用。
显然地,
ksecpaddingpkcs1
是
equivalent
到PKCSα1,1.5。回到理论的画板上…
其他新尝试的理论:
iPhone(.cer文件)上的证书与服务器(.pfx文件)上的pkcs 12捆绑包不完全相同,因此它无法工作。在不同的证书存储和服务器加密字符串中安装了.cer文件,回退得很好;
转换成base-64和向服务器发布的行为导致了同一类往返旅行中不存在的奇怪现象,所以我首先尝试了一些URLENCoding/decoding,然后从iPhone发布原始二进制文件,验证它是相等的,得到了相同的坏数据;
我的原始字符串是125个字节,所以我认为它可能是以UTF-8(长截图)截断的,所以我将其裁剪为44个字节的字符串,但没有结果;
回顾一下系统,密码库确保我使用了一个合适的类,并发现了“rsapkcs1keyExchangeDeformatter”,在新的前景中变得兴高采烈,当它的行为完全相同时,我感到沮丧。
成功!
事实证明,我在iPhone模拟器上的钥匙链上有点粗糙,可以这么说,它把水弄脏了。我删除了钥匙链数据库
~/Library/Application Support/iPhone Simulator/User/Library/Keychains/keychain-2-debug.db
使它被重新创造,并且工作得很好。谢谢你的帮助。据估计,这是一件简单但不明显的事情。(我学到了两件事:1)从模拟器中卸载应用程序并不能清除其钥匙链条目;2)定期全新启动。)
注意:keychain文件的常规路径取决于iOS版本:
~/library/application support/iphone simulator/[版本]/library/keychains/keychain-2-debug.db
例如。,
~/library/application support/iphone模拟器/4.3/library/keychains/keychain-2-debug.db