【问题标题】:Public key encryption with RSACryptoServiceProvider使用 RSACryptoServiceProvider 进行公钥加密
【发布时间】:2013-03-20 02:57:50
【问题描述】:

一段时间以来,我在 CodeProject 上看过一篇文章,其中解释了如何使用 RSA 提供程序进行加密和解密:

RSA Private Key Encryption

虽然 2009 年的旧版本有问题,但 2012 年的新版本(支持 System.Numerics.BigInteger)似乎更可靠。不过,这个版本缺少的是一种使用 public 密钥加密 和使用 private 密钥解密 的方法。

所以,我自己尝试过,但解密时会出现垃圾。我不熟悉 RSA 提供商,所以我在这里一无所知。很难找到更多关于这应该如何工作的信息。

有人知道这有什么问题吗? 以下是使用公钥加密:

// Add 4 byte padding to the data, and convert to BigInteger struct
BigInteger numData = GetBig( AddPadding( data ) );
RSAParameters rsaParams = rsa.ExportParameters( false );
//BigInteger D = GetBig( rsaParams.D ); //only for private key
BigInteger Exponent = GetBig( rsaParams.Exponent );
BigInteger Modulus = GetBig( rsaParams.Modulus );
BigInteger encData = BigInteger.ModPow( numData, Exponent, Modulus );    
return encData.ToByteArray();

执行此操作时是否使用提供商提供的大“D”?可能不是,因为它是没有“D”的公钥。

然后是对应的(使用 PRIVATE 密钥解密):

BigInteger numEncData = new BigInteger( cipherData );

RSAParameters rsaParams = rsa.ExportParameters( true );
BigInteger D = GetBig( rsaParams.D );
//BigInteger Exponent = GetBig( rsaParams.Exponent );
BigInteger Modulus = GetBig( rsaParams.Modulus );

BigInteger decData = BigInteger.ModPow( numEncData, D, Modulus );

byte[] data = decData.ToByteArray();
byte[] result = new byte[ data.Length - 1 ];
Array.Copy( data, result, result.Length );
result = RemovePadding( result );

Array.Reverse( result );
return result;

这里需要“D”还是指数?

显然,我需要加密货币在私人-公共-公共-私人两种方式下工作。 非常感谢任何帮助!

【问题讨论】:

    标签: c# .net cryptography rsa encryption-asymmetric


    【解决方案1】:

    这里有一个例子:

        public static void rsaPlayground()
        {
            byte[] data = new byte[] { 1, 2, 3, 4, 5 };
            RSACryptoServiceProvider csp = new RSACryptoServiceProvider();//make a new csp with a new keypair
            var pub_key = csp.ExportParameters(false); // export public key
            var priv_key = csp.ExportParameters(true); // export private key
    
            var encData = csp.Encrypt(data, false); // encrypt with PKCS#1_V1.5 Padding
            var decBytes = MyRSAImpl.plainDecryptPriv(encData, priv_key); //decrypt with own BigInteger based implementation
            var decData = decBytes.SkipWhile(x => x != 0).Skip(1).ToArray();//strip PKCS#1_V1.5 padding
    
        }
    
        public class MyRSAImpl 
        {
    
            private static byte[] rsaOperation(byte[] data, BigInteger exp, BigInteger mod)
            {
                BigInteger bData = new BigInteger(
                    data    //our data block
                    .Reverse()  //BigInteger has another byte order
                    .Concat(new byte[] { 0 }) // append 0 so we are allways handling positive numbers
                    .ToArray() // constructor wants an array
                );
                return 
                    BigInteger.ModPow(bData, exp, mod) // the RSA operation itself
                    .ToByteArray() //make bytes from BigInteger
                    .Reverse() // back to "normal" byte order
                    .ToArray(); // return as byte array
    
                /*
                 * 
                 * A few words on Padding:
                 * 
                 * you will want to strip padding after decryption or apply before encryption 
                 * 
                 */
            }
    
            public static byte[] plainEncryptPriv(byte[] data, RSAParameters key) 
            {
                MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
                return rsaOperation(data, myKey.privExponent, myKey.Modulus);
            }
            public static byte[] plainEncryptPub(byte[] data, RSAParameters key)
            {
                MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
                return rsaOperation(data, myKey.pubExponent, myKey.Modulus);
            }
            public static byte[] plainDecryptPriv(byte[] data, RSAParameters key)
            {
                MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
                return rsaOperation(data, myKey.privExponent, myKey.Modulus);
            }
            public static byte[] plainDecryptPub(byte[] data, RSAParameters key)
            {
                MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
                return rsaOperation(data, myKey.pubExponent, myKey.Modulus);
            }
    
        }
    
        public class MyRSAParams
        {
            public static MyRSAParams fromRSAParameters(RSAParameters key)
            {
                var ret = new MyRSAParams();
                ret.Modulus = new BigInteger(key.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
                ret.privExponent = new BigInteger(key.D.Reverse().Concat(new byte[] { 0 }).ToArray());
                ret.pubExponent = new BigInteger(key.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
    
                return ret;
            }
            public BigInteger Modulus;
            public BigInteger privExponent;
            public BigInteger pubExponent;
        }
    

    【讨论】:

    • 在公钥中找不到“D”元素。它仅在使用私钥进行解密时设置,因此除非私钥与应用程序一起分发,否则您的示例将失败。
    • 嗯...这可能是一个事实,当您没有私钥时,您无法使用私钥解密...是的...这与a有什么关系仅显示如何在 RSA 背后进行数学运算的计算示例?
    • 不正确,您只能在解密过程中使用公钥解密使用私钥加密的数据。您上面的示例需要私钥,无论是使用公钥还是私钥进行解密。请看看你的样品,你会明白的。总而言之,您需要公开和私有才能使您的任何解密方法起作用,这是错误的。
    • 特别是 MyRSAParams.fromRSAParameters 查找私有和公共指数。 -- D 值。
    • 叹息......所以......你的意思是构造函数不尊重公钥? ...编写自己的...这是一个示例,展示了如何进行数学运算以及如何阅读关键组件...没有免费的复制和粘贴生产代码与保修...随时发布您自己的答案...
    【解决方案2】:

    以这个编码/解码为例

            byte[] toEncryptData = Encoding.ASCII.GetBytes("hello world");
    
            //Generate keys
            RSACryptoServiceProvider rsaGenKeys = new RSACryptoServiceProvider();
            string privateXml = rsaGenKeys.ToXmlString(true);
            string publicXml = rsaGenKeys.ToXmlString(false);
    
            //Encode with public key
            RSACryptoServiceProvider rsaPublic = new RSACryptoServiceProvider();
            rsaPublic.FromXmlString(publicXml);
            byte[] encryptedRSA = rsaPublic.Encrypt(toEncryptData, false);
            string EncryptedResult = Encoding.Default.GetString(encryptedRSA);
    
    
            //Decode with private key
            var rsaPrivate = new RSACryptoServiceProvider();
            rsaPrivate.FromXmlString(privateXml);
            byte[] decryptedRSA = rsaPrivate.Decrypt(encryptedRSA, false);
            string originalResult = Encoding.Default.GetString(decryptedRSA);
    

    【讨论】:

    • 最初的问题是询问两个方向的示例。您的代码显示了如何仅使用私钥进行解密,而不是如何使用公钥进行解密。
    • 在 RSA 的情况下,不需要用公钥解密。除了你的意思是 rsa 签名。
    • 不,我的意思是使用公钥解密。例如,在 php 中,使用 openssl_private_encrypt() - 将私钥 PRIVATE 保持在服务器上应有的状态。现在在“客户端”中,这需要使用公钥解密(示例客户端是用 c# 编写并使用 AuthentiCode“签名”的程序)。方便地将公共证书嵌入到程序中(签名过程的一部分)。现在,以另一种方式想象——史诗般的失败。并滚动一个你需要解析的哈希来“验证”数据——很容易被黑。
    • 我会声明这一点,这不是你的错,世界其他地方都疯了,并且认为将私钥分发给客户端应用程序是明智的选择——甚至更好,使用自签名客户端的私钥,并在服务器上存储大量的公钥——这些很容易被模仿,对于任何真正安全的东西(例如许可软件)来说都是 100% 的废话。
    • 也许我的回答太仓促了。我认为 RSACryptoServiceProvider 有故意的限制,以避免私人加密/公共解密可能出现的错误。对于签名,我们可以使用 SignData/VerifyData。
    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 2011-08-16
    • 2012-04-11
    • 2019-08-06
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多