Skip to content

Commit 1e4ae87

Browse files
committed
Release Update v1.6, 重新发布,调整部分逻辑,修复错误
1 parent 34b1efc commit 1e4ae87

File tree

4 files changed

+115
-37
lines changed

4 files changed

+115
-37
lines changed

Program.cs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,18 @@ static void RSATest(bool fast) {
114114

115115
//对调交换公钥私钥
116116
ST("【Unsafe|对调公钥私钥,私钥加密公钥解密】", "[ Unsafe | Swap the public key and private key, private key encryption and public key decryption ]");
117-
rsa4 = rsa.SwapKey_Exponent_D__Unsafe();
117+
var rsaPri = rsa.SwapKey_Exponent_D__Unsafe();
118+
var rsaPub = new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe();
119+
if (!RSA_Util.IsUseBouncyCastle) {
120+
rsaPub = rsaPri;
121+
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.");
122+
}
118123
try {
119-
var en4 = rsa4.Encrypt("PKCS1", str);
120-
var sign4 = rsa4.Sign("SHA1", str);
121-
de = rsa4.Decrypt("PKCS1", en4);
124+
var enPri = rsaPri.Encrypt("PKCS1", str);
125+
var signPub = rsaPub.Sign("SHA1", str);
126+
de = rsaPub.Decrypt("PKCS1", enPri);
122127
AssertMsg(de, de == str);
123-
AssertMsg(T("校验 OK", "Verify OK"), rsa4.Verify("SHA1", sign4, str));
128+
AssertMsg(T("校验 OK", "Verify OK"), rsaPri.Verify("SHA1", signPub, str));
124129
} catch (Exception e) {
125130
if (!RSA_Util.IS_CoreOr46 && !RSA_Util.IsUseBouncyCastle) {
126131
S(T("不支持在RSACryptoServiceProvider中使用:", "Not supported in RSACryptoServiceProvider: ") + e.Message);
@@ -129,7 +134,7 @@ static void RSATest(bool fast) {
129134
}
130135
}
131136

132-
rsa4 = rsa4.SwapKey_Exponent_D__Unsafe();
137+
rsa4 = rsaPri.SwapKey_Exponent_D__Unsafe();
133138
de = rsa4.Decrypt("PKCS1", en);
134139
AssertMsg(de, de == str);
135140
AssertMsg(T("校验 OK", "Verify OK"), rsa4.Verify("SHA1", sign, str));
@@ -141,7 +146,7 @@ static void RSATest(bool fast) {
141146
ST("【测试一遍所有的加密、解密填充方式】 按回车键继续测试...", "[ Test all the encryption and decryption padding mode ] Press Enter to continue testing...");
142147
ReadIn();
143148
RSA_Util rsa5 = new RSA_Util(2048);
144-
testPaddings(false, rsa5, true);
149+
testPaddings(false, rsa5, new RSA_Util(rsa5.ToPEM(true)), true);
145150
}
146151
}
147152
static Type Type_RuntimeInformation(Type[] outOSPlatform) {
@@ -404,10 +409,20 @@ static void testProvider(bool checkOpenSSL) {
404409

405410
S(HR);
406411
ST("测试一遍所有的加密、解密填充方式:", "Test all the encryption and decryption padding mode:");
407-
testPaddings(checkOpenSSL, rsa, true);
412+
testPaddings(checkOpenSSL, rsa, new RSA_Util(rsa.ToPEM(true)), true);
413+
414+
S(HR);
415+
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");
416+
Console.Write("> ");
417+
string yn = ReadIn().Trim().ToUpper();
418+
if (yn == "Y") {
419+
var rsaPri = rsa.SwapKey_Exponent_D__Unsafe();
420+
var rsaPub = new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe();
421+
testPaddings(checkOpenSSL, rsaPub, rsaPri, true);
422+
}
408423
}
409424
/// <summary>测试一遍所有的加密、解密填充方式</summary>
410-
static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) {
425+
static int testPaddings(bool checkOpenSSL, RSA_Util rsaPri, RSA_Util rsaPub, bool log) {
411426
int errCount = 0;
412427
var errMsgs = new List<string>();
413428
var txt = "1234567890";
@@ -419,7 +434,7 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) {
419434

420435
if (checkOpenSSL) {
421436
try {
422-
runOpenSSL(rsa, txtData);
437+
runOpenSSL(rsaPri.HasPrivate ? rsaPri : rsaPub, txtData);
423438
} catch (Exception e) {
424439
S(T("运行OpenSSL失败:", "Failed to run OpenSSL: ") + e.Message);
425440
return errCount;
@@ -431,8 +446,8 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) {
431446
var errMsg = "";
432447
try {
433448
{
434-
byte[] enc = rsa.Encrypt(type, txtData);
435-
byte[] dec = rsa.Decrypt(type, enc);
449+
byte[] enc = rsaPub.Encrypt(type, txtData);
450+
byte[] dec = rsaPri.Decrypt(type, enc);
436451
bool isOk = true;
437452
if (dec.Length != txtData.Length) {
438453
isOk = false;
@@ -456,7 +471,7 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) {
456471
errMsg = "+OpenSSL: " + T("OpenSSL加密出错", "OpenSSL encryption error");
457472
throw e;
458473
}
459-
byte[] dec = rsa.Decrypt(type, enc);
474+
byte[] dec = rsaPri.Decrypt(type, enc);
460475
bool isOk = true;
461476
if (dec.Length != txtData.Length) {
462477
isOk = false;
@@ -493,8 +508,8 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) {
493508
var errMsg = "";
494509
try {
495510
{
496-
byte[] sign = rsa.Sign(type, txtData);
497-
var isOk = rsa.Verify(type, sign, txtData);
511+
byte[] sign = rsaPri.Sign(type, txtData);
512+
var isOk = rsaPub.Verify(type, sign, txtData);
498513
if (!isOk) {
499514
errMsg = T("未通过校验", "Failed verification");
500515
throw new Exception(errMsg);
@@ -508,7 +523,7 @@ static int testPaddings(bool checkOpenSSL, RSA_Util rsa, bool log) {
508523
errMsg = "+OpenSSL: " + T("OpenSSL签名出错", "OpenSSL signature error");
509524
throw e;
510525
}
511-
var isOk = rsa.Verify(type, sign, txtData);
526+
var isOk = rsaPub.Verify(type, sign, txtData);
512527
if (!isOk) {
513528
errMsg = "+OpenSSL: " + T("未通过校验", "Failed verification");
514529
throw new Exception(errMsg);
@@ -550,12 +565,13 @@ static void threadRun() {
550565
int Count = 0;
551566
int ErrCount = 0;
552567
RSA_Util rsa = new RSA_Util(2048);
568+
RSA_Util rsaPub = new RSA_Util(rsa.ToPEM(true));
553569
S(T("正在测试中,线程数:", "Under test, number of threads: ") + ThreadCount + T(",按回车键结束测试...", ", press enter to end the test..."));
554570

555571
for (int i = 0; i < ThreadCount; i++) {
556572
new Thread(() => {
557573
while (!Abort) {
558-
int err = testPaddings(false, rsa, false);
574+
int err = testPaddings(false, rsa, rsaPub, false);
559575
if (err > 0) {
560576
Interlocked.Add(ref ErrCount, err);
561577
}

README-English.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ var isVerify=rsa.Verify("PKCS1+SHA1", sign, "test123");
7575
var pemTxt=rsa.ToPEM().ToPEM_PKCS8();
7676

7777
//Unconventional (unsafe, not recommended): private key encryption, public key decryption, public key signature, private key verification
78-
RSA_Util rsa2=rsa.SwapKey_Exponent_D__Unsafe();
79-
//... rsa2.Encrypt rsa2.Decrypt rsa2.Sign rsa2.Verify
78+
RSA_Util rsaS_Private=rsa.SwapKey_Exponent_D__Unsafe();
79+
RSA_Util rsaS_Public=new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe();
80+
//... rsaS_Private.Encrypt rsaS_Public.Decrypt
81+
//... rsaS_Public.Sign rsaS_Private.Verify
8082
8183
Console.WriteLine(pemTxt+"\n"+enTxt+"\n"+deTxt+"\n"+sign+"\n"+isVerify);
8284
Console.ReadLine();
@@ -121,7 +123,7 @@ Welcome to join QQ group: 421882406, pure lowercase password: `xiangyuecn`
121123
122124
Padding|Algorithm|Frame|Core|BC
123125
:-|:-|:-:|:-:|:-:
124-
NO|RSA/ECB/NoPadding|×|×|√
126+
NO|RSA/ECB/NoPadding|√|√|√
125127
PKCS1 |RSA/ECB/PKCS1Padding|√|√|√
126128
OAEP+SHA1 |RSA/ECB/OAEPwithSHA-1andMGF1Padding|√|√|√
127129
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
291293

292294
`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.
293295

294-
`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`.
296+
`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).
295297

296298
`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.
297299

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,10 @@ var isVerify=rsa.Verify("PKCS1+SHA1", sign, "测试123");
7676
var pemTxt=rsa.ToPEM().ToPEM_PKCS8();
7777

7878
//非常规的(不安全、不建议使用):私钥加密、公钥解密,公钥签名、私钥验证
79-
RSA_Util rsa2=rsa.SwapKey_Exponent_D__Unsafe();
80-
//... rsa2.Encrypt rsa2.Decrypt rsa2.Sign rsa2.Verify
79+
RSA_Util rsaS_Private=rsa.SwapKey_Exponent_D__Unsafe();
80+
RSA_Util rsaS_Public=new RSA_Util(rsa.ToPEM(true)).SwapKey_Exponent_D__Unsafe();
81+
//... rsaS_Private.Encrypt rsaS_Public.Decrypt
82+
//... rsaS_Public.Sign rsaS_Private.Verify
8183
8284
Console.WriteLine(pemTxt+"\n"+enTxt+"\n"+deTxt+"\n"+sign+"\n"+isVerify);
8385
Console.ReadLine();
@@ -122,7 +124,7 @@ Console.ReadLine();
122124
123125
加密填充方式|Algorithm|Frame|Core|BC
124126
:-|:-|:-:|:-:|:-:
125-
NO|RSA/ECB/NoPadding|×|×|√
127+
NO|RSA/ECB/NoPadding|√|√|√
126128
PKCS1 |RSA/ECB/PKCS1Padding|√|√|√
127129
OAEP+SHA1 |RSA/ECB/OAEPwithSHA-1andMGF1Padding|√|√|√
128130
OAEP+SHA256|RSA/ECB/OAEPwithSHA-256andMGF1Padding|4.6+|√|√
@@ -292,7 +294,7 @@ PSS+MD5 |MD5withRSA/PSS|4.6+|√|√
292294

293295
`RSA_PEM` **ToPEM(bool convertToPublic = false)**:导出RSA_PEM对象(然后可以通过RSA_PEM.ToPEM方法导出PEM文本),如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响。
294296

295-
`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`
297+
`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填充进行解密,然后去除填充数据)
296298

297299
`string` **Encrypt(string padding, string str)**:加密任意长度字符串(utf-8)返回base64,出错抛异常。本方法线程安全。padding指定填充方式,如:PKCS1、OAEP+SHA256大写,参考上面的加密填充方式表格,使用空值时默认为PKCS1。
298300

0 commit comments

Comments
 (0)