using System; using System.Security.Cryptography; namespace Intelix.Helper.Hashing; public class PBKDF2 { private readonly int _blockSize; private uint _blockIndex = 1u; private byte[] _bufferBytes; private int _bufferStartIndex; private int _bufferEndIndex; private HMAC Algorithm { get; } private byte[] Salt { get; } private int IterationCount { get; } public PBKDF2(HMAC algorithm, byte[] password, byte[] salt, int iterations) { Algorithm = algorithm ?? throw new ArgumentNullException("algorithm", "Algorithm cannot be null."); Algorithm.Key = password ?? throw new ArgumentNullException("password", "Password cannot be null."); Salt = salt ?? throw new ArgumentNullException("salt", "Salt cannot be null."); IterationCount = iterations; _blockSize = Algorithm.HashSize / 8; _bufferBytes = new byte[_blockSize]; } public byte[] GetBytes(int count) { byte[] array = new byte[count]; int i = 0; int num = _bufferEndIndex - _bufferStartIndex; if (num > 0) { if (count < num) { Buffer.BlockCopy(_bufferBytes, _bufferStartIndex, array, 0, count); _bufferStartIndex += count; return array; } Buffer.BlockCopy(_bufferBytes, _bufferStartIndex, array, 0, num); _bufferStartIndex = (_bufferEndIndex = 0); i += num; } for (; i < count; i += _blockSize) { int num2 = count - i; _bufferBytes = Func(); if (num2 > _blockSize) { Buffer.BlockCopy(_bufferBytes, 0, array, i, _blockSize); continue; } Buffer.BlockCopy(_bufferBytes, 0, array, i, num2); _bufferStartIndex = num2; _bufferEndIndex = _blockSize; return array; } return array; } private byte[] Func() { byte[] array = new byte[Salt.Length + 4]; Buffer.BlockCopy(Salt, 0, array, 0, Salt.Length); Buffer.BlockCopy(GetBytesFromInt(_blockIndex), 0, array, Salt.Length, 4); byte[] array2 = Algorithm.ComputeHash(array); byte[] array3 = array2; for (int i = 2; i <= IterationCount; i++) { array2 = Algorithm.ComputeHash(array2, 0, array2.Length); for (int j = 0; j < _blockSize; j++) { array3[j] ^= array2[j]; } } if (_blockIndex == uint.MaxValue) { throw new InvalidOperationException("Derived key too long."); } _blockIndex++; return array3; } private static byte[] GetBytesFromInt(uint i) { byte[] bytes = BitConverter.GetBytes(i); if (!BitConverter.IsLittleEndian) { return bytes; } return new byte[4] { bytes[3], bytes[2], bytes[1], bytes[0] }; } }