From 1e4ae877ab43c58f0ead8276d46146205432e312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E5=9D=9A=E6=9E=9C?= <753610399@qq.com> Date: Tue, 12 Sep 2023 16:19:48 +0800 Subject: [PATCH] =?UTF-8?q?Release=20Update=20v1.6,=20=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E5=8F=91=E5=B8=83=EF=BC=8C=E8=B0=83=E6=95=B4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Program.cs | 50 +++++++++++++++++++---------- README-English.md | 10 +++--- README.md | 10 +++--- RSA_Util.cs | 82 ++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 115 insertions(+), 37 deletions(-) diff --git a/Program.cs b/Program.cs index 92fa6f0..13bd32e 100644 --- a/Program.cs +++ b/Program.cs @@ -114,13 +114,18 @@ static void RSATest(bool fast) { //对调交换公钥私钥 ST("【Unsafe|对调公钥私钥,私钥加密公钥解密】", "[ Unsafe | Swap the public key and private key, private key encryption and public key decryption ]"); - rsa4 = rsa.SwapKey_Exponent_D__Unsafe(); + var rsaPri = rsa.SwapKey_Exponent_D__Unsafe(); + var rsaPub = new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe(); + if (!RSA_Util.IsUseBouncyCastle) { + rsaPub = rsaPri; + ST(".NET自带的RSA不支持仅含公钥的密钥进行解密和签名,使用NoPadding填充方式或IsUseBouncyCastle时无此问题", "The RSA that comes with .NET does not support decryption and signing with keys containing only public keys. This problem does not occur when using NoPadding or IsUseBouncyCastle."); + } try { - var en4 = rsa4.Encrypt("PKCS1", str); - var sign4 = rsa4.Sign("SHA1", str); - de = rsa4.Decrypt("PKCS1", en4); + var enPri = rsaPri.Encrypt("PKCS1", str); + var signPub = rsaPub.Sign("SHA1", str); + de = rsaPub.Decrypt("PKCS1", enPri); AssertMsg(de, de == str); - AssertMsg(T("校验 OK", "Verify OK"), rsa4.Verify("SHA1", sign4, str)); + AssertMsg(T("校验 OK", "Verify OK"), rsaPri.Verify("SHA1", signPub, str)); } catch (Exception e) { if (!RSA_Util.IS_CoreOr46 && !RSA_Util.IsUseBouncyCastle) { S(T("不支持在RSACryptoServiceProvider中使用:", "Not supported in RSACryptoServiceProvider: ") + e.Message); @@ -129,7 +134,7 @@ static void RSATest(bool fast) { } } - rsa4 = rsa4.SwapKey_Exponent_D__Unsafe(); + rsa4 = rsaPri.SwapKey_Exponent_D__Unsafe(); de = rsa4.Decrypt("PKCS1", en); AssertMsg(de, de == str); AssertMsg(T("校验 OK", "Verify OK"), rsa4.Verify("SHA1", sign, str)); @@ -141,7 +146,7 @@ static void RSATest(bool fast) { ST("【测试一遍所有的加密、解密填充方式】 按回车键继续测试...", "[ Test all the encryption and decryption padding mode ] Press Enter to continue testing..."); ReadIn(); RSA_Util rsa5 = new RSA_Util(2048); - testPaddings(false, rsa5, true); + testPaddings(false, rsa5, new RSA_Util(rsa5.ToPEM(true)), true); } } static Type Type_RuntimeInformation(Type[] outOSPlatform) { @@ -404,10 +409,20 @@ static void testProvider(bool checkOpenSSL) { S(HR); ST("测试一遍所有的加密、解密填充方式:", "Test all the encryption and decryption padding mode:"); - testPaddings(checkOpenSSL, rsa, true); + testPaddings(checkOpenSSL, rsa, new RSA_Util(rsa.ToPEM(true)), true); + + S(HR); + ST("Unsafe|是否要对调公钥私钥(私钥加密公钥解密)重新测试一遍?(Y/N) N", "Unsafe | Do you want to swap the public and private keys (private key encryption and public key decryption) and test again? (Y/N) N"); + Console.Write("> "); + string yn = ReadIn().Trim().ToUpper(); + if (yn == "Y") { + var rsaPri = rsa.SwapKey_Exponent_D__Unsafe(); + var rsaPub = new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe(); + testPaddings(checkOpenSSL, rsaPub, rsaPri, true); + } } /// 测试一遍所有的加密、解密填充方式 - static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) { + static int testPaddings(bool checkOpenSSL, RSA_Util rsaPri, RSA_Util rsaPub, bool log) { int errCount = 0; var errMsgs = new List(); var txt = "1234567890"; @@ -419,7 +434,7 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) { if (checkOpenSSL) { try { - runOpenSSL(rsa, txtData); + runOpenSSL(rsaPri.HasPrivate ? rsaPri : rsaPub, txtData); } catch (Exception e) { S(T("运行OpenSSL失败:", "Failed to run OpenSSL: ") + e.Message); return errCount; @@ -431,8 +446,8 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) { var errMsg = ""; try { { - byte[] enc = rsa.Encrypt(type, txtData); - byte[] dec = rsa.Decrypt(type, enc); + byte[] enc = rsaPub.Encrypt(type, txtData); + byte[] dec = rsaPri.Decrypt(type, enc); bool isOk = true; if (dec.Length != txtData.Length) { isOk = false; @@ -456,7 +471,7 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) { errMsg = "+OpenSSL: " + T("OpenSSL加密出错", "OpenSSL encryption error"); throw e; } - byte[] dec = rsa.Decrypt(type, enc); + byte[] dec = rsaPri.Decrypt(type, enc); bool isOk = true; if (dec.Length != txtData.Length) { isOk = false; @@ -493,8 +508,8 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) { var errMsg = ""; try { { - byte[] sign = rsa.Sign(type, txtData); - var isOk = rsa.Verify(type, sign, txtData); + byte[] sign = rsaPri.Sign(type, txtData); + var isOk = rsaPub.Verify(type, sign, txtData); if (!isOk) { errMsg = T("未通过校验", "Failed verification"); throw new Exception(errMsg); @@ -508,7 +523,7 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) { errMsg = "+OpenSSL: " + T("OpenSSL签名出错", "OpenSSL signature error"); throw e; } - var isOk = rsa.Verify(type, sign, txtData); + var isOk = rsaPub.Verify(type, sign, txtData); if (!isOk) { errMsg = "+OpenSSL: " + T("未通过校验", "Failed verification"); throw new Exception(errMsg); @@ -550,12 +565,13 @@ static void threadRun() { int Count = 0; int ErrCount = 0; RSA_Util rsa = new RSA_Util(2048); + RSA_Util rsaPub = new RSA_Util(rsa.ToPEM(true)); S(T("正在测试中,线程数:", "Under test, number of threads: ") + ThreadCount + T(",按回车键结束测试...", ", press enter to end the test...")); for (int i = 0; i < ThreadCount; i++) { new Thread(() => { while (!Abort) { - int err = testPaddings(false, rsa, false); + int err = testPaddings(false, rsa, rsaPub, false); if (err > 0) { Interlocked.Add(ref ErrCount, err); } diff --git a/README-English.md b/README-English.md index 639c757..3358702 100644 --- a/README-English.md +++ b/README-English.md @@ -75,8 +75,10 @@ var isVerify=rsa.Verify("PKCS1+SHA1", sign, "test123"); var pemTxt=rsa.ToPEM().ToPEM_PKCS8(); //Unconventional (unsafe, not recommended): private key encryption, public key decryption, public key signature, private key verification -RSA_Util rsa2=rsa.SwapKey_Exponent_D__Unsafe(); -//... rsa2.Encrypt rsa2.Decrypt rsa2.Sign rsa2.Verify +RSA_Util rsaS_Private=rsa.SwapKey_Exponent_D__Unsafe(); +RSA_Util rsaS_Public=new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe(); +//... rsaS_Private.Encrypt rsaS_Public.Decrypt +//... rsaS_Public.Sign rsaS_Private.Verify Console.WriteLine(pemTxt+"\n"+enTxt+"\n"+deTxt+"\n"+sign+"\n"+isVerify); Console.ReadLine(); @@ -121,7 +123,7 @@ Welcome to join QQ group: 421882406, pure lowercase password: `xiangyuecn` Padding|Algorithm|Frame|Core|BC :-|:-|:-:|:-:|:-: -NO|RSA/ECB/NoPadding|×|×|√ +NO|RSA/ECB/NoPadding|√|√|√ PKCS1 |RSA/ECB/PKCS1Padding|√|√|√ OAEP+SHA1 |RSA/ECB/OAEPwithSHA-1andMGF1Padding|√|√|√ OAEP+SHA256|RSA/ECB/OAEPwithSHA-256andMGF1Padding|4.6+|√|√ @@ -291,7 +293,7 @@ The `RSA_Util.cs` file depends on `RSA_PEM.cs`, which encapsulates encryption, d `RSA_PEM` **ToPEM(bool convertToPublic = false)**: Export RSA_PEM object (then you can export PEM text by RSA_PEM.ToPEM method), if convertToPublic RSA containing private key will only return public key, RSA containing only public key will not be affected. -`RSA_Util` **SwapKey_Exponent_D__Unsafe()**: [Unsafe and not recommended] Swap the public key exponent (Key_Exponent) and the private key exponent (Key_D): use the public key as the private key (new.Key_D=this.Key_Exponent) and the private key as the public key (new. Key_Exponent=this.Key_D), returns a new RSA object; for example, used for: private key encryption, public key decryption, this is an unconventional usage. The current object must contain a private key, otherwise an exception will be thrown if it cannot be swapped. Note: It is very insecure to use the public key as a private key, because the public key exponent of most generated keys is 0x10001 (AQAB), which is too easy to guess and cannot be used as a real private key. The swapped key does not support use in RSACryptoServiceProvider (.NET Framework 4.5 and below): `!IS_CoreOr46 && !IsUseBouncyCastle`. +`RSA_Util` **SwapKey_Exponent_D__Unsafe()**: [Unsafe and not recommended] Swap the public key exponent (Key_Exponent) and the private key exponent (Key_D): use the public key as the private key (new.Key_D=this.Key_Exponent) and the private key as the public key (new.Key_Exponent=this.Key_D), returns a new RSA object; for example, used for: private key encryption, public key decryption, this is an unconventional usage. If the current key only contains the public key, the swap will not occur, and the returned new RSA will allow decryption and signing operations with the public key; However, the RSA that comes with .NET does not support decryption and signing with keys containing only the public key, and the exponent must be swapped (If it is .NET Framework 4.5 and below, public and private keys are not supported), there is no such problem when using NoPadding or IsUseBouncyCastle. Note: It is very unsafe to use a public key as a private key, because the public key exponent of most generated keys is 0x10001 (AQAB), which is too easy to guess and cannot be used as a true private key. In some private key encryption implementations, such as Java's own RSA, when using non-NoPadding padding, encryption with private key objects may use EMSA-PKCS1-v1_5 padding (using the private key exponent to construct a public key object does not have this problem ), so when interoperating between different programs, you may need to use the corresponding padding algorithm to first fill the data, and then use NoPadding padding to encrypt (decryption also uses NoPadding padding to decrypt, and then remove the padding data). `string` **Encrypt(string padding, string str)**: Encrypt arbitrary length string (utf-8) returns base64, and an exception is thrown if an error occurs. This method is thread safe. padding specifies the encryption padding, such as: PKCS1, OAEP+SHA256 uppercase, refer to the encryption padding table above, and the default is PKCS1 when using a null value. diff --git a/README.md b/README.md index f277192..ab36234 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,10 @@ var isVerify=rsa.Verify("PKCS1+SHA1", sign, "测试123"); var pemTxt=rsa.ToPEM().ToPEM_PKCS8(); //非常规的(不安全、不建议使用):私钥加密、公钥解密,公钥签名、私钥验证 -RSA_Util rsa2=rsa.SwapKey_Exponent_D__Unsafe(); -//... rsa2.Encrypt rsa2.Decrypt rsa2.Sign rsa2.Verify +RSA_Util rsaS_Private=rsa.SwapKey_Exponent_D__Unsafe(); +RSA_Util rsaS_Public=new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe(); +//... rsaS_Private.Encrypt rsaS_Public.Decrypt +//... rsaS_Public.Sign rsaS_Private.Verify Console.WriteLine(pemTxt+"\n"+enTxt+"\n"+deTxt+"\n"+sign+"\n"+isVerify); Console.ReadLine(); @@ -122,7 +124,7 @@ Console.ReadLine(); 加密填充方式|Algorithm|Frame|Core|BC :-|:-|:-:|:-:|:-: -NO|RSA/ECB/NoPadding|×|×|√ +NO|RSA/ECB/NoPadding|√|√|√ PKCS1 |RSA/ECB/PKCS1Padding|√|√|√ OAEP+SHA1 |RSA/ECB/OAEPwithSHA-1andMGF1Padding|√|√|√ OAEP+SHA256|RSA/ECB/OAEPwithSHA-256andMGF1Padding|4.6+|√|√ @@ -292,7 +294,7 @@ PSS+MD5 |MD5withRSA/PSS|4.6+|√|√ `RSA_PEM` **ToPEM(bool convertToPublic = false)**:导出RSA_PEM对象(然后可以通过RSA_PEM.ToPEM方法导出PEM文本),如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响。 -`RSA_Util` **SwapKey_Exponent_D__Unsafe()**:【不安全、不建议使用】对调交换公钥指数(Key_Exponent)和私钥指数(Key_D):把公钥当私钥使用(new.Key_D=this.Key_Exponent)、私钥当公钥使用(new.Key_Exponent=this.Key_D),返回一个新RSA对象;比如用于:私钥加密、公钥解密,这是非常规的用法。当前对象必须含私钥,否则无法交换会直接抛异常。注意:把公钥当私钥使用是非常不安全的,因为绝大部分生成的密钥的公钥指数为 0x10001(AQAB),太容易被猜测到,无法作为真正意义上的私钥。交换后的密钥不支持在RSACryptoServiceProvider(.NET Framework 4.5及以下版本)中使用:`!IS_CoreOr46 && !IsUseBouncyCastle`。 +`RSA_Util` **SwapKey_Exponent_D__Unsafe()**:【不安全、不建议使用】对调交换公钥指数(Key_Exponent)和私钥指数(Key_D):把公钥当私钥使用(new.Key_D=this.Key_Exponent)、私钥当公钥使用(new.Key_Exponent=this.Key_D),返回一个新RSA对象;比如用于:私钥加密、公钥解密,这是非常规的用法。当前密钥如果只包含公钥,将不会发生对调,返回的新RSA将允许用公钥进行解密和签名操作;但.NET自带的RSA不支持仅含公钥的密钥进行解密和签名,必须进行指数对调(如果是.NET Framework 4.5及以下版本,公钥私钥均不支持),使用NoPadding填充方式或IsUseBouncyCastle时无此问题。注意:把公钥当私钥使用是非常不安全的,因为绝大部分生成的密钥的公钥指数为 0x10001(AQAB),太容易被猜测到,无法作为真正意义上的私钥。部分私钥加密实现中,比如Java自带的RSA,使用非NoPadding填充方式时,用私钥对象进行加密可能会采用EMSA-PKCS1-v1_5填充方式(用私钥指数构造成公钥对象无此问题),因此在不同程序之间互通时,可能需要自行使用对应填充算法先对数据进行填充,然后再用NoPadding填充方式进行加密(解密也按NoPadding填充进行解密,然后去除填充数据)。 `string` **Encrypt(string padding, string str)**:加密任意长度字符串(utf-8)返回base64,出错抛异常。本方法线程安全。padding指定填充方式,如:PKCS1、OAEP+SHA256大写,参考上面的加密填充方式表格,使用空值时默认为PKCS1。 diff --git a/RSA_Util.cs b/RSA_Util.cs index 9f45c4d..31ff216 100644 --- a/RSA_Util.cs +++ b/RSA_Util.cs @@ -10,6 +10,7 @@ using System; using System.IO; +using System.Numerics; using System.Reflection; using System.Security.Cryptography; using System.Text; @@ -44,12 +45,17 @@ public RSA_PEM ToPEM(bool convertToPublic = false) { return PEM__.CopyToNew(convertToPublic); } /// - /// 【不安全、不建议使用】对调交换公钥指数(Key_Exponent)和私钥指数(Key_D):把公钥当私钥使用(new.Key_D=this.Key_Exponent)、私钥当公钥使用(new.Key_Exponent=this.Key_D),返回一个新RSA对象;比如用于:私钥加密、公钥解密,这是非常规的用法 - /// 。当前对象必须含私钥,否则无法交换会直接抛异常 - /// 。注意:把公钥当私钥使用是非常不安全的,因为绝大部分生成的密钥的公钥指数为 0x10001(AQAB),太容易被猜测到,无法作为真正意义上的私钥 - /// 。交换后的密钥不支持在RSACryptoServiceProvider(.NET Framework 4.5及以下版本)中使用:!IS_CoreOr46 And !IsUseBouncyCastle + /// 【不安全、不建议使用】对调交换公钥指数(Key_Exponent)和私钥指数(Key_D):把公钥当私钥使用(new.Key_D=this.Key_Exponent)、私钥当公钥使用(new.Key_Exponent=this.Key_D),返回一个新RSA对象;比如用于:私钥加密、公钥解密,这是非常规的用法。 + ///

当前密钥如果只包含公钥,将不会发生对调,返回的新RSA将允许用公钥进行解密和签名操作;但.NET自带的RSA不支持仅含公钥的密钥进行解密和签名,必须进行指数对调(如果是.NET Framework 4.5及以下版本,公钥私钥均不支持),使用NoPadding填充方式或IsUseBouncyCastle时无此问题。 + ///

注意:把公钥当私钥使用是非常不安全的,因为绝大部分生成的密钥的公钥指数为 0x10001(AQAB),太容易被猜测到,无法作为真正意义上的私钥。 + ///

部分私钥加密实现中,比如Java自带的RSA,使用非NoPadding填充方式时,用私钥对象进行加密可能会采用EMSA-PKCS1-v1_5填充方式(用私钥指数构造成公钥对象无此问题),因此在不同程序之间互通时,可能需要自行使用对应填充算法先对数据进行填充,然后再用NoPadding填充方式进行加密(解密也按NoPadding填充进行解密,然后去除填充数据)。 ///
public RSA_Util SwapKey_Exponent_D__Unsafe() { + if (PEM__.Key_D == null) { + var rsa = new RSA_Util(PEM__.CopyToNew(false)); + rsa.allowKeyDNull = true; + return rsa; + } return new RSA_Util(PEM__.SwapKey_Exponent_D__Unsafe()); } @@ -467,6 +473,15 @@ private RSA createRSA() { } + private bool allowKeyDNull; + private void checkKeyD(bool usePub) { + if (usePub) return; + if (PEM__.Key_D != null) return; + if (allowKeyDNull) return; + throw new Exception(T("当前是公钥,常规情况下不允许进行Decrypt或Sign操作,可以调用SwapKey方法来允许进行此操作", "Currently it is a public key. Decrypt or Sign operations are not allowed under normal circumstances. You can call the SwapKey method to allow this operation.")); + } + + @@ -539,6 +554,7 @@ static private void __OaepParam(string ctype, out string outType, out string out outHash = hash; } private byte[] __EncDec(bool isEnc, string ctype, byte[] data, int blockLen) { + checkKeyD(isEnc); string ctype0 = ctype, CType = ctype.ToUpper(); bool isNO = false, isOaep = false; @@ -589,6 +605,29 @@ private byte[] __EncDec(bool isEnc, string ctype, byte[] data, int blockLen) { return (byte[])processBlock.Invoke(cipher, new object[] { data, offset, len }); }; #endif + } else if (isNO) { + //.NET不支持NoPadding,手动实现一下 + var n = RSA_PEM.BigX(PEM__.Key_Modulus); + var e = RSA_PEM.BigX(PEM__.Key_Exponent); + if (!isEnc && PEM__.Key_D != null) {//如果未提供私钥,将用公钥解密 + e = RSA_PEM.BigX(PEM__.Key_D); + } + process = (offset, len) => { + if (isEnc) { + byte[] pad0 = new byte[blockLen]; + Array.Copy(data, offset, pad0, pad0.Length - len, len); + var m = RSA_PEM.BigX(pad0); + var c = BigInteger.ModPow(m, e, n); + return RSA_PEM.BigB(c); + } else { + var enc = new byte[len]; + Array.Copy(data, offset, enc, 0, len); + var m = RSA_PEM.BigX(enc); + var c = BigInteger.ModPow(m, e, n); + return RSA_PEM.BigB(c); + } + }; + destory = () => { }; } else if (IS_CoreOr46) { //使用高版本RSA进行加密解密,4.6+ 或 Core if (isNO) throw new Exception(NetNotSupportMsg(ctype0 + T("加密填充模式", " encryption padding mode"))); @@ -677,6 +716,7 @@ private bool __Verify(string hash, byte[] sign, byte[] data) { } static private Regex HS_Exp = new Regex("^SHA(3-|-?512/)?[\\-/]?(\\d+)WITHRSA$"); private void __SignVerify(bool isSign, string hashType, byte[] data, byte[] signData, out byte[] signVal, out bool verifyVal) { + checkKeyD(!isSign); string stype = RSAPadding_Sign(hashType), SType = stype.ToUpper(); bool isPss = SType.EndsWith("/PSS"); @@ -866,17 +906,35 @@ private dynamic Bc_Key(bool usePub) { return val; }; #if RSA_Util_BouncyCastle_CompileCode_1 - BcInt[] ks = new BcInt[] { new BcInt(BigX(k.Key_Modulus)), new BcInt(BigX(k.Key_Exponent)), new BcInt(BigX(k.Key_D)), new BcInt(BigX(k.Val_P)), new BcInt(BigX(k.Val_Q)), new BcInt(BigX(k.Val_DP)), new BcInt(BigX(k.Val_DQ)), new BcInt(BigX(k.Val_InverseQ)) }; - if (usePub) { - return new RsaKeyParameters(false, ks[0], ks[1]); - } + BcInt[] ks = new BcInt[8]; + ks[0] = new BcInt(BigX(k.Key_Modulus)); + ks[1] = new BcInt(BigX(k.Key_Exponent)); + checkKeyD(usePub); + if (usePub || k.Key_D == null) { + return new RsaKeyParameters(!usePub, ks[0], ks[1]); + } + ks[2] = new BcInt(BigX(k.Key_D)); + ks[3] = new BcInt(BigX(k.Val_P)); + ks[4] = new BcInt(BigX(k.Val_Q)); + ks[5] = new BcInt(BigX(k.Val_DP)); + ks[6] = new BcInt(BigX(k.Val_DQ)); + ks[7] = new BcInt(BigX(k.Val_InverseQ)); return new RsaPrivateCrtKeyParameters(ks[0], ks[1], ks[2], ks[3], ks[4], ks[5], ks[6], ks[7]); #else var BInt = rsaBouncyCastle.GetType("Org.BouncyCastle.Math.BigInteger").GetConstructor(new Type[] { typeof(byte[]) }); - object[] ks = new object[] { BInt.Invoke(new object[] { BigX(k.Key_Modulus) }), BInt.Invoke(new object[] { BigX(k.Key_Exponent) }), BInt.Invoke(new object[] { BigX(k.Key_D) }), BInt.Invoke(new object[] { BigX(k.Val_P) }), BInt.Invoke(new object[] { BigX(k.Val_Q) }), BInt.Invoke(new object[] { BigX(k.Val_DP) }), BInt.Invoke(new object[] { BigX(k.Val_DQ) }), BInt.Invoke(new object[] { BigX(k.Val_InverseQ) }) }; - if (usePub) { - return FindCtor(rsaBouncyCastle.GetType("Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters"), new string[] { "bool", "big", "big" }).Invoke(new object[] { false, ks[0], ks[1] }); - } + object[] ks = new object[8]; + ks[0] = BInt.Invoke(new object[] { BigX(k.Key_Modulus) }); + ks[1] = BInt.Invoke(new object[] { BigX(k.Key_Exponent) }); + checkKeyD(usePub); + if (usePub || k.Key_D == null) {//如果未提供私钥,将用公钥解密、签名 + return FindCtor(rsaBouncyCastle.GetType("Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters"), new string[] { "bool", "big", "big" }).Invoke(new object[] { !usePub, ks[0], ks[1] }); + } + ks[2] = BInt.Invoke(new object[] { BigX(k.Key_D) }); + ks[3] = BInt.Invoke(new object[] { BigX(k.Val_P) }); + ks[4] = BInt.Invoke(new object[] { BigX(k.Val_Q) }); + ks[5] = BInt.Invoke(new object[] { BigX(k.Val_DP) }); + ks[6] = BInt.Invoke(new object[] { BigX(k.Val_DQ) }); + ks[7] = BInt.Invoke(new object[] { BigX(k.Val_InverseQ) }); return FindCtor(rsaBouncyCastle.GetType("Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters"), new string[] { "big", "big", "big", "big", "big", "big", "big", "big" }).Invoke(ks); #endif }