fork(3) download
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4.  
  5. // https://g...content-available-to-author-only...b.com/dotnet/corefx/blob/29cb063b95661470340b6ba7e1381495c05bfff2/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs
  6. namespace My.System.Security.Cryptography
  7. {
  8. using global::System;
  9. using global::System.Text;
  10. using global::System.Diagnostics;
  11. using global::System.Security.Cryptography;
  12.  
  13. using global::My.Internal.Cryptography;
  14.  
  15. public class Rfc2898DeriveBytes : DeriveBytes
  16. {
  17. private const int MinimumSaltSize = 8;
  18.  
  19. private readonly byte[] _password;
  20. private byte[] _salt;
  21. private uint _iterations;
  22. private HMAC _hmac;
  23. private int _blockSize;
  24.  
  25. private byte[] _buffer;
  26. private uint _block;
  27. private int _startIndex;
  28. private int _endIndex;
  29.  
  30. public HashAlgorithmName HashAlgorithm { get; }
  31.  
  32. public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations)
  33. : this(password, salt, iterations, HashAlgorithmName.SHA1)
  34. {
  35. }
  36.  
  37. public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations, HashAlgorithmName hashAlgorithm)
  38. {
  39. if (salt == null)
  40. throw new ArgumentNullException(nameof(salt));
  41. if (salt.Length < MinimumSaltSize)
  42. throw new ArgumentException("SR.Cryptography_PasswordDerivedBytes_FewBytesSalt", nameof(salt));
  43. if (iterations <= 0)
  44. throw new ArgumentOutOfRangeException(nameof(iterations), "SR.ArgumentOutOfRange_NeedPosNum");
  45. if (password == null)
  46. throw new NullReferenceException(); // This "should" be ArgumentNullException but for compat, we throw NullReferenceException.
  47.  
  48. _salt = salt.CloneByteArray();
  49. _iterations = (uint)iterations;
  50. _password = password.CloneByteArray();
  51. HashAlgorithm = hashAlgorithm;
  52. _hmac = OpenHmac();
  53. // _blockSize is in bytes, HashSize is in bits.
  54. _blockSize = _hmac.HashSize >> 3;
  55.  
  56. Initialize();
  57. }
  58.  
  59. public Rfc2898DeriveBytes(string password, byte[] salt)
  60. : this(password, salt, 1000)
  61. {
  62. }
  63.  
  64. public Rfc2898DeriveBytes(string password, byte[] salt, int iterations)
  65. : this(password, salt, iterations, HashAlgorithmName.SHA1)
  66. {
  67. }
  68.  
  69. public Rfc2898DeriveBytes(string password, byte[] salt, int iterations, HashAlgorithmName hashAlgorithm)
  70. : this(Encoding.UTF8.GetBytes(password), salt, iterations, hashAlgorithm)
  71. {
  72. }
  73.  
  74. public Rfc2898DeriveBytes(string password, int saltSize)
  75. : this(password, saltSize, 1000)
  76. {
  77. }
  78.  
  79. public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
  80. : this(password, saltSize, iterations, HashAlgorithmName.SHA1)
  81. {
  82. }
  83.  
  84. public Rfc2898DeriveBytes(string password, int saltSize, int iterations, HashAlgorithmName hashAlgorithm)
  85. {
  86. if (saltSize < 0)
  87. throw new ArgumentOutOfRangeException(nameof(saltSize), "SR.ArgumentOutOfRange_NeedNonNegNum");
  88. if (saltSize < MinimumSaltSize)
  89. throw new ArgumentException("SR.Cryptography_PasswordDerivedBytes_FewBytesSalt", nameof(saltSize));
  90. if (iterations <= 0)
  91. throw new ArgumentOutOfRangeException(nameof(iterations), "SR.ArgumentOutOfRange_NeedPosNum");
  92.  
  93. _salt = Helpers.GenerateRandom(saltSize);
  94. _iterations = (uint)iterations;
  95. _password = Encoding.UTF8.GetBytes(password);
  96. HashAlgorithm = hashAlgorithm;
  97. _hmac = OpenHmac();
  98. // _blockSize is in bytes, HashSize is in bits.
  99. _blockSize = _hmac.HashSize >> 3;
  100.  
  101. Initialize();
  102. }
  103.  
  104. public int IterationCount
  105. {
  106. get
  107. {
  108. return (int)_iterations;
  109. }
  110.  
  111. set
  112. {
  113. if (value <= 0)
  114. throw new ArgumentOutOfRangeException(nameof(value), "SR.ArgumentOutOfRange_NeedPosNum");
  115. _iterations = (uint)value;
  116. Initialize();
  117. }
  118. }
  119.  
  120. public byte[] Salt
  121. {
  122. get
  123. {
  124. return _salt.CloneByteArray();
  125. }
  126.  
  127. set
  128. {
  129. if (value == null)
  130. throw new ArgumentNullException(nameof(value));
  131. if (value.Length < MinimumSaltSize)
  132. throw new ArgumentException("SR.Cryptography_PasswordDerivedBytes_FewBytesSalt");
  133. _salt = value.CloneByteArray();
  134. Initialize();
  135. }
  136. }
  137.  
  138. protected override void Dispose(bool disposing)
  139. {
  140. if (disposing)
  141. {
  142. if (_hmac != null)
  143. {
  144. _hmac.Dispose();
  145. _hmac = null;
  146. }
  147.  
  148. if (_buffer != null)
  149. Array.Clear(_buffer, 0, _buffer.Length);
  150. if (_password != null)
  151. Array.Clear(_password, 0, _password.Length);
  152. if (_salt != null)
  153. Array.Clear(_salt, 0, _salt.Length);
  154. }
  155. base.Dispose(disposing);
  156. }
  157.  
  158. public override byte[] GetBytes(int cb)
  159. {
  160. Debug.Assert(_blockSize > 0);
  161.  
  162. if (cb <= 0)
  163. throw new ArgumentOutOfRangeException(nameof(cb), "SR.ArgumentOutOfRange_NeedPosNum");
  164. byte[] password = new byte[cb];
  165.  
  166. int offset = 0;
  167. int size = _endIndex - _startIndex;
  168. if (size > 0)
  169. {
  170. if (cb >= size)
  171. {
  172. Buffer.BlockCopy(_buffer, _startIndex, password, 0, size);
  173. _startIndex = _endIndex = 0;
  174. offset += size;
  175. }
  176. else
  177. {
  178. Buffer.BlockCopy(_buffer, _startIndex, password, 0, cb);
  179. _startIndex += cb;
  180. return password;
  181. }
  182. }
  183.  
  184. Debug.Assert(_startIndex == 0 && _endIndex == 0, "Invalid start or end index in the internal buffer.");
  185.  
  186. while (offset < cb)
  187. {
  188. byte[] T_block = Func();
  189. int remainder = cb - offset;
  190. if (remainder > _blockSize)
  191. {
  192. Buffer.BlockCopy(T_block, 0, password, offset, _blockSize);
  193. offset += _blockSize;
  194. }
  195. else
  196. {
  197. Buffer.BlockCopy(T_block, 0, password, offset, remainder);
  198. offset += remainder;
  199. Buffer.BlockCopy(T_block, remainder, _buffer, _startIndex, _blockSize - remainder);
  200. _endIndex += (_blockSize - remainder);
  201. return password;
  202. }
  203. }
  204. return password;
  205. }
  206.  
  207. public byte[] CryptDeriveKey(string algname, string alghashname, int keySize, byte[] rgbIV)
  208. {
  209. // If this were to be implemented here, CAPI would need to be used (not CNG) because of
  210. // unfortunate differences between the two. Using CNG would break compatibility. Since this
  211. // assembly currently doesn't use CAPI it would require non-trivial additions.
  212. // In addition, if implemented here, only Windows would be supported as it is intended as
  213. // a thin wrapper over the corresponding native API.
  214. // Note that this method is implemented in PasswordDeriveBytes (in the Csp assembly) using CAPI.
  215. throw new PlatformNotSupportedException();
  216. }
  217.  
  218. public override void Reset()
  219. {
  220. Initialize();
  221. }
  222.  
  223. [global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "HMACSHA1 is needed for compat. (https://g...content-available-to-author-only...b.com/dotnet/corefx/issues/9438)")]
  224. private HMAC OpenHmac()
  225. {
  226. Debug.Assert(_password != null);
  227.  
  228. HashAlgorithmName hashAlgorithm = HashAlgorithm;
  229.  
  230. if (string.IsNullOrEmpty(hashAlgorithm.Name))
  231. throw new CryptographicException("SR.Cryptography_HashAlgorithmNameNullOrEmpty");
  232.  
  233. if (hashAlgorithm == HashAlgorithmName.SHA1)
  234. return new HMACSHA1(_password);
  235. if (hashAlgorithm == HashAlgorithmName.SHA256)
  236. return new HMACSHA256(_password);
  237. if (hashAlgorithm == HashAlgorithmName.SHA384)
  238. return new HMACSHA384(_password);
  239. if (hashAlgorithm == HashAlgorithmName.SHA512)
  240. return new HMACSHA512(_password);
  241.  
  242. throw new CryptographicException(string.Format("SR.Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name));
  243. }
  244.  
  245. private void Initialize()
  246. {
  247. if (_buffer != null)
  248. Array.Clear(_buffer, 0, _buffer.Length);
  249. _buffer = new byte[_blockSize];
  250. _block = 1;
  251. _startIndex = _endIndex = 0;
  252. }
  253.  
  254. // This function is defined as follows:
  255. // Func (S, i) = HMAC(S || i) | HMAC2(S || i) | ... | HMAC(iterations) (S || i)
  256. // where i is the block number.
  257. private byte[] Func()
  258. {
  259. byte[] temp = new byte[_salt.Length + sizeof(uint)];
  260. Buffer.BlockCopy(_salt, 0, temp, 0, _salt.Length);
  261. Helpers.WriteInt(_block, temp, _salt.Length);
  262.  
  263. temp = _hmac.ComputeHash(temp);
  264.  
  265. byte[] ret = temp;
  266. for (int i = 2; i <= _iterations; i++)
  267. {
  268. temp = _hmac.ComputeHash(temp);
  269.  
  270. for (int j = 0; j < _blockSize; j++)
  271. {
  272. ret[j] ^= temp[j];
  273. }
  274. }
  275.  
  276. // increment the block count.
  277. _block++;
  278. return ret;
  279. }
  280. }
  281. }
  282.  
  283. // https://g...content-available-to-author-only...b.com/dotnet/corefx/blob/45b724f6b6391910edea8a70f3f22a4a7996696d/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithmName.cs
  284. namespace My.System.Security.Cryptography
  285. {
  286. using global::System;
  287.  
  288. // Strongly typed string representing the name of a hash algorithm.
  289. // Open ended to allow extensibility while giving the discoverable feel of an enum for common values.
  290.  
  291. /// <summary>
  292. /// Specifies the name of a cryptographic hash algorithm.
  293. /// </summary>
  294. /// Asymmetric Algorithms implemented using Microsoft's CNG (Cryptography Next Generation) API
  295. /// will interpret the underlying string value as a CNG algorithm identifier:
  296. /// * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375534(v=vs.85).aspx
  297. ///
  298. /// As with CNG, the names are case-sensitive.
  299. ///
  300. /// Asymmetric Algorithms implemented using other technologies:
  301. /// * Must recognize at least "MD5", "SHA1", "SHA256", "SHA384", and "SHA512".
  302. /// * Should recognize additional CNG IDs for any other hash algorithms that they also support.
  303. /// </remarks>
  304. public struct HashAlgorithmName : IEquatable<HashAlgorithmName>
  305. {
  306. // Returning a new instance every time is free here since HashAlgorithmName is a struct with
  307. // a single string field. The optimized codegen should be equivalent to return "MD5".
  308.  
  309. /// <summary>
  310. /// Gets a <see cref="HashAlgorithmName" /> representing "MD5"
  311. /// </summary>
  312. public static HashAlgorithmName MD5 { get { return new HashAlgorithmName("MD5"); } }
  313.  
  314. /// <summary>
  315. /// Gets a <see cref="HashAlgorithmName" /> representing "SHA1"
  316. /// </summary>
  317. public static HashAlgorithmName SHA1 { get { return new HashAlgorithmName("SHA1"); } }
  318.  
  319. /// <summary>
  320. /// Gets a <see cref="HashAlgorithmName" /> representing "SHA256"
  321. /// </summary>
  322. public static HashAlgorithmName SHA256 { get { return new HashAlgorithmName("SHA256"); } }
  323.  
  324. /// <summary>
  325. /// Gets a <see cref="HashAlgorithmName" /> representing "SHA384"
  326. /// </summary>
  327. public static HashAlgorithmName SHA384 { get { return new HashAlgorithmName("SHA384"); } }
  328.  
  329. /// <summary>
  330. /// Gets a <see cref="HashAlgorithmName" /> representing "SHA512"
  331. /// </summary>
  332. public static HashAlgorithmName SHA512 { get { return new HashAlgorithmName("SHA512"); } }
  333.  
  334. private readonly string _name;
  335.  
  336. /// <summary>
  337. /// Gets a <see cref="HashAlgorithmName" /> representing a custom name.
  338. /// </summary>
  339. /// <param name="name">The custom hash algorithm name.</param>
  340. public HashAlgorithmName(string name)
  341. {
  342. // Note: No validation because we have to deal with default(HashAlgorithmName) regardless.
  343. _name = name;
  344. }
  345.  
  346. /// <summary>
  347. /// Gets the underlying string representation of the algorithm name.
  348. /// </summary>
  349. /// <remarks>
  350. /// May be null or empty to indicate that no hash algorithm is applicable.
  351. /// </remarks>
  352. public string Name
  353. {
  354. get { return _name; }
  355. }
  356.  
  357. public override string ToString()
  358. {
  359. return _name ?? String.Empty;
  360. }
  361.  
  362. public override bool Equals(object obj)
  363. {
  364. return obj is HashAlgorithmName && Equals((HashAlgorithmName)obj);
  365. }
  366.  
  367. public bool Equals(HashAlgorithmName other)
  368. {
  369. // NOTE: intentionally ordinal and case sensitive, matches CNG.
  370. return _name == other._name;
  371. }
  372.  
  373. public override int GetHashCode()
  374. {
  375. return _name == null ? 0 : _name.GetHashCode();
  376. }
  377.  
  378. public static bool operator ==(HashAlgorithmName left, HashAlgorithmName right)
  379. {
  380. return left.Equals(right);
  381. }
  382.  
  383. public static bool operator !=(HashAlgorithmName left, HashAlgorithmName right)
  384. {
  385. return !(left == right);
  386. }
  387. }
  388. }
  389.  
  390. // https://g...content-available-to-author-only...b.com/dotnet/corefx/blob/bffef76f6af208e2042a2f27bc081ee908bb390b/src/System.Security.Cryptography.Encoding/src/Internal/Cryptography/Helpers.cs
  391. // https://g...content-available-to-author-only...b.com/dotnet/corefx/blob/827f47f48df00923b802427486b062d62dd243b5/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/Helpers.cs
  392. namespace My.Internal.Cryptography
  393. {
  394. using global::System;
  395. using global::System.Diagnostics;
  396. using global::System.Security.Cryptography;
  397.  
  398. internal static class Helpers
  399. {
  400. public static byte[] CloneByteArray(this byte[] src)
  401. {
  402. if (src == null)
  403. {
  404. return null;
  405. }
  406.  
  407. return (byte[])(src.Clone());
  408. }
  409.  
  410. public static byte[] GenerateRandom(int count)
  411. {
  412. byte[] buffer = new byte[count];
  413. using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
  414. {
  415. rng.GetBytes(buffer);
  416. }
  417. return buffer;
  418. }
  419.  
  420. // encodes the integer i into a 4-byte array, in big endian.
  421. public static void WriteInt(uint i, byte[] arr, int offset)
  422. {
  423. unchecked
  424. {
  425. Debug.Assert(arr != null);
  426. Debug.Assert(arr.Length >= offset + sizeof(uint));
  427.  
  428. arr[offset] = (byte)(i >> 24);
  429. arr[offset + 1] = (byte)(i >> 16);
  430. arr[offset + 2] = (byte)(i >> 8);
  431. arr[offset + 3] = (byte)i;
  432. }
  433. }
  434. }
  435. }
  436.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty