/// <summary> /// Hash the given password to a Argon2 hash string. /// </summary> /// <param name="password"> /// The password to hash. Gets UTF-8 encoded before hashing. /// </param> /// <param name="timeCost"> /// The time cost to use. Defaults to 3. /// </param> /// <param name="memoryCost"> /// The memory cost to use. Defaults to 65536 (64K). /// </param> /// <param name="parallelism"> /// The parallelism to use. Default to 1 (single threaded). /// </param> /// <param name="type"> /// Data-dependent or data-independent. Defaults to data-independent /// (as recommended for password hashing). /// </param> /// <param name="hashLength"> /// The length of the hash in bytes. Note, the string returned base-64 /// encodes this with other parameters so the resulting string is /// significantly longer. /// </param> /// <returns> /// The Argon2 hash of the given password. /// </returns> public static string Hash( string password, int timeCost = 3, int memoryCost = 65536, int parallelism = 1, Argon2Type type = Argon2Type.DataIndependentAddressing, int hashLength = 32) { using (var passwordBuf = new SecureArray <byte>(Encoding.UTF8.GetByteCount(password))) { byte[] salt = new byte[16]; System.Security.Cryptography.RandomNumberGenerator.Create().GetBytes(salt); Encoding.UTF8.GetBytes(password, 0, password.Length, passwordBuf.Buffer, 0); var argon2 = new Argon2( new Argon2Config { TimeCost = timeCost, MemoryCost = memoryCost, Threads = parallelism, Lanes = parallelism, Password = passwordBuf.Buffer, Salt = salt, HashLength = hashLength, Version = Argon2Version.Nineteen }); using (var hash = argon2.Hash()) { return(argon2.config.EncodeString(hash.Buffer)); } } }
/// <summary> /// Verify the given Argon2 hash as being that of the given password. /// </summary> /// <param name="encoded"> /// The Argon2 hash string. This has the actual hash along with other parameters used in the hash. /// </param> /// <param name="password"> /// The password to verify /// </param> /// <returns> /// True on success; false otherwise. /// </returns> public static bool Verify( string encoded, byte[] password) { SecureArray <byte> hash = null; try { var configToVerify = new Argon2Config { Password = password }; if (!configToVerify.DecodeString(encoded, out hash) || hash == null) { return(false); } var hasherToVerify = new Argon2(configToVerify); var hashToVerify = hasherToVerify.Hash(); return(!hash.Buffer.Where((b, i) => b != hashToVerify[i]).Any()); } finally { hash?.Dispose(); } }
internal static void AddUser(string username, string password) { Argon2Config config = new Argon2Config { Type = Argon2Type.DataIndependentAddressing, Version = Argon2Version.Nineteen, TimeCost = 3, MemoryCost = 32768, Lanes = 4, Threads = Environment.ProcessorCount, Password = Encoding.ASCII.GetBytes(password), Salt = Convert.FromBase64String(Properties.Settings.Default.Salt), // >= 8 bytes if not null HashLength = 20 // >= 4 }; Argon2 argon2 = new Argon2(config); string passwordHash; using (SecureArray <byte> hashA = argon2.Hash()) { passwordHash = config.EncodeString(hashA.Buffer); } var userCreated = new user() { username = username, passwordHash = passwordHash, isAdmin = false, isEnabled = false }; context.users.Add(userCreated); context.SaveChanges(); }
/// <summary> /// Convert Securestring to an DpApi encrypted byte[] /// </summary> /// <param name="secureString"></param> /// <returns></returns> public static DpapiEncryptedByteArray ToEncryptedArray(this SecureString secureString) { IntPtr zero = IntPtr.Zero; if ((secureString == null) || (secureString.Length == 0)) { return(null); } try { // unicode so twice as big using (var secureArray = new SecureArray <byte>(secureString.Length)) { zero = Marshal.SecureStringToGlobalAllocAnsi(secureString); Marshal.Copy(zero, secureArray.Buffer, 0, secureString.Length); return(secureArray.ToSecureBytes()); } } finally { if (zero != IntPtr.Zero) { Marshal.ZeroFreeGlobalAllocAnsi(zero); } } }
/// <summary> /// Verify the given Argon2 hash as being that of the given password. /// </summary> /// <param name="encoded"> /// The Argon2 hash string. This has the actual hash along with other parameters used in the hash. /// </param> /// <param name="password"> /// The password to verify. This gets UTF-8 encoded. /// </param> /// <param name="secret"> /// The secret used in the creation of <paramref name="encoded"/>. UTF-8 encoded to create the byte-buffer actually used in the verification. /// May be null for no secret. <see cref="string"/>.<see cref="string.Empty"/> is treated as null. /// </param> /// <param name="secureArrayCall"> /// The methods that get called to secure arrays. A null value defaults to <see cref="SecureArray"/>.<see cref="SecureArray.DefaultCall"/>. /// </param> /// <returns> /// True on success; false otherwise. /// </returns> public static bool Verify( string encoded, string password, string secret, SecureArrayCall secureArrayCall = null) { var secretBuf = string.IsNullOrEmpty(secret) ? null : SecureArray <byte> .Best(Encoding.UTF8.GetByteCount(secret), secureArrayCall); try { if (secretBuf != null) { Encoding.UTF8.GetBytes(secret, 0, secret.Length, secretBuf.Buffer, 0); } using var passwordBuf = SecureArray <byte> .Best(Encoding.UTF8.GetByteCount(password), secureArrayCall); Encoding.UTF8.GetBytes(password, 0, password.Length, passwordBuf.Buffer, 0); return(Verify(encoded, passwordBuf.Buffer, secretBuf?.Buffer, secureArrayCall)); } finally { secretBuf?.Dispose(); } }
/// <summary> /// Convert a SecureArray<byte> to SecureString /// </summary> /// <param name="plainString"></param> /// <returns></returns> public static SecureString ToSecureString(this SecureArray <byte> plainString) { using (plainString) { return(ToSecureString(plainString.Buffer.Cast <char>().ToArray())); } }
/// <summary> /// Verify the given Argon2 hash as being that of the given password. /// </summary> /// <param name="encoded"> /// The Argon2 hash string. This has the actual hash along with other parameters used in the hash. /// </param> /// <param name="configToVerify"> /// The configuration that contains the values used to created <paramref name="encoded"/>. /// </param> /// <returns> /// True on success; false otherwise. /// </returns> public static bool Verify( string encoded, Argon2Config configToVerify) { SecureArray <byte> hash = null; try { if (!configToVerify.DecodeString(encoded, out hash) || hash == null) { return(false); } using (var hasherToVerify = new Argon2(configToVerify)) { using (var hashToVerify = hasherToVerify.Hash()) { return(!hash.Buffer.Where((b, i) => b != hashToVerify[i]).Any()); } } } finally { hash?.Dispose(); } }
public void TestArgon2RoundTrip() { var password = "******"; byte[] passwordBytes = Encoding.UTF8.GetBytes(password); byte[] salt = new byte[16]; Rng.GetBytes(salt); var config = new Argon2Config { Type = Argon2Type.DataIndependentAddressing, Version = Argon2Version.Nineteen, Password = passwordBytes, Salt = salt, TimeCost = 3, MemoryCost = 65536, Lanes = 4, Threads = 2, }; var argon2 = new Argon2(config); SecureArray <byte> hash = argon2.Hash(); var passwordHash = config.EncodeString(hash.Buffer); this.output.WriteLine($"Argon2 of {password} --> {passwordHash}"); Assert.True( Argon2.Verify(passwordHash, passwordBytes, SecureArray.DefaultCall), $"expected verify to work for {passwordHash} (Argon2 hash of {password}"); }
// Token: 0x06000075 RID: 117 RVA: 0x00004298 File Offset: 0x00002498 private void Resize(int newSize) { using (SecureArray <char> secureArray = this.buffer) { this.buffer = new SecureArray <char>(newSize); secureArray.ArrayValue.CopyTo(this.buffer.ArrayValue, 0); } }
/// <summary> /// Compares a hash, salt and plain password and sets IsValid /// </summary> public SecuredPassword(string plainPassword, byte[] hash, byte[] salt, HashStrategyKind hashStrategy) { _hash = hash; _salt = salt; SetHashStrategy(hashStrategy); byte[] newKey; switch (hashStrategy) { case HashStrategyKind.Pbkdf210001Iterations: var numberOfIterations = (int)_hashingParameter; if (numberOfIterations <= 10000) { throw new ArgumentException("Iterations must be greater than 10000"); } using (var deriveBytes = new Rfc2898DeriveBytes(plainPassword, salt, numberOfIterations, HashAlgorithmName.SHA256)) { newKey = deriveBytes.GetBytes(_saltSize); IsValid = newKey.SequenceEqual(hash); } break; case HashStrategyKind.Argon2WorkCost: SecureArray <byte> hashB = null; try { var passwordBytes = Encoding.ASCII.GetBytes(plainPassword); var configOfPasswordToVerify = new Argon2Config { Type = Argon2Type.DataIndependentAddressing, Version = Argon2Version.Nineteen, TimeCost = 10, MemoryCost = (int)_hashingParameter, Lanes = 5, Threads = Environment.ProcessorCount, Salt = _salt, Password = passwordBytes, HashLength = 20 }; var hashString = Encoding.ASCII.GetString(_hash); if (configOfPasswordToVerify.DecodeString(hashString, out hashB) && hashB != null) { var argon2ToVerify = new Argon2(configOfPasswordToVerify); using (var hashToVerify = argon2ToVerify.Hash()) { if (!hashB.Buffer.Where((b, i) => b != hashToVerify[i]).Any()) { IsValid = true; } } } } finally { hashB?.Dispose(); } break; } }
private void CreateInputHtmlCollection(SecureNameValueCollection collection, SecureHttpBuffer buffer, Uri redirectUrl, int majorCasVersion) { foreach (string text in collection) { buffer.CopyAtCurrentPosition("<input type='hidden' name='"); buffer.CopyAtCurrentPosition(text); buffer.CopyAtCurrentPosition("' value='"); if (text == "password") { SecureString securePassword; collection.TryGetSecureValue(text, out securePassword); using (SecureArray <char> secureArray = securePassword.TransformToSecureCharArray(new CharTransformDelegate(FbaFormPostProxyRequestHandler.EncodeForSingleQuotedAttribute))) { buffer.CopyAtCurrentPosition(secureArray); goto IL_14B; } goto IL_72; } goto IL_72; IL_14B: buffer.CopyAtCurrentPosition("'>"); continue; IL_72: string text2; if (!(text == "destination")) { collection.TryGetUnsecureValue(text, out text2); buffer.CopyAtCurrentPosition(EncodingUtilities.HtmlEncode(text2)); goto IL_14B; } collection.TryGetUnsecureValue(text, out text2); Uri uri; if (!Uri.TryCreate(text2, UriKind.Absolute, out uri)) { throw new HttpException(400, "destination value is not valid"); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(redirectUrl.Scheme); stringBuilder.Append(Uri.SchemeDelimiter); stringBuilder.Append(redirectUrl.Authority); if (FbaFormPostProxyRequestHandler.IsOwaUrl(uri, OwaUrl.AuthPost, true)) { stringBuilder.Append(OwaUrl.ApplicationRoot.ImplicitUrl); } else if (string.IsNullOrEmpty(this.explicitLogonUser)) { stringBuilder.Append(redirectUrl.PathAndQuery); } else { stringBuilder.Append(uri.PathAndQuery); } buffer.CopyAtCurrentPosition(stringBuilder.ToString()); goto IL_14B; } }
/// <summary> /// Verify the given Argon2 hash as being that of the given password. /// </summary> /// <param name="encoded"> /// The Argon2 hash string. This has the actual hash along with other parameters used in the hash. /// </param> /// <param name="password"> /// The password to verify. This gets UTF-8 encoded. /// </param> /// <returns> /// True on success; false otherwise. /// </returns> public static bool Verify( string encoded, string password) { using (var passwordBuf = new SecureArray <byte>(Encoding.UTF8.GetByteCount(password))) { Encoding.UTF8.GetBytes(password, 0, password.Length, passwordBuf.Buffer, 0); return(Verify(encoded, passwordBuf.Buffer)); } }
public static DpapiEncryptedByteArray ToSecureBytes(this SecureArray <byte> secureArray) { if (secureArray == null) { throw new ArgumentNullException(nameof(secureArray)); } // constructor clears array on creation return(new DpapiEncryptedByteArray(secureArray)); }
// Token: 0x06000070 RID: 112 RVA: 0x00004168 File Offset: 0x00002368 public void CopyAtCurrentPosition(SecureArray <char> secureArray) { base.CheckDisposed(); if (secureArray == null) { throw new ArgumentNullException("secureArray"); } this.AdjustSizeAtCurrentPosition(secureArray.ArrayValue.Length); secureArray.ArrayValue.CopyTo(this.buffer.ArrayValue, this.currentPosition); this.currentPosition += secureArray.ArrayValue.Length; }
// Token: 0x0600006F RID: 111 RVA: 0x0000411C File Offset: 0x0000231C public void CopyAtCurrentPosition(SecureString secureValue) { base.CheckDisposed(); if (secureValue == null) { throw new ArgumentNullException("secureValue"); } using (SecureArray <char> secureArray = SecureStringExtensions.ConvertToSecureCharArray(secureValue)) { this.CopyAtCurrentPosition(secureArray); } }
private bool disposedValue = false; // To detect redundant calls private void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { SecureArray.Zero(_protecteBytes); } disposedValue = true; } }
private void Initialize() { using var blockHash = SecureArray <byte> .Best(PrehashSeedLength, this.config.SecureArrayCall); using (var initialHash = this.InitialHash()) { Array.Copy(initialHash.Buffer, blockHash.Buffer, PrehashDigestLength); } InitialKat(blockHash.Buffer, this); this.FillFirstBlocks(blockHash.Buffer); }
public KeyPair(byte[] publicKey, byte[] privateKey) { if (privateKey.Length % 16 != 0) { throw new ArgumentOutOfRangeException("Private Key length must be a multiple of 16 bytes."); } _publicKey = publicKey; _privateKey = new SecureArray <byte>(32, SecureArrayType.ZeroedPinnedAndNoSwap); Array.Copy(privateKey, _privateKey.Buffer, privateKey.Length); Array.Clear(privateKey, 0, 32); }
public static SecureArray <char> TransformToSecureCharArray(this SecureString securePassword, CharTransformDelegate transform) { if (securePassword == null) { throw new ArgumentNullException("securePassword"); } if (transform == null) { throw new ArgumentNullException("transform"); } SecureArray <char> secureArray = null; using (DisposeGuard disposeGuard = default(DisposeGuard)) { secureArray = securePassword.ConvertToSecureCharArray(); disposeGuard.Add <SecureArray <char> >(secureArray); int num = 0; bool flag = false; foreach (char c in secureArray.ArrayValue) { char[] array = transform(c); num += ((array == null) ? 1 : array.Length); flag |= (array != null); } if (flag) { using (SecureArray <char> secureArray2 = secureArray) { secureArray = new SecureArray <char>(num); disposeGuard.Add <SecureArray <char> >(secureArray); int num2 = 0; foreach (char c2 in secureArray2.ArrayValue) { char[] array2 = transform(c2); if (array2 == null) { secureArray.ArrayValue[num2] = c2; num2++; } else { array2.CopyTo(secureArray.ArrayValue, num2); num2 += array2.Length; } } } } disposeGuard.Success(); } return(secureArray); }
public static string Argon2Hash(string data) { Argon2Config config = DataHasher.Argon2Config; config.Password = Encoding.UTF8.GetBytes(data); byte[] salt = new byte[18]; RNG.GetBytes(salt); config.Salt = Encoding.UTF8.GetBytes(System.Convert.ToBase64String(salt)); using Argon2 argon2 = new Argon2(DataHasher.Argon2Config); using SecureArray <byte> hash = argon2.Hash(); return(DataHasher.Argon2Config.EncodeString(hash.Buffer)); }
/// <summary> /// Test <see cref="Argon2"/>. /// </summary> /// <returns> /// The result text. /// </returns> public static string TestArgon2RoundTrip() { var password = "******"; byte[] passwordBytes = Encoding.UTF8.GetBytes(password); byte[] salt = new byte[16]; Rng.GetBytes(salt); var secret = "secret1"; byte[] secretBytes = Encoding.UTF8.GetBytes(secret); var failedResults = new List <string>(); var passedResults = new List <string>(); foreach (var argon2Type in new[] { Argon2Type.DataIndependentAddressing, Argon2Type.DataDependentAddressing, Argon2Type.HybridAddressing }) { var argon2Name = argon2Type == Argon2Type.DataIndependentAddressing ? "Argon2i" : argon2Type == Argon2Type.DataDependentAddressing ? "Argon2d" : "Argon2id"; var config = new Argon2Config { Type = argon2Type, Version = Argon2Version.Nineteen, Password = passwordBytes, Salt = salt, Secret = secretBytes, TimeCost = 3, MemoryCost = 65536, Lanes = 4, Threads = 2, }; var argon2 = new Argon2(config); SecureArray <byte> hash = argon2.Hash(); var passwordHash = config.EncodeString(hash.Buffer); Console.WriteLine($"{argon2Name} of {password} --> {passwordHash}"); if (Argon2.Verify(passwordHash, passwordBytes, secretBytes, SecureArray.DefaultCall)) { passedResults.Add(argon2Name); Console.WriteLine($"Round Trip {argon2Name} Passed"); } else { failedResults.Add(argon2Name); Console.WriteLine($"Round Trip {argon2Name} FAILED"); Console.WriteLine($" expected verify to work for {passwordHash} (Argon2 hash of {password})"); } } return(failedResults.Any() ? $"RoundTrip FAILED: [{string.Join(", ", failedResults)}] (passed: [{string.Join(", ", passedResults)}])" : "RoundTrip Passed"); }
private void FillFirstBlocks(byte[] blockHash) { using var blockHashBytes = SecureArray <byte> .Best(BlockSize, this.config.SecureArrayCall); for (int l = 0; l < this.config.Lanes; ++l) { Store32(blockHash, PrehashDigestLength, 0); Store32(blockHash, PrehashDigestLength + 4, l); Blake2BLong(blockHashBytes.Buffer, blockHash, this.config.SecureArrayCall); LoadBlock(this.Memory[l * this.LaneLength], blockHashBytes.Buffer); Store32(blockHash, PrehashDigestLength, 1); Blake2BLong(blockHashBytes.Buffer, blockHash, this.config.SecureArrayCall); LoadBlock(this.Memory[(l * this.LaneLength) + 1], blockHashBytes.Buffer); } }
/// <summary> /// Given a plain password and a hash strategy, calculate the salt and hash /// </summary> public SecuredPassword(string plainPassword, HashStrategyKind hashStrategy) { if (string.IsNullOrWhiteSpace(plainPassword)) { throw new ArgumentNullException(plainPassword); } SetHashStrategy(hashStrategy); switch (hashStrategy) { case HashStrategyKind.Pbkdf210001Iterations: var numberOfIterations = (int)_hashingParameter; if (numberOfIterations <= 10000) { throw new ArgumentException("Iterations must be greater than 10000"); } using (var deriveBytes = new Rfc2898DeriveBytes(plainPassword, _saltSize, numberOfIterations, HashAlgorithmName.SHA256)) { _salt = deriveBytes.Salt; _hash = deriveBytes.GetBytes(_saltSize); } break; case HashStrategyKind.Argon2WorkCost: byte[] passwordBytes = Encoding.UTF8.GetBytes(plainPassword); _salt = new byte[_saltSize]; RandomNumberGenerator.GetBytes(_salt); var config = new Argon2Config { Type = Argon2Type.DataIndependentAddressing, Version = Argon2Version.Nineteen, TimeCost = 10, MemoryCost = (int)_hashingParameter, Lanes = 5, Threads = Environment.ProcessorCount, Password = passwordBytes, Salt = _salt, HashLength = 20 }; var argon2A = new Argon2(config); using (SecureArray <byte> hashArgon = argon2A.Hash()) { _hash = Encoding.ASCII.GetBytes(config.EncodeString(hashArgon.Buffer)); } break; } IsValid = true; }
public void TestArgon2() { foreach (var testVector in Argon2TestVectors) { var encoded = new StringBuilder(); uint tagLength = (uint)testVector.TagLength; try { var config = new Argon2Config { Type = testVector.Type, Version = testVector.Version, TimeCost = testVector.Iterations, MemoryCost = testVector.MemoryKBytes, Lanes = testVector.Parallelism, Threads = testVector.Parallelism, Password = testVector.Password, Salt = testVector.Salt, Secret = testVector.Secret, AssociatedData = testVector.AssociatedData, HashLength = testVector.TagLength }; var argon2 = new Argon2(config); SecureArray <byte> hash = argon2.Hash(); Assert.False( hash.Buffer.Where((b, i) => b != testVector.Tag[i]).Any(), $"Test {testVector.Name}: Got{Environment.NewLine}{BitConverter.ToString(hash.Buffer)}{Environment.NewLine}expected{Environment.NewLine}{BitConverter.ToString(testVector.Tag)}"); this.output.WriteLine( "Passed Argon2:\r\n" + $" Version 0x{(int)testVector.Version:X} ({(int)testVector.Version})\r\n" + $" Type {testVector.Type}\r\n" + $" Iterations {testVector.Iterations}\r\n" + $" Memory KBytes {testVector.MemoryKBytes}\r\n" + $" Parallelism {testVector.Parallelism}\r\n" + $" Password {BitConverter.ToString(testVector.Password)}\r\n" + $" Salt {BitConverter.ToString(testVector.Salt)}\r\n" + $" Secret {BitConverter.ToString(testVector.Secret)}\r\n" + $" AssciatedData {BitConverter.ToString(testVector.AssociatedData)}\r\n" + $" Gave expected hash {BitConverter.ToString(hash.Buffer)}\r\n" + $" encoded {encoded}"); } catch (Exception e) { Assert.False(true, e.Message); } } }
/// <summary> /// Initializes a new instance of the <see cref="Blake2BCore"/> class. /// </summary> /// <param name="secureArrayCall"> /// The methods that get called to secure arrays. A null value defaults to <see cref="SecureArray"/>.<see cref="SecureArray.DefaultCall"/>. /// </param> /// <param name="lockMemory"> /// Used to set locking strategy for buffers used in creating the hash. The memory /// will always be zeroed prior to destruction. The memory is also always pinned /// so the CLR can't move it and leave extraneous copies floating around in RAM. /// </param> public Blake2BCore(SecureArrayCall secureArrayCall, LockMemoryPolicy lockMemory = LockMemoryPolicy.BestEffort) { switch (lockMemory) { case LockMemoryPolicy.None: this.buf = new SecureArray <byte>(128, SecureArrayType.ZeroedAndPinned, secureArrayCall); this.mbuf = new SecureArray <ulong>(16, SecureArrayType.ZeroedAndPinned, secureArrayCall); this.hbuf = new SecureArray <ulong>(8, SecureArrayType.ZeroedAndPinned, secureArrayCall); break; case LockMemoryPolicy.BestEffort: try { this.buf = new SecureArray <byte>(128, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall); } catch (LockFailException) { this.buf = new SecureArray <byte>(128, SecureArrayType.ZeroedAndPinned, secureArrayCall); } try { this.mbuf = new SecureArray <ulong>(16, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall); } catch (LockFailException) { this.mbuf = new SecureArray <ulong>(16, SecureArrayType.ZeroedAndPinned, secureArrayCall); } try { this.hbuf = new SecureArray <ulong>(8, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall); } catch (LockFailException) { this.hbuf = new SecureArray <ulong>(8, SecureArrayType.ZeroedAndPinned, secureArrayCall); } break; default: this.buf = new SecureArray <byte>(128, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall); this.mbuf = new SecureArray <ulong>(16, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall); this.hbuf = new SecureArray <ulong>(8, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall); break; } }
/// <summary> /// Does a Blake2 hash with the ability to truncate or extend the hash to any length. /// </summary> /// <param name="hash"> /// The buffer to fill with the hash. /// </param> /// <param name="inputBuffer"> /// What to hash. /// </param> /// <param name="secureArrayCall"> /// The methods that get called to secure arrays. A null value defaults to <see cref="SecureArray"/>.<see cref="SecureArray.DefaultCall"/>. /// </param> private static void Blake2BLong(byte[] hash, byte[] inputBuffer, SecureArrayCall secureArrayCall) { var outputLengthBytes = new byte[4]; using var intermediateHash = SecureArray <byte> .Best(Blake2B.OutputLength, secureArrayCall); var config = new Blake2BConfig { Result64ByteBuffer = intermediateHash.Buffer, OutputSizeInBytes = hash.Length > 64 ? 64 : hash.Length, }; Store32(outputLengthBytes, hash.Length); using (var blakeHash = Blake2B.Create(config, secureArrayCall)) { blakeHash.Update(outputLengthBytes); blakeHash.Update(inputBuffer); blakeHash.Finish(); } if (hash.Length <= intermediateHash.Buffer.Length) { Array.Copy(intermediateHash.Buffer, hash, hash.Length); return; } const int b2B2 = Blake2B.OutputLength / 2; Array.Copy(intermediateHash.Buffer, hash, b2B2); int pos = b2B2; int lastHashIndex = hash.Length - Blake2B.OutputLength; var toHash = new byte[Blake2B.OutputLength]; while (pos < lastHashIndex) { Array.Copy(intermediateHash.Buffer, toHash, intermediateHash.Buffer.Length); Blake2B.ComputeHash(toHash, config, secureArrayCall); Array.Copy(intermediateHash.Buffer, 0, hash, pos, b2B2); pos += b2B2; } Array.Copy(intermediateHash.Buffer, toHash, intermediateHash.Buffer.Length); Blake2B.ComputeHash(toHash, config, secureArrayCall); Array.Copy(intermediateHash.Buffer, 0, hash, pos, hash.Length - pos); }
/// <summary> /// Initializes a new instance of the <see cref="Argon2"/> class. /// </summary> /// <param name="config"> /// The configuration to use. /// </param> public Argon2(Argon2Config config) { this.config = config; uint memoryBlocks = (uint)config.MemoryCost; if (memoryBlocks < 2 * SyncPoints * config.Lanes) { memoryBlocks = 2 * SyncPoints * (uint)config.Lanes; } this.SegmentLength = (int)(memoryBlocks / (config.Lanes * SyncPoints)); // ensure that all segments have equal length this.LaneLength = this.SegmentLength * SyncPoints; this.MemoryBlockCount = this.LaneLength * this.config.Lanes; this.memory = BestSecureArray <ulong>(BlockSize * this.MemoryBlockCount / 8); this.Memory = new Blocks(this.memory.Buffer, this.MemoryBlockCount); }
public Blake2BHasher(Blake2BConfig config) { if (config == null) { config = DefaultConfig; } this.core = new Blake2BCore(config.LockMemoryPolicy); this.rawConfig = Blake2IvBuilder.ConfigB(config, null); if (config.Key != null && config.Key.Length != 0) { this.key = new SecureArray <byte>(128); Array.Copy(config.Key, this.key.Buffer, config.Key.Length); } this.outputSizeInBytes = config.OutputSizeInBytes; this.defaultOutputBuffer = config.Result64ByteBuffer; this.Init(); }
/// <summary> /// Convert array to a secure array /// will zero array passed in using RtlZeroMemory /// </summary> /// <typeparam name="T"></typeparam> /// <param name="array"></param> /// <returns></returns> public static SecureArray <T> ToSecureArray <T>(this T[] array) where T : struct { if (array == null) { throw new ArgumentNullException(nameof(array)); } try { var secure = new SecureArray <T>(array.Length); Buffer.BlockCopy(array, 0, secure.Buffer, 0, array.Length); return(secure); } finally { SecureArray.Zero(array); } }
public string HashPassword(string password) { if (string.IsNullOrEmpty(password)) { throw new ArgumentNullException(password); } byte[] salt = new byte[32]; Argon2Config argon2Config = _argon2Config; argon2Config.Password = Encoding.UTF8.GetBytes(password); argon2Config.Salt = salt; _randomNumberGenerator.GetBytes(salt); var argon2 = new Argon2(argon2Config); using SecureArray <byte> secureArray = argon2.Hash(); argon2.Dispose(); return(argon2Config.EncodeString(secureArray.Buffer)); }