1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using Org.BouncyCastle.Asn1.X9; 6 using Org.BouncyCastle.Crypto.Parameters; 7 using Org.BouncyCastle.Crypto; 8 using Org.BouncyCastle.Security; 9 using Org.BouncyCastle.Crypto.Engines; 10 using Org.BouncyCastle.Crypto.Digests; 11 using Org.BouncyCastle.Utilities; 12 using Org.BouncyCastle.Utilities.Encoders; 13 using Org.BouncyCastle.Crypto.Generators; 14 using System.IO; 15 using Org.BouncyCastle.X509; 16 using Org.BouncyCastle.Math; 17 using Org.BouncyCastle.Asn1; 18 using System.Text; 19 using Org.BouncyCastle.Asn1.GM; 20 using Org.BouncyCastle.Crypto.Signers; 21 using System.Configuration; 22 23 namespace FBW.MerchantAP.Tools 24 { 25 public class Sm3withSm2Helper 26 { 27 28 private static X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1"); 29 private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N); 30 31 /** 32 * 33 * @param msg 34 * @param userId 35 * @param privateKey 36 * @return r||s,直接拼接byte数组的rs 37 */ 38 public static byte[] SignSm3WithSm2(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey) 39 { 40 return RsAsn1ToPlainByteArray(SignSm3WithSm2Asn1Rs(msg, userId, privateKey)); 41 } 42 43 44 45 /** 46 * 将BC SM2 RAW签名值转化为ASN1格式签名值 47 * @param bcCipTxt 48 * @return 49 * @throws Exception 50 */ 51 private static byte[] signRawToAsn1(byte[] bcCipTxt) 52 { 53 54 byte[] netSignCipTxt = new byte[73]; 55 56 byte[] signR = new byte[32]; 57 byte[] signS = new byte[32]; 58 59 Buffer.BlockCopy(bcCipTxt, 0, signR, 0, 32); 60 Buffer.BlockCopy(bcCipTxt, 32, signS, 0, 32); 61 62 //signR补位 63 int wPos = 4; 64 netSignCipTxt[0] = 0x30; 65 netSignCipTxt[2] = 0x02; 66 if ((signR[0] & 0xFF) >= 128) 67 { 68 netSignCipTxt[wPos - 1] = 0x21; 69 netSignCipTxt[wPos] = 0x00; 70 wPos += 1; 71 } 72 else 73 { 74 netSignCipTxt[wPos - 1] = 0x20; 75 } 76 Buffer.BlockCopy(signR, 0, netSignCipTxt, wPos, 32); 77 wPos += 32; 78 79 //signS补位 80 netSignCipTxt[wPos] = 0x02; 81 wPos += 1; 82 if ((signS[0] & 0xFF) >= 128) 83 { 84 netSignCipTxt[wPos] = 0x21; 85 wPos += 1; 86 netSignCipTxt[wPos] = 0x00; 87 wPos += 1; 88 } 89 else 90 { 91 netSignCipTxt[wPos] = 0x20; 92 wPos += 1; 93 } 94 Buffer.BlockCopy(signS, 0, netSignCipTxt, wPos, 32); 95 wPos += 32; 96 97 if (70 == wPos) 98 { 99 netSignCipTxt[1] = 0x44; 100 } 101 else if (71 == wPos) 102 { 103 netSignCipTxt[1] = 0x45; 104 } 105 else if (72 == wPos) 106 { 107 netSignCipTxt[1] = 0x46; 108 } 109 else 110 { 111 throw new Exception("signRawToAsn1 Error!"); 112 } 113 114 byte[] resultBytes = new byte[wPos]; 115 Buffer.BlockCopy(netSignCipTxt, 0, resultBytes, 0, wPos); 116 117 return resultBytes; 118 } 119 120 /** 121 * 将ASN1格式签名值转化为BC SM2 RAW 签名值 122 * 123 * @param signature Asn1格式签名值 124 * @return byte[] Raw签名值 125 */ 126 private static byte[] signAsn12Raw(byte[] signature) 127 { 128 129 byte[] resultBytes = new byte[64]; 130 131 //截取signR 132 int wPos = 3; 133 if ((signature[wPos] & 0xFF) == 32) 134 { 135 wPos += 1; 136 } 137 else if ((signature[wPos] & 0xFF) == 33) 138 { 139 wPos += 2; 140 } 141 else 142 { 143 throw new Exception("signR length Error!"); 144 } 145 Buffer.BlockCopy(signature, wPos, resultBytes, 0, 32); 146 wPos += 32; 147 148 //截取signS 149 wPos += 1; 150 if ((signature[wPos] & 0xFF) == 32) 151 { 152 wPos += 1; 153 } 154 else if ((signature[wPos] & 0xFF) == 33) 155 { 156 wPos += 2; 157 } 158 else 159 { 160 throw new Exception("signS length Error!"); 161 } 162 Buffer.BlockCopy(signature, wPos, resultBytes, 32, 32); 163 164 165 166 return resultBytes; 167 } 168 169 /** 170 * @param msg 171 * @param userId 172 * @param privateKey 173 * @return rs in <b>asn1 format</b> 174 */ 175 public static byte[] SignSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey) 176 { 177 try 178 { 179 ISigner signer = SignerUtilities.GetSigner("SM3withSM2"); 180 signer.Init(true, new ParametersWithID(privateKey, userId)); 181 signer.BlockUpdate(msg, 0, msg.Length); 182 byte[] sig = signer.GenerateSignature(); 183 return sig; 184 } 185 catch (Exception e) 186 { 187 ////log.Error("SignSm3WithSm2Asn1Rs error: " + e.Message, e); 188 return null; 189 } 190 } 191 192 /** 193 * 194 * @param msg 195 * @param userId 196 * @param rs r||s,直接拼接byte数组的rs 197 * @param publicKey 198 * @return 199 */ 200 public static bool VerifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, AsymmetricKeyParameter publicKey) 201 { 202 if (rs == null || msg == null || userId == null) return false; 203 if (rs.Length != RS_LEN * 2) return false; 204 return VerifySm3WithSm2Asn1Rs(msg, userId, RsPlainByteArrayToAsn1(rs), publicKey); 205 } 206 207 /** 208 * 209 * @param msg 210 * @param userId 211 * @param rs in <b>asn1 format</b> 212 * @param publicKey 213 * @return 214 */ 215 216 public static bool VerifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] sign, AsymmetricKeyParameter publicKey) 217 { 218 try 219 { 220 ISigner signer = SignerUtilities.GetSigner("SM3withSM2"); 221 signer.Init(false, new ParametersWithID(publicKey, userId)); 222 signer.BlockUpdate(msg, 0, msg.Length); 223 return signer.VerifySignature(sign); 224 } 225 catch (Exception e) 226 { 227 ////log.Error("VerifySm3WithSm2Asn1Rs error: " + e.Message, e); 228 return false; 229 } 230 } 231 232 /** 233 * bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2 234 * @param c1c2c3 235 * @return 236 */ 237 private static byte[] ChangeC1C2C3ToC1C3C2(byte[] c1c2c3) 238 { 239 int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。 240 const int c3Len = 32; //new SM3Digest().getDigestSize(); 241 byte[] result = new byte[c1c2c3.Length]; 242 Buffer.BlockCopy(c1c2c3, 0, result, 0, c1Len); //c1 243 Buffer.BlockCopy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3 244 Buffer.BlockCopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2 245 return result; 246 } 247 248 249 /** 250 * bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密 251 * @param c1c3c2 252 * @return 253 */ 254 private static byte[] ChangeC1C3C2ToC1C2C3(byte[] c1c3c2) 255 { 256 int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。 257 const int c3Len = 32; //new SM3Digest().GetDigestSize(); 258 byte[] result = new byte[c1c3c2.Length]; 259 Buffer.BlockCopy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65 260 Buffer.BlockCopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2 261 Buffer.BlockCopy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3 262 return result; 263 } 264 265 /** 266 * c1||c3||c2 267 * @param data 268 * @param key 269 * @return 270 */ 271 public static byte[] Sm2Decrypt(byte[] data, AsymmetricKeyParameter key) 272 { 273 return Sm2DecryptOld(ChangeC1C3C2ToC1C2C3(data), key); 274 } 275 276 /** 277 * c1||c3||c2 278 * @param data 279 * @param key 280 * @return 281 */ 282 283 public static byte[] Sm2Encrypt(byte[] data, AsymmetricKeyParameter key) 284 { 285 return ChangeC1C2C3ToC1C3C2(Sm2EncryptOld(data, key)); 286 } 287 288 /** 289 * c1||c2||c3 290 * @param data 291 * @param key 292 * @return 293 */ 294 public static byte[] Sm2EncryptOld(byte[] data, AsymmetricKeyParameter pubkey) 295 { 296 try 297 { 298 SM2Engine sm2Engine = new SM2Engine(); 299 sm2Engine.Init(true, new ParametersWithRandom(pubkey, new SecureRandom())); 300 return sm2Engine.ProcessBlock(data, 0, data.Length); 301 } 302 catch (Exception e) 303 { 304 ////log.Error("Sm2EncryptOld error: " + e.Message, e); 305 return null; 306 } 307 } 308 309 /** 310 * c1||c2||c3 311 * @param data 312 * @param key 313 * @return 314 */ 315 public static byte[] Sm2DecryptOld(byte[] data, AsymmetricKeyParameter key) 316 { 317 try 318 { 319 SM2Engine sm2Engine = new SM2Engine(); 320 sm2Engine.Init(false, key); 321 return sm2Engine.ProcessBlock(data, 0, data.Length); 322 } 323 catch (Exception e) 324 { 325 ////log.Error("Sm2DecryptOld error: " + e.Message, e); 326 return null; 327 } 328 } 329 330 /** 331 * @param bytes 332 * @return 333 */ 334 public static byte[] Sm3(byte[] bytes) 335 { 336 try 337 { 338 SM3Digest digest = new SM3Digest(); 339 digest.BlockUpdate(bytes, 0, bytes.Length); 340 byte[] result = DigestUtilities.DoFinal(digest); 341 return result; 342 } 343 catch (Exception e) 344 { 345 //log.Error("Sm3 error: " + e.Message, e); 346 return null; 347 } 348 } 349 350 private const int RS_LEN = 32; 351 352 private static byte[] BigIntToFixexLengthBytes(BigInteger rOrS) 353 { 354 // for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123, 355 // r and s are the result of mod n, so they should be less than n and have length<=32 356 byte[] rs = rOrS.ToByteArray(); 357 if (rs.Length == RS_LEN) return rs; 358 else if (rs.Length == RS_LEN + 1 && rs[0] == 0) return Arrays.CopyOfRange(rs, 1, RS_LEN + 1); 359 else if (rs.Length < RS_LEN) 360 { 361 byte[] result = new byte[RS_LEN]; 362 Arrays.Fill(result, (byte)0); 363 Buffer.BlockCopy(rs, 0, result, RS_LEN - rs.Length, rs.Length); 364 return result; 365 } 366 else 367 { 368 throw new ArgumentException("err rs: " + Hex.ToHexString(rs)); 369 } 370 } 371 372 /** 373 * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s 374 * @param rsDer rs in asn1 format 375 * @return sign result in plain byte array 376 */ 377 private static byte[] RsAsn1ToPlainByteArray(byte[] rsDer) 378 { 379 Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer); 380 byte[] r = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value); 381 byte[] s = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value); 382 byte[] result = new byte[RS_LEN * 2]; 383 Buffer.BlockCopy(r, 0, result, 0, r.Length); 384 Buffer.BlockCopy(s, 0, result, RS_LEN, s.Length); 385 return result; 386 } 387 388 /** 389 * BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式 390 * @param sign in plain byte array 391 * @return rs result in asn1 format 392 */ 393 private static byte[] RsPlainByteArrayToAsn1(byte[] sign) 394 { 395 if (sign.Length != RS_LEN * 2) throw new ArgumentException("err rs. "); 396 BigInteger r = new BigInteger(1, Arrays.CopyOfRange(sign, 0, RS_LEN)); 397 BigInteger s = new BigInteger(1, Arrays.CopyOfRange(sign, RS_LEN, RS_LEN * 2)); 398 Asn1EncodableVector v = new Asn1EncodableVector(); 399 v.Add(new DerInteger(r)); 400 v.Add(new DerInteger(s)); 401 try 402 { 403 return new DerSequence(v).GetEncoded("DER"); 404 } 405 catch (IOException e) 406 { 407 //log.Error("RsPlainByteArrayToAsn1 error: " + e.Message, e); 408 return null; 409 } 410 } 411 412 public static AsymmetricCipherKeyPair GenerateKeyPair() 413 { 414 try 415 { 416 ECKeyPairGenerator kpGen = new ECKeyPairGenerator(); 417 kpGen.Init(new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom())); 418 return kpGen.GenerateKeyPair(); 419 } 420 catch (Exception e) 421 { 422 //log.Error("generateKeyPair error: " + e.Message, e); 423 return null; 424 } 425 } 426 427 public static ECPrivateKeyParameters GetPrivatekeyFromD(BigInteger d) 428 { 429 return new ECPrivateKeyParameters(d, ecDomainParameters); 430 } 431 432 public static ECPublicKeyParameters GetPublickeyFromXY(BigInteger x, BigInteger y) 433 { 434 return new ECPublicKeyParameters(x9ECParameters.Curve.CreatePoint(x, y), ecDomainParameters); 435 } 436 437 public static AsymmetricKeyParameter GetPublickeyFromX509File(FileInfo file) 438 { 439 440 FileStream fileStream = null; 441 try 442 { 443 //file.DirectoryName + "\\" + file.Name 444 fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read); 445 X509Certificate certificate = new X509CertificateParser().ReadCertificate(fileStream); 446 return certificate.GetPublicKey(); 447 } 448 catch (Exception e) 449 { 450 //log.Error(file.Name + "读取失败,异常:" + e); 451 } 452 finally 453 { 454 if (fileStream != null) 455 fileStream.Close(); 456 } 457 return null; 458 } 459 460 public class Sm2Cert 461 { 462 public AsymmetricKeyParameter privateKey; 463 public AsymmetricKeyParameter publicKey; 464 public String certId; 465 } 466 467 private static byte[] ToByteArray(int i) 468 { 469 byte[] byteArray = new byte[4]; 470 byteArray[0] = (byte)(i >> 24); 471 byteArray[1] = (byte)((i & 0xFFFFFF) >> 16); 472 byteArray[2] = (byte)((i & 0xFFFF) >> 8); 473 byteArray[3] = (byte)(i & 0xFF); 474 return byteArray; 475 } 476 477 /** 478 * 字节数组拼接 479 * 480 * @param params 481 * @return 482 */ 483 private static byte[] Join(params byte[][] byteArrays) 484 { 485 List<byte> byteSource = new List<byte>(); 486 for (int i = 0; i < byteArrays.Length; i++) 487 { 488 byteSource.AddRange(byteArrays[i]); 489 } 490 byte[] data = byteSource.ToArray(); 491 return data; 492 } 493 494 /** 495 * 密钥派生函数 496 * 497 * @param Z 498 * @param klen 499 * 生成klen字节数长度的密钥 500 * @return 501 */ 502 private static byte[] KDF(byte[] Z, int klen) 503 { 504 int ct = 1; 505 int end = (int)Math.Ceiling(klen * 1.0 / 32); 506 List<byte> byteSource = new List<byte>(); 507 try 508 { 509 for (int i = 1; i < end; i++) 510 { 511 byteSource.AddRange(Sm3withSm2Helper.Sm3(Join(Z, ToByteArray(ct)))); 512 ct++; 513 } 514 byte[] last = Sm3withSm2Helper.Sm3(Join(Z, ToByteArray(ct))); 515 if (klen % 32 == 0) 516 { 517 byteSource.AddRange(last); 518 } 519 else 520 byteSource.AddRange(Arrays.CopyOfRange(last, 0, klen % 32)); 521 return byteSource.ToArray(); 522 } 523 catch (Exception e) 524 { 525 //log.Error("KDF error: " + e.Message, e); 526 } 527 return null; 528 } 529 530 public static byte[] Sm4DecryptCBC(byte[] keyBytes, byte[] cipher, byte[] iv, String algo) 531 { 532 if (keyBytes.Length != 16) throw new ArgumentException("err key length"); 533 if (cipher.Length % 16 != 0) throw new ArgumentException("err data length"); 534 535 try 536 { 537 KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes); 538 IBufferedCipher c = CipherUtilities.GetCipher(algo); 539 if (iv == null) iv = ZeroIv(algo); 540 c.Init(false, new ParametersWithIV(key, iv)); 541 return c.DoFinal(cipher); 542 } 543 catch (Exception e) 544 { 545 //log.Error("Sm4DecryptCBC error: " + e.Message, e); 546 return null; 547 } 548 } 549 550 551 public static byte[] Sm4EncryptCBC(byte[] keyBytes, byte[] plain, byte[] iv, String algo) 552 { 553 if (keyBytes.Length != 16) throw new ArgumentException("err key length"); 554 if (plain.Length % 16 != 0) throw new ArgumentException("err data length"); 555 556 try 557 { 558 KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes); 559 IBufferedCipher c = CipherUtilities.GetCipher(algo); 560 if (iv == null) iv = ZeroIv(algo); 561 c.Init(true, new ParametersWithIV(key, iv)); 562 return c.DoFinal(plain); 563 } 564 catch (Exception e) 565 { 566 //log.Error("Sm4EncryptCBC error: " + e.Message, e); 567 return null; 568 } 569 } 570 571 572 public static byte[] Sm4EncryptECB(byte[] keyBytes, byte[] plain, string algo) 573 { 574 if (keyBytes.Length != 16) throw new ArgumentException("err key length"); 575 if (plain.Length % 16 != 0) throw new ArgumentException("err data length"); 576 577 try 578 { 579 KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes); 580 IBufferedCipher c = CipherUtilities.GetCipher(algo); 581 c.Init(true, key); 582 return c.DoFinal(plain); 583 } 584 catch (Exception e) 585 { 586 //log.Error("Sm4EncryptECB error: " + e.Message, e); 587 return null; 588 } 589 } 590 591 public static byte[] Sm4DecryptECB(byte[] keyBytes, byte[] cipher, string algo) 592 { 593 if (keyBytes.Length != 16) throw new ArgumentException("err key length"); 594 if (cipher.Length % 16 != 0) throw new ArgumentException("err data length"); 595 596 try 597 { 598 KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes); 599 IBufferedCipher c = CipherUtilities.GetCipher(algo); 600 c.Init(false, key); 601 return c.DoFinal(cipher); 602 } 603 catch (Exception e) 604 { 605 //log.Error("Sm4DecryptECB error: " + e.Message, e); 606 return null; 607 } 608 } 609 610 public const String SM4_ECB_NOPADDING = "SM4/ECB/NoPadding"; 611 public const String SM4_CBC_NOPADDING = "SM4/CBC/NoPadding"; 612 public const String SM4_CBC_PKCS7PADDING = "SM4/CBC/PKCS7Padding"; 613 614 /** 615 * cfca官网CSP沙箱导出的sm2文件 616 * @param pem 二进制原文 617 * @param pwd 密码 618 * @return 619 */ 620 public static Sm2Cert readSm2File(byte[] pem, String pwd) 621 { 622 623 Sm2Cert sm2Cert = new Sm2Cert(); 624 try 625 { 626 Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(pem); 627 // ASN1Integer asn1Integer = (ASN1Integer) asn1Sequence.getObjectAt(0); //version=1 628 Asn1Sequence priSeq = (Asn1Sequence)asn1Sequence[1];//private key 629 Asn1Sequence pubSeq = (Asn1Sequence)asn1Sequence[2];//public key and x509 cert 630 631 // ASN1ObjectIdentifier sm2DataOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(0); 632 // ASN1ObjectIdentifier sm4AlgOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(1); 633 Asn1OctetString priKeyAsn1 = (Asn1OctetString)priSeq[2]; 634 byte[] key = KDF(System.Text.Encoding.UTF8.GetBytes(pwd), 32); 635 byte[] priKeyD = Sm4DecryptCBC(Arrays.CopyOfRange(key, 16, 32), 636 priKeyAsn1.GetOctets(), 637 Arrays.CopyOfRange(key, 0, 16), SM4_CBC_PKCS7PADDING); 638 sm2Cert.privateKey = GetPrivatekeyFromD(new BigInteger(1, priKeyD)); 639 // //log.Info(Hex.toHexString(priKeyD)); 640 641 // ASN1ObjectIdentifier sm2DataOidPub = (ASN1ObjectIdentifier) pubSeq.getObjectAt(0); 642 Asn1OctetString pubKeyX509 = (Asn1OctetString)pubSeq[1]; 643 X509Certificate x509 = (X509Certificate)new X509CertificateParser().ReadCertificate(pubKeyX509.GetOctets()); 644 sm2Cert.publicKey = x509.GetPublicKey(); 645 sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进账,有啥其他进制要求的自己改改 646 return sm2Cert; 647 } 648 catch (Exception e) 649 { 650 //log.Error("readSm2File error: " + e.Message, e); 651 return null; 652 } 653 } 654 655 /** 656 * 657 * @param cert 658 * @return 659 */ 660 public static Sm2Cert ReadSm2X509Cert(byte[] cert) 661 { 662 Sm2Cert sm2Cert = new Sm2Cert(); 663 try 664 { 665 666 X509Certificate x509 = new X509CertificateParser().ReadCertificate(cert); 667 sm2Cert.publicKey = x509.GetPublicKey(); 668 sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进账,有啥其他进制要求的自己改改 669 return sm2Cert; 670 } 671 catch (Exception e) 672 { 673 //log.Error("ReadSm2X509Cert error: " + e.Message, e); 674 return null; 675 } 676 } 677 678 public static byte[] ZeroIv(String algo) 679 { 680 681 try 682 { 683 IBufferedCipher cipher = CipherUtilities.GetCipher(algo); 684 int blockSize = cipher.GetBlockSize(); 685 byte[] iv = new byte[blockSize]; 686 Arrays.Fill(iv, (byte)0); 687 return iv; 688 } 689 catch (Exception e) 690 { 691 //log.Error("ZeroIv error: " + e.Message, e); 692 return null; 693 } 694 } 695 696 //国密标准公钥头 697 public const String SM2_KEY_TITLE = "3059301306072a8648ce3d020106082a811ccf5501822d03420004"; 698 public const String USER_ID = "1234567812345678"; 699 700 public class Sm2Vo 701 { 702 public String sm2_x; 703 public String sm2_y; 704 } 705 706 707 /** 708 * BASE64格式公钥转换为裸公钥 709 * @param sm2Key 710 * @return 711 */ 712 private static Sm2Vo parseBase64TRawKey(String sm2Key) 713 { 714 if (null == sm2Key) 715 { 716 return null; 717 } 718 719 String sm2_asn1 = Hex.ToHexString(Convert.FromBase64String(sm2Key)); 720 if (!sm2_asn1.StartsWith(SM2_KEY_TITLE)) 721 { 722 return null; 723 } 724 Sm2Vo sm2Cert = new Sm2Vo(); 725 String sm2_xy = sm2_asn1.Substring(SM2_KEY_TITLE.Length, sm2_asn1.Length - SM2_KEY_TITLE.Length); 726 sm2Cert.sm2_x = sm2_xy.Substring(0, sm2_xy.Length / 2); 727 sm2Cert.sm2_y = sm2_xy.Substring(sm2_xy.Length / 2, sm2_xy.Length - sm2_xy.Length / 2); 728 729 return sm2Cert; 730 } 731 732 /// <summary> 733 /// 使用国密加签(聚合支付) 734 /// </summary> 735 /// <param name="str">需要加签的字符</param> 736 /// <returns></returns> 737 public static string GenerateSmSign(string str) 738 { 739 // 生成公私钥对 740 AsymmetricCipherKeyPair kp = Sm3withSm2Helper.GenerateKeyPair(); 741 string a = Convert.ToString(((ECPrivateKeyParameters)kp.Private).D); 742 string privateKey = ConfigurationManager.AppSettings["privatekey"].ToString(); 743 744 AsymmetricKeyParameter SMprivateKey = GetPrivatekeyFromD(new BigInteger(privateKey, 16)); 745 746 //1.国密签名 747 byte[] msg = System.Text.Encoding.UTF8.GetBytes(str); 748 //签名 USER_ID 应使用国密局推荐 ID,即“1234567812345678” 749 byte[] userId = System.Text.Encoding.UTF8.GetBytes(USER_ID); 750 byte[] sig = SignSm3WithSm2(msg, userId, SMprivateKey); 751 //国密加签结果 752 string c = System.Convert.ToBase64String(signRawToAsn1(sig)); 753 return c; 754 } 755 756 /// <summary> 757 /// 验证加签是否正确(聚合) 758 /// </summary> 759 /// <param name="rawMsg">原字符</param> 760 /// <param name="signedStr">返回的签名</param> 761 /// <returns></returns> 762 public static bool VerifySmSign(string rawMsg, string signedStr) 763 { 764 765 string publicKey = ConfigurationManager.AppSettings["publickey"]; 766 byte[] sig2 = Convert.FromBase64String(signedStr); 767 Sm2Vo sm2Vo = parseBase64TRawKey(publicKey); 768 string privateKeyRawX = sm2Vo.sm2_x; 769 string privateKeyRawY = sm2Vo.sm2_y; 770 AsymmetricKeyParameter SMPbkey = GetPublickeyFromXY(new BigInteger(privateKeyRawX, 16), new BigInteger(privateKeyRawY, 16)); 771 byte[] sig3 = signAsn12Raw(sig2); 772 byte[] msg = System.Text.Encoding.UTF8.GetBytes(rawMsg); 773 //签名 USER_ID 应使用国密局推荐 ID,即“1234567812345678” 774 byte[] userId = System.Text.Encoding.UTF8.GetBytes(USER_ID); 775 bool flag = VerifySm3WithSm2(msg, userId, sig3, SMPbkey); 776 return flag; 777 } 778 779 /// <summary> 780 /// 单笔下单使用国密加签(apiSign) 781 /// </summary> 782 /// <param name="str">需要加签的字符</param> 783 /// <returns></returns> 784 public static string SingOrderGenerateSmSign(string str) 785 { 786 string privateKey = ConfigurationManager.AppSettings["singprivateKey"].ToString(); 787 AsymmetricKeyParameter SMprivateKey = GetPrivatekeyFromD(new BigInteger(privateKey, 16)); 788 //1.国密签名 789 byte[] msg = System.Text.Encoding.UTF8.GetBytes(str); 790 var sm2 = new SM2Signer(new SM3Digest()); 791 ICipherParameters cp; cp = new ParametersWithRandom(SMprivateKey); 792 sm2.Init(true, cp); 793 sm2.BlockUpdate(msg, 0, msg.Length); 794 var signbyte = sm2.GenerateSignature(); 795 return Hex.ToHexString(RsAsn1ToPlainByteArray(signbyte)); 796 } 797 798 /// <summary> 799 ///单笔下单 sm3加密(Sign) 800 /// </summary> 801 /// <param name="data"></param> 802 /// <returns></returns> 803 public static string ToSM3byte(string data) 804 { 805 byte[] msg = Encoding.GetEncoding("utf-8").GetBytes(data); 806 SM3Digest sm3 = new SM3Digest(); 807 sm3.BlockUpdate(msg, 0, msg.Length); 808 byte[] md = new byte[sm3.GetDigestSize()];//SM3算法产生的哈希值大小 809 sm3.DoFinal(md, 0); 810 return new UTF8Encoding().GetString(Hex.Encode(md)); 811 } 812 813 } 814 }
使用 nuget 第三方加密算法包 :
<package id="BouncyCastle" version="1.8.6.1" targetFramework="net452" />
<package id="BouncyCastle.Crypto.dll" version="1.8.1" targetFramework="net452" />