DotNetUtilities.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. #if NET5_0_OR_GREATER
  5. using System.Runtime.Versioning;
  6. #endif
  7. using System.Security.Cryptography;
  8. using SystemX509 = System.Security.Cryptography.X509Certificates;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Pkcs;
  11. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  12. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X9;
  13. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  14. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators;
  15. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  16. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
  17. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  18. using Best.HTTP.SecureProtocol.Org.BouncyCastle.X509;
  19. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Security
  20. {
  21. /// <summary>
  22. /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world.
  23. /// </summary>
  24. public static class DotNetUtilities
  25. {
  26. /// <summary>
  27. /// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure.
  28. /// </summary>
  29. /// <param name="x509Struct"></param>
  30. /// <returns>A System.Security.Cryptography.X509Certificate.</returns>
  31. public static SystemX509.X509Certificate ToX509Certificate(
  32. X509CertificateStructure x509Struct)
  33. {
  34. return new SystemX509.X509Certificate(x509Struct.GetDerEncoded());
  35. }
  36. public static SystemX509.X509Certificate ToX509Certificate(
  37. X509Certificate x509Cert)
  38. {
  39. return new SystemX509.X509Certificate(x509Cert.GetEncoded());
  40. }
  41. public static X509Certificate FromX509Certificate(
  42. SystemX509.X509Certificate x509Cert)
  43. {
  44. return new X509CertificateParser().ReadCertificate(x509Cert.GetRawCertData());
  45. }
  46. public static AsymmetricCipherKeyPair GetDsaKeyPair(DSA dsa)
  47. {
  48. return GetDsaKeyPair(dsa.ExportParameters(true));
  49. }
  50. public static AsymmetricCipherKeyPair GetDsaKeyPair(DSAParameters dp)
  51. {
  52. DsaPublicKeyParameters pubKey = GetDsaPublicKey(dp);
  53. DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters(
  54. new BigInteger(1, dp.X),
  55. pubKey.Parameters);
  56. return new AsymmetricCipherKeyPair(pubKey, privKey);
  57. }
  58. public static DsaPublicKeyParameters GetDsaPublicKey(DSA dsa)
  59. {
  60. return GetDsaPublicKey(dsa.ExportParameters(false));
  61. }
  62. public static DsaPublicKeyParameters GetDsaPublicKey(DSAParameters dp)
  63. {
  64. DsaValidationParameters validationParameters = (dp.Seed != null)
  65. ? new DsaValidationParameters(dp.Seed, dp.Counter)
  66. : null;
  67. DsaParameters parameters = new DsaParameters(
  68. new BigInteger(1, dp.P),
  69. new BigInteger(1, dp.Q),
  70. new BigInteger(1, dp.G),
  71. validationParameters);
  72. return new DsaPublicKeyParameters(
  73. new BigInteger(1, dp.Y),
  74. parameters);
  75. }
  76. #if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER || UNITY_2021_2_OR_NEWER
  77. public static AsymmetricCipherKeyPair GetECDsaKeyPair(ECDsa ecDsa)
  78. {
  79. return GetECKeyPair("ECDSA", ecDsa.ExportParameters(true));
  80. }
  81. public static ECPublicKeyParameters GetECDsaPublicKey(ECDsa ecDsa)
  82. {
  83. return GetECPublicKey("ECDSA", ecDsa.ExportParameters(false));
  84. }
  85. public static AsymmetricCipherKeyPair GetECKeyPair(string algorithm, ECParameters ec)
  86. {
  87. ECPublicKeyParameters pubKey = GetECPublicKey(algorithm, ec);
  88. ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
  89. pubKey.AlgorithmName,
  90. new BigInteger(1, ec.D),
  91. pubKey.Parameters);
  92. return new AsymmetricCipherKeyPair(pubKey, privKey);
  93. }
  94. public static ECPublicKeyParameters GetECPublicKey(string algorithm, ECParameters ec)
  95. {
  96. X9ECParameters x9 = GetX9ECParameters(ec.Curve);
  97. if (x9 == null)
  98. throw new NotSupportedException("Unrecognized curve");
  99. return new ECPublicKeyParameters(
  100. algorithm,
  101. GetECPoint(x9.Curve, ec.Q),
  102. new ECDomainParameters(x9));
  103. }
  104. private static Math.EC.ECPoint GetECPoint(Math.EC.ECCurve curve, ECPoint point)
  105. {
  106. return curve.CreatePoint(new BigInteger(1, point.X), new BigInteger(1, point.Y));
  107. }
  108. private static X9ECParameters GetX9ECParameters(ECCurve curve)
  109. {
  110. if (!curve.IsNamed)
  111. throw new NotSupportedException("Only named curves are supported");
  112. Oid oid = curve.Oid;
  113. if (oid != null)
  114. {
  115. string oidValue = oid.Value;
  116. if (oidValue != null)
  117. return ECKeyPairGenerator.FindECCurveByOid(new DerObjectIdentifier(oidValue));
  118. }
  119. return null;
  120. }
  121. #endif
  122. public static AsymmetricCipherKeyPair GetRsaKeyPair(RSA rsa)
  123. {
  124. return GetRsaKeyPair(rsa.ExportParameters(true));
  125. }
  126. public static AsymmetricCipherKeyPair GetRsaKeyPair(RSAParameters rp)
  127. {
  128. RsaKeyParameters pubKey = GetRsaPublicKey(rp);
  129. RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
  130. pubKey.Modulus,
  131. pubKey.Exponent,
  132. new BigInteger(1, rp.D),
  133. new BigInteger(1, rp.P),
  134. new BigInteger(1, rp.Q),
  135. new BigInteger(1, rp.DP),
  136. new BigInteger(1, rp.DQ),
  137. new BigInteger(1, rp.InverseQ));
  138. return new AsymmetricCipherKeyPair(pubKey, privKey);
  139. }
  140. public static RsaKeyParameters GetRsaPublicKey(RSA rsa)
  141. {
  142. return GetRsaPublicKey(rsa.ExportParameters(false));
  143. }
  144. public static RsaKeyParameters GetRsaPublicKey(
  145. RSAParameters rp)
  146. {
  147. return new RsaKeyParameters(
  148. false,
  149. new BigInteger(1, rp.Modulus),
  150. new BigInteger(1, rp.Exponent));
  151. }
  152. public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey)
  153. {
  154. if (privateKey is DSA dsa)
  155. return GetDsaKeyPair(dsa);
  156. #if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER || UNITY_2021_2_OR_NEWER
  157. if (privateKey is ECDsa ecDsa)
  158. return GetECDsaKeyPair(ecDsa);
  159. #endif
  160. if (privateKey is RSA rsa)
  161. return GetRsaKeyPair(rsa);
  162. throw new ArgumentException("Unsupported algorithm specified", nameof(privateKey));
  163. }
  164. #if NET5_0_OR_GREATER
  165. [SupportedOSPlatform("windows")]
  166. #endif
  167. public static RSA ToRSA(RsaKeyParameters rsaKey)
  168. {
  169. // TODO This appears to not work for private keys (when no CRT info)
  170. return CreateRSAProvider(ToRSAParameters(rsaKey));
  171. }
  172. #if NET5_0_OR_GREATER
  173. [SupportedOSPlatform("windows")]
  174. #endif
  175. public static RSA ToRSA(RsaKeyParameters rsaKey, CspParameters csp)
  176. {
  177. // TODO This appears to not work for private keys (when no CRT info)
  178. return CreateRSAProvider(ToRSAParameters(rsaKey), csp);
  179. }
  180. #if NET5_0_OR_GREATER
  181. [SupportedOSPlatform("windows")]
  182. #endif
  183. public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
  184. {
  185. return CreateRSAProvider(ToRSAParameters(privKey));
  186. }
  187. #if NET5_0_OR_GREATER
  188. [SupportedOSPlatform("windows")]
  189. #endif
  190. public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey, CspParameters csp)
  191. {
  192. return CreateRSAProvider(ToRSAParameters(privKey), csp);
  193. }
  194. #if NET5_0_OR_GREATER
  195. [SupportedOSPlatform("windows")]
  196. #endif
  197. public static RSA ToRSA(RsaPrivateKeyStructure privKey)
  198. {
  199. return CreateRSAProvider(ToRSAParameters(privKey));
  200. }
  201. #if NET5_0_OR_GREATER
  202. [SupportedOSPlatform("windows")]
  203. #endif
  204. public static RSA ToRSA(RsaPrivateKeyStructure privKey, CspParameters csp)
  205. {
  206. return CreateRSAProvider(ToRSAParameters(privKey), csp);
  207. }
  208. public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
  209. {
  210. RSAParameters rp = new RSAParameters();
  211. rp.Modulus = rsaKey.Modulus.ToByteArrayUnsigned();
  212. if (rsaKey.IsPrivate)
  213. rp.D = ConvertRSAParametersField(rsaKey.Exponent, rp.Modulus.Length);
  214. else
  215. rp.Exponent = rsaKey.Exponent.ToByteArrayUnsigned();
  216. return rp;
  217. }
  218. public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
  219. {
  220. RSAParameters rp = new RSAParameters();
  221. rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
  222. rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
  223. rp.P = privKey.P.ToByteArrayUnsigned();
  224. rp.Q = privKey.Q.ToByteArrayUnsigned();
  225. rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
  226. rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
  227. rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
  228. rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
  229. return rp;
  230. }
  231. public static RSAParameters ToRSAParameters(RsaPrivateKeyStructure privKey)
  232. {
  233. RSAParameters rp = new RSAParameters();
  234. rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
  235. rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
  236. rp.P = privKey.Prime1.ToByteArrayUnsigned();
  237. rp.Q = privKey.Prime2.ToByteArrayUnsigned();
  238. rp.D = ConvertRSAParametersField(privKey.PrivateExponent, rp.Modulus.Length);
  239. rp.DP = ConvertRSAParametersField(privKey.Exponent1, rp.P.Length);
  240. rp.DQ = ConvertRSAParametersField(privKey.Exponent2, rp.Q.Length);
  241. rp.InverseQ = ConvertRSAParametersField(privKey.Coefficient, rp.Q.Length);
  242. return rp;
  243. }
  244. private static byte[] ConvertRSAParametersField(BigInteger n, int size)
  245. {
  246. return BigIntegers.AsUnsignedByteArray(size, n);
  247. }
  248. // TODO Why do we use CspParameters instead of just RSA.Create in methods below?
  249. // private static RSA CreateRSA(RSAParameters rp)
  250. // {
  251. //#if NETCOREAPP2_0_OR_GREATER || NET472_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  252. // return RSA.Create(rp);
  253. //#else
  254. // var rsa = RSA.Create();
  255. // rsa.ImportParameters(rp);
  256. // return rsa;
  257. //#endif
  258. // }
  259. #if NET5_0_OR_GREATER
  260. [SupportedOSPlatform("windows")]
  261. #endif
  262. private static RSACryptoServiceProvider CreateRSAProvider(RSAParameters rp)
  263. {
  264. CspParameters csp = new CspParameters();
  265. csp.KeyContainerName = string.Format("BouncyCastle-{0}", Guid.NewGuid());
  266. return CreateRSAProvider(rp, csp);
  267. }
  268. #if NET5_0_OR_GREATER
  269. [SupportedOSPlatform("windows")]
  270. #endif
  271. private static RSACryptoServiceProvider CreateRSAProvider(RSAParameters rp, CspParameters csp)
  272. {
  273. RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp);
  274. rsaCsp.ImportParameters(rp);
  275. return rsaCsp;
  276. }
  277. }
  278. }
  279. #pragma warning restore
  280. #endif