PKMacBuilder.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cmp;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Iana;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Oiw;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.IO;
  12. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  13. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  14. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  15. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crmf
  16. {
  17. internal class PKMacStreamCalculator
  18. : IStreamCalculator
  19. {
  20. private readonly MacSink _stream;
  21. public PKMacStreamCalculator(IMac mac)
  22. {
  23. _stream = new MacSink(mac);
  24. }
  25. public Stream Stream
  26. {
  27. get { return _stream; }
  28. }
  29. public object GetResult()
  30. {
  31. return new DefaultPKMacResult(_stream.Mac);
  32. }
  33. }
  34. internal class PKMacFactory
  35. : IMacFactory
  36. {
  37. protected readonly PbmParameter parameters;
  38. private readonly byte[] key;
  39. public PKMacFactory(byte[] key, PbmParameter parameters)
  40. {
  41. this.key = Arrays.Clone(key);
  42. this.parameters = parameters;
  43. }
  44. public virtual object AlgorithmDetails
  45. {
  46. get { return new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac, parameters); }
  47. }
  48. public virtual IStreamCalculator CreateCalculator()
  49. {
  50. IMac mac = MacUtilities.GetMac(parameters.Mac.Algorithm);
  51. mac.Init(new KeyParameter(key));
  52. return new PKMacStreamCalculator(mac);
  53. }
  54. }
  55. internal class DefaultPKMacResult
  56. : IBlockResult
  57. {
  58. private readonly IMac mac;
  59. public DefaultPKMacResult(IMac mac)
  60. {
  61. this.mac = mac;
  62. }
  63. public byte[] Collect()
  64. {
  65. byte[] res = new byte[mac.GetMacSize()];
  66. mac.DoFinal(res, 0);
  67. return res;
  68. }
  69. public int Collect(byte[] sig, int sigOff)
  70. {
  71. byte[] signature = Collect();
  72. signature.CopyTo(sig, sigOff);
  73. return signature.Length;
  74. }
  75. }
  76. public class PKMacBuilder
  77. {
  78. private AlgorithmIdentifier owf;
  79. private AlgorithmIdentifier mac;
  80. private IPKMacPrimitivesProvider provider;
  81. private SecureRandom random;
  82. private PbmParameter parameters;
  83. private int iterationCount;
  84. private int saltLength = 20;
  85. private int maxIterations;
  86. /// <summary>
  87. /// Default, IterationCount = 1000, OIW=IdSha1, Mac=HmacSHA1
  88. /// </summary>
  89. public PKMacBuilder() :
  90. this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000, new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), new DefaultPKMacPrimitivesProvider())
  91. {
  92. }
  93. /// <summary>
  94. /// Defaults with IPKMacPrimitivesProvider
  95. /// </summary>
  96. /// <param name="provider"></param>
  97. public PKMacBuilder(IPKMacPrimitivesProvider provider) :
  98. this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000, new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), provider)
  99. {
  100. }
  101. /// <summary>
  102. /// Create.
  103. /// </summary>
  104. /// <param name="provider">The Mac provider</param>
  105. /// <param name="digestAlgorithmIdentifier">Digest Algorithm Id</param>
  106. /// <param name="macAlgorithmIdentifier">Mac Algorithm Id</param>
  107. public PKMacBuilder(IPKMacPrimitivesProvider provider, AlgorithmIdentifier digestAlgorithmIdentifier, AlgorithmIdentifier macAlgorithmIdentifier) :
  108. this(digestAlgorithmIdentifier, 1000, macAlgorithmIdentifier, provider)
  109. {
  110. }
  111. /// <summary>
  112. /// Create a PKMAC builder enforcing a ceiling on the maximum iteration count.
  113. /// </summary>
  114. /// <param name="provider">supporting calculator</param>
  115. /// <param name="maxIterations">max allowable value for iteration count.</param>
  116. public PKMacBuilder(IPKMacPrimitivesProvider provider, int maxIterations)
  117. {
  118. this.provider = provider;
  119. this.maxIterations = maxIterations;
  120. }
  121. private PKMacBuilder(AlgorithmIdentifier digestAlgorithmIdentifier, int iterationCount, AlgorithmIdentifier macAlgorithmIdentifier, IPKMacPrimitivesProvider provider)
  122. {
  123. this.iterationCount = iterationCount;
  124. this.mac = macAlgorithmIdentifier;
  125. this.owf = digestAlgorithmIdentifier;
  126. this.provider = provider;
  127. }
  128. /**
  129. * Set the salt length in octets.
  130. *
  131. * @param saltLength length in octets of the salt to be generated.
  132. * @return the generator
  133. */
  134. public PKMacBuilder SetSaltLength(int saltLength)
  135. {
  136. if (saltLength < 8)
  137. throw new ArgumentException("salt length must be at least 8 bytes");
  138. this.saltLength = saltLength;
  139. return this;
  140. }
  141. /// <summary>
  142. /// Set the iteration count.
  143. /// </summary>
  144. /// <param name="iterationCount">the iteration count.</param>
  145. /// <returns>this</returns>
  146. /// <exception cref="ArgumentException">if iteration count is less than 100</exception>
  147. public PKMacBuilder SetIterationCount(int iterationCount)
  148. {
  149. if (iterationCount < 100)
  150. throw new ArgumentException("iteration count must be at least 100");
  151. CheckIterationCountCeiling(iterationCount);
  152. this.iterationCount = iterationCount;
  153. return this;
  154. }
  155. /// <summary>
  156. /// Set PbmParameters
  157. /// </summary>
  158. /// <param name="parameters">The parameters.</param>
  159. /// <returns>this</returns>
  160. public PKMacBuilder SetParameters(PbmParameter parameters)
  161. {
  162. CheckIterationCountCeiling(parameters.IterationCount.IntValueExact);
  163. this.parameters = parameters;
  164. return this;
  165. }
  166. /// <summary>
  167. /// The Secure random
  168. /// </summary>
  169. /// <param name="random">The random.</param>
  170. /// <returns>this</returns>
  171. public PKMacBuilder SetSecureRandom(SecureRandom random)
  172. {
  173. this.random = random;
  174. return this;
  175. }
  176. /// <summary>
  177. /// Build an IMacFactory.
  178. /// </summary>
  179. /// <param name="password">The password.</param>
  180. /// <returns>IMacFactory</returns>
  181. public IMacFactory Build(char[] password)
  182. {
  183. if (parameters != null)
  184. return GenCalculator(parameters, password);
  185. byte[] salt = new byte[saltLength];
  186. if (random == null)
  187. {
  188. this.random = new SecureRandom();
  189. }
  190. random.NextBytes(salt);
  191. return GenCalculator(new PbmParameter(salt, owf, iterationCount, mac), password);
  192. }
  193. private void CheckIterationCountCeiling(int iterationCount)
  194. {
  195. if (maxIterations > 0 && iterationCount > maxIterations)
  196. throw new ArgumentException("iteration count exceeds limit (" + iterationCount + " > " + maxIterations + ")");
  197. }
  198. private IMacFactory GenCalculator(PbmParameter parameters, char[] password)
  199. {
  200. // From RFC 4211
  201. //
  202. // 1. Generate a random salt value S
  203. //
  204. // 2. Append the salt to the pw. K = pw || salt.
  205. //
  206. // 3. Hash the value of K. K = HASH(K)
  207. //
  208. // 4. Iter = Iter - 1. If Iter is greater than zero. Goto step 3.
  209. //
  210. // 5. Compute an HMAC as documented in [HMAC].
  211. //
  212. // MAC = HASH( K XOR opad, HASH( K XOR ipad, data) )
  213. //
  214. // Where opad and ipad are defined in [HMAC].
  215. byte[] pw = Strings.ToUtf8ByteArray(password);
  216. byte[] salt = parameters.Salt.GetOctets();
  217. byte[] K = new byte[pw.Length + salt.Length];
  218. Array.Copy(pw, 0, K, 0, pw.Length);
  219. Array.Copy(salt, 0, K, pw.Length, salt.Length);
  220. IDigest digest = provider.CreateDigest(parameters.Owf);
  221. int iter = parameters.IterationCount.IntValueExact;
  222. digest.BlockUpdate(K, 0, K.Length);
  223. K = new byte[digest.GetDigestSize()];
  224. digest.DoFinal(K, 0);
  225. while (--iter > 0)
  226. {
  227. digest.BlockUpdate(K, 0, K.Length);
  228. digest.DoFinal(K, 0);
  229. }
  230. byte[] key = K;
  231. return new PKMacFactory(key, parameters);
  232. }
  233. }
  234. }
  235. #pragma warning restore
  236. #endif