LianLianPaySecurity.cs 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Essensoft.AspNetCore.Payment.Security;
  5. using Org.BouncyCastle.Crypto;
  6. namespace Essensoft.AspNetCore.Payment.LianLianPay.Utility
  7. {
  8. public class LianLianPaySecurity
  9. {
  10. public static string GetSignContent(LianLianPayDictionary para, List<string> exclude = null)
  11. {
  12. if (para == null || para.Count == 0)
  13. {
  14. return string.Empty;
  15. }
  16. var sb = new StringBuilder();
  17. foreach (var iter in para)
  18. {
  19. if (exclude != null && exclude.Contains(iter.Key))
  20. {
  21. continue;
  22. }
  23. if (!string.IsNullOrEmpty(iter.Value) && "sign" != iter.Key)
  24. {
  25. sb.Append(iter.Key).Append("=").Append(iter.Value).Append("&");
  26. }
  27. }
  28. return sb.Remove(sb.Length - 1, 1).ToString();
  29. }
  30. public static string Encrypt(string plaintext, AsymmetricKeyParameter public_key)
  31. {
  32. var hmack_key = Guid.NewGuid().ToString("N");
  33. var version = "lianpay1_0_1";
  34. var aes_key = Guid.NewGuid().ToString("N");
  35. var nonce = Guid.NewGuid().ToString("N").Substring(0, 8);
  36. return LianlianpayEncrypt(plaintext, public_key, hmack_key, version, aes_key, nonce);
  37. }
  38. public static string Decrypt(string ciphertext, AsymmetricKeyParameter private_key)
  39. {
  40. if (!string.IsNullOrEmpty(ciphertext))
  41. {
  42. var ciphertextArry = ciphertext.Split('$');
  43. var base64_encrypted_aes_key = ciphertextArry.Length > 2 ? ciphertextArry[2] : string.Empty;
  44. var base64_nonce = ciphertextArry.Length > 3 ? ciphertextArry[3] : string.Empty;
  45. var base64_ciphertext = ciphertextArry.Length > 4 ? ciphertextArry[4] : string.Empty;
  46. return LianlianpayDecrypt(base64_ciphertext, base64_encrypted_aes_key, base64_nonce, private_key);
  47. }
  48. else
  49. {
  50. return string.Empty;
  51. }
  52. }
  53. private static string LianlianpayEncrypt(string req, AsymmetricKeyParameter public_key, string hmack_key, string version, string aes_key, string nonce)
  54. {
  55. var b64Hmack_key = RSA_ECB_OAEPWithSHA1AndMGF1Padding.Encrypt(hmack_key, public_key);
  56. var b64Aes_key = RSA_ECB_OAEPWithSHA1AndMGF1Padding.Encrypt(aes_key, public_key);
  57. var b64Nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(nonce));
  58. var iv = CreateCtrIv(Encoding.UTF8.GetBytes(nonce));
  59. var encry = AES_CTR_NoPadding.Encrypt(req, aes_key, iv);
  60. var message = b64Nonce + "$" + encry;
  61. var sign = HMACSHA256.Compute(Encoding.UTF8.GetBytes(message), Encoding.UTF8.GetBytes(hmack_key));
  62. var b64Sign = Convert.ToBase64String(sign);
  63. return version + "$" + b64Hmack_key + "$" + b64Aes_key + "$" + b64Nonce + "$" + encry + "$" + b64Sign;
  64. }
  65. private static string LianlianpayDecrypt(string base64_ciphertext, string base64_encrypted_aes_key, string base64_nonce, AsymmetricKeyParameter trader_pri_key)
  66. {
  67. var key = RSA_ECB_OAEPWithSHA1AndMGF1Padding.Decrypt(base64_encrypted_aes_key, trader_pri_key);
  68. var nonce = Convert.FromBase64String(base64_nonce);
  69. var iv = CreateCtrIv(nonce);
  70. return AES_CTR_NoPadding.Decrypt(base64_ciphertext, key, iv);
  71. }
  72. private static byte[] CreateCtrIv(byte[] nonce)
  73. {
  74. var counter = new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 };
  75. var output = new byte[nonce.Length + counter.Length];
  76. for (var i = 0; i < nonce.Length; ++i)
  77. {
  78. output[i] = nonce[i];
  79. }
  80. for (var i = 0; i < counter.Length; ++i)
  81. {
  82. output[i + nonce.Length] = counter[i];
  83. }
  84. return output;
  85. }
  86. }
  87. }