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

标签 c# iphone rsa encryption

到目前为止,我已经为此花了两天时间,并梳理了我可以使用的所有资源,所以这是最后的手段。

我有一个 X509 证书,其公钥存储在 iPhone 的钥匙串(keychain)中(此时仅模拟器)。在 ASP.NET 方面,我在证书存储中使用私钥获得了证书。当我在 iPhone 上加密一个字符串并在服务器上解密它时,我得到一个 CryptographicException “不良数据。”我试过 Array.Reverse建议在 RSACryptoServiceProvider 远景上的一页,但它没有帮助。

我比较了两边的base-64字符串,它们是相等的。我在解码后比较了原始字节数组,它们也是相等的。如果我在服务器上使用公钥加密,字节数组与 iPhone 的版本不同,并且很容易使用私钥解密。原始明文字符串为 115 个字符,因此它在我的 2048 位 key 的 256 字节限制之内。

这是 iPhone 的加密方法(几乎是从 CryptoExercise sample appwrapSymmetricKey 方法逐字记录):

+ (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 都是 little-endian,所以这不是问题。

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

其他新尝试的理论:
  • iPhone 上的证书(.cer 文件)与服务器上的 PKCS#12 包(.pfx 文件)并不完全相同,因此它永远无法工作。在不同的证书存储中安装了 .cer 文件,并且服务器加密的字符串往返就好了;
  • 转换为 base-64 和 POST 到服务器的行为导致了同一个类往返中不存在的奇怪,所以我首先尝试了一些 URLEncoding/Decoding,然后从 iPhone 发布原始二进制文件,验证它是相等的,并得到相同的坏数据;
  • 我的原始字符串是 125 字节,所以我认为它可能会在 UTF-8(长镜头)中被截断,所以我将其裁剪为 44 字节字符串,但没有结果;
  • 回顾 System.Cryptography 库以确保我使用了适当的类并发现了`RSAPKCS1KeyExchangeDeformatter`,对新的前景感到高兴,当它的行为完全相同时感到沮丧。

  • 成功!

    事实证明,我在 iPhone 模拟器上的钥匙串(keychain)中有一些东西弄脏了水,可以这么说。我在 ~/Library/Application Support/iPhone Simulator/User/Library/Keychains/keychain-2-debug.db 删除了钥匙串(keychain)数据库。使其重新创建并且工作正常。感谢您的所有帮助。数字这将是一些简单但不明显的事情。 (我学到了两件事:1)从模拟器中卸载应用程序不会清除其钥匙串(keychain)条目,2)定期重新启动。)

    注意:钥匙串(keychain)文件的通用路径取决于 iOS 版本:
    ~/Library/Application Support/iPhone Simulator/[version]/Library/Keychains/keychain-2-debug.db
    例如。,
    ~/Library/Application Support/iPhone Simulator/4.3/Library/Keychains/keychain-2-debug.db

    最佳答案

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

    这意味着:

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

  • 我建议前两个不太可能,但是它们是远程可能的。

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

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

    关于c# - 在 C# 中解密使用 RSA 在 iPhone 上加密的内容时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1133724/

    相关文章:

    c# - 禁用/修复 .Designer.cs 文件中的代码分析警告

    python - 如何使用 Python 从 Windows 7 中迭代连接的 iPhone 上的照片?

    iphone - 使用vDSP的iPhone4s,iPhone 5每秒最大FFT

    c# - 设计和实现社会关系问题

    c# - 控制我的应用程序的 Windows 7 任务栏分组

    C#:Blowfish 加密单个双字

    iphone - 如何获取 iPod/iPhone 的 UDID?

    c# - RSA 导入手动 RSParams 因错误数据错误而失败

    java.security.spec.InvalidKeySpecException : java. security.InvalidKeyException: key 格式无效

    java - 如何在二次筛技术的筛分步骤中使用对数