如何使用 RSACng 解密之前使用 RSACryptoServiceProvider 加密的数据

How to decrypt data using RSACng that is previously encrypted with RSACryptoServiceProvider

我正在从 RSACryptoServiceProvider 迁移到 RSACng 以获取新版本。但是,由于 CAPI 的 RSACryptoserviceProvider 使用 Little Endian Architecture 而 CNG API 的 RSACng 使用 Big Endian Architecture,问题是我如何使用以前的 CNG Api 解密数据使用 RSACryptoService 提供程序加密 (CAPI)?

我已经尝试 Array.reverse(cypherText) 并尝试使用 CNG Api 解密,但它抛出了错误,'The parameter is incorrect'。

  1. 我也尝试过解密一半密文的方法,因为 CNG API 使用 RSAEncryptionPadding.OaepSHA512 填充,而 CAPI 使用 OAEP 填充。

我的 RSACryptoServiceProvider class 如下:-

 public static void EncryptWithSystemKeyRSACryptoService(byte[] 
 plainBytes, bool representsUnicodeString, out string cypherText)
 {
                CspParameters cp = new CspParameters();
                cp.KeyContainerName = regValue.ToString();
                cp.Flags = CspProviderFlags.UseMachineKeyStore;
                cp.KeyNumber = (int)KeyNumber.Exchange;
                byte[] encBlockData=null;
                using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cp))
                {
                    res = CryptResult.GeneralError;
                    int keysize = rsaCSP.KeySize;


                     //This encrypts data and uses FOAEP padding
                    encBlockData = rsaCSP.Encrypt(plainBytes, true);
                }
                    //Should i have to reverse the Byte order?
                    // I am doing Array.reverse for encrypted data as it follows little endian architecture and CNG Api follows Big Endian architecture
                    Array.Reverse(encBlockData);
                    cypherText = BitConverter.ToString(encBlockData );
                    cypherText = cypherText.Replace("-", "");
                    cypherText = cypherText.ToLower();
 }

这就是我使用 RSACryptoservice Provider (CAPI) 加密数据的方式 我的 RSACng class 如下:-

           //I am calling this to use RSACng API to get private keys
           private static byte[] SetPrivateAndPublicKeysAndDecrypt(byte[] cyphertext)
           {
                cp.KeyContainerName = regValue.ToString();
                cp.Flags = CspProviderFlags.UseMachineKeyStore;
                cp.KeyNumber = (int)KeyNumber.Exchange;

             using (RSACryptoServiceProvider rsaCSP = new 
             RSACryptoServiceProvider(cp))
            {
                res = CryptResult.GeneralError;
                keysize = rsaCSP.KeySize;
                q = rsaCSP.ExportCspBlob(false);
                RSAp = rsaCSP.ExportParameters(true);

            }
          //created cngKey
            cngKey = CngKey.Import(q, CngKeyBlobFormat.GenericPublicBlob);
             //created RSACng instance
             RSACng rsacng = new RSACng(cngKey)
            {
              KeySize = keysize
            };
              rsacng.ImportParameters(RSAp);
             //Decrypt using RSACng API using OAEPSHA512 padding
               var plainText= crypto.Decrypt(cyphertext, RSAEncryptionPadding.OaepSHA512);
        return plainText;
            }

预期结果应该是->明文解密成功

实际结果-> 异常被捕获-> 'The parameter is incorrect'.

RSA 密文在 PKCS#1 (which specifies PKCS#1 v1.5 RSA encryption and OAEP encryption as implemented by most libraries). The function is called I2OSP within that standard 中被定义为使用静态大小、无符号、大端编码,并且密文的大小(以完整字节计)应与密钥大小相同。如果它不是big endian,那么它不符合RSA / OAEP,换句话说。

普通的 ASN.1 编码密钥也是如此:它们根据 DER(可分辨编码规则)使用动态大小、签名的大端编码。这些密钥在 PKCS#1、PKCS#8 和 X.509 标准中定义,尽管它们也可能嵌入到 PKCS#12 兼容密钥库中 - 例如。有时,密钥也会进行 PEM 编码,以使其与需要文本而不是二进制的协议兼容。

所以永远不必反转使用标准编码之一的密文或密钥。计算是在小端(或不是)内部执行的,这无关紧要。几乎所有现代密码或其他密码原语都是如此。输入/输出简单地以特定顺序的字节定义,而不是数字。只有非常低级别的功能可能会在例如上运行。单词,这混淆了问题(但你不会在 MS API 中找到它)。

只有 Microsoft 自己的专有(蹩脚的)密钥编码可以使用小端。


bartonjs当然是;您需要匹配填充方法,并且用于 OAEP(或者更确切地说,OAEP 中的掩码生成函数 MGF1)的默认哈希是 SHA-1。还有很多其他的陷阱需要避免,例如对明文/密文进行正确的编码/解码。