在使用RSA在iPhone上加密的C#中解密时遇到问题

bbr*_*own 8 c# iphone encryption rsa

到目前为止,我已经花了两天时间来处理这个问题,并且可以根据我的需要进行梳理,所以这是最后的选择.

我有一个X509证书,其公钥存储在iPhone的钥匙串中(此时仅为模拟器).在ASP.NET方面,我在证书库中获得了带有私钥的证书.当我在iPhone上加密字符串并在服务器上解密时,我收到CryptographicException"错误的数据".我尝试了Array.ReverseRSACryptoServiceProvider页面上建议的远景,但它没有帮助.

我比较了两侧的64弦,它们是相同的.我在解码后比较了原始字节数组,它们也相等.如果我使用公钥在服务器上加密,则字节数组与iPhone的版本不同,并且可以使用私钥轻松解密.原始明文字符串是115个字符,因此它在我的2048位密钥的256字节限制范围内.

这是iPhone加密方法(几乎是CryptoExercise示例应用程序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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是服务器端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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我怀疑平台之间存在一些编码问题.我知道一个是大端,另一个是小端,但我不知道哪个是哪个或如何克服差异.Mac OS X,Windows和iPhone都是小端的,所以这不是问题所在.

新理论:如果将OAEP填充布尔值设置为false,则默认为PKCS#1 1.5填充.SecKey只有SecPadding定义PKCS1,PKCS1MD2,PKCS1MD5,和PKCS1SHA1.也许微软的PKCS#1 1.5!= Apple的PKCS1,因此填充正在影响加密的二进制输出.我尝试使用kSecPaddingPKCS1fOAEP设置为false,它仍然没有工作.显然,kSecPaddingPKCS1等效于PKCS#1 1.5.回到理论上的绘图板......

其他新尝试的理论:

  1. iPhone上的证书(.cer文件)与服务器上的PKCS#12捆绑包(.pfx文件)不完全相同,因此它永远不会起作用.已安装的.cer文件在不同的证书存储区和服务器加密的字符串中进行了很好的处理;
  2. 转换到base-64和POST到服务器的行为导致奇怪,这在同一类往返中不存在所以我首先尝试了一些URLEncoding/Decoding,然后从iPhone发布了原始二进制文件,验证它是相同的,并得到相同的坏数据;
  3. 我的原始字符串是125个字节,所以我认为它可能在UTF-8(长镜头)中截断,所以我把它裁剪成44字节的字符串而没有结果;
  4. 回顾一下System.Cryptography库,以确保我使用了一个合适的类并发现了`RSAPKCS1KeyExchangeDeformatter`,对新的潜在客户感到高兴,并且当它表现完全相同时会感到沮丧.

成功!

事实证明,我在iPhone模拟器上的钥匙扣中有一些瑕疵,可以说是混淆了水域.我删除了Keychain DB,~/Library/Application Support/iPhone Simulator/User/Library/Keychains/keychain-2-debug.db使其重新创建,并且工作正常.谢谢你的帮助.数字本来是简单但不明显的.(我学到的两件事:1)从模拟器中卸载应用程序不会清除其Keychain条目,2)定期开始绝对新鲜.)

注意:keychain文件的通用路径取决于iOS版本:〜/ Library/Application Support/iPhone Simulator/[version] /Library/Keychains/keychain-2-debug.db eg~/Library/Application Support/iPhone模拟器/ 4.3 /库/钥匙串/ keychain-2-debug.db

Jon*_*ant 3

嗯...第一步(正如您所说的那样)是使用 iPhone 和 C# 实现使用相同的初始化向量来加密相同的消息。您应该得到相同的输出。你说你没有,所以有问题。

这意味着:

  • iPhone 的 RSA 实现不正确。
  • RSA 的 .NET 实现不正确。
  • 密钥文件不同(或解释不同)。

我建议前两种可能性不大,但可能性很小。

您声明:“在不同的证书存储中安装了 .cer 文件,并且服务器加密的字符串往返得很好”...这并不能证明任何事情:所有这些证明的是,给定一组特定的随机数字,您可以成功加密/解密一个平台。您不能保证两个平台都看到相同的随机数集。

所以我建议你把它降到尽可能低的水平。检查两个平台上加密的直接(字节数组)输入和输出。如果使用完全相同的(二进制)输入,您没有得到相同的输出,那么您就会遇到平台问题。我认为这不太可能,所以我猜你会发现 IV 的解释不同。