/// <summary> /// Derives a secret key of any size from a password and a salt. /// </summary> /// <param name="password">The password.</param> /// <param name="salt">The salt.</param> /// <param name="opsLimit">Represents a maximum amount of computations to perform.</param> /// <param name="memLimit">Is the maximum amount of RAM that the function will use, in bytes.</param> /// <param name="outputLength">The length of the computed output array.</param> /// <returns>Returns a byte array of the given size.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="SaltOutOfRangeException"></exception> /// <exception cref="OutOfMemoryException"></exception> public static byte[] ArgonHashBinary(byte[] password, byte[] salt, long opsLimit, int memLimit, long outputLength = ARGON_SALTBYTES) { if (password == null) { throw new ArgumentNullException("password", "Password cannot be null"); } if (salt == null) { throw new ArgumentNullException("salt", "Salt cannot be null"); } if (salt.Length != ARGON_SALTBYTES) { throw new SaltOutOfRangeException(string.Format("Salt must be {0} bytes in length.", ARGON_SALTBYTES)); } if (opsLimit < 2) { throw new ArgumentOutOfRangeException("opsLimit", "opsLimit the number of passes, has to be at least 3"); } if (memLimit <= 0) { throw new ArgumentOutOfRangeException("memLimit", "memLimit cannot be zero or negative"); } if (outputLength <= 0) { throw new ArgumentOutOfRangeException("outputLength", "OutputLength cannot be zero or negative"); } byte[] buffer = new byte[outputLength]; SodiumCore.Init(); int ret = SodiumLibrary.crypto_pwhash(buffer, buffer.Length, password, password.GetLongLength(0), salt, opsLimit, memLimit, ARGON_ALGORITHM_DEFAULT); if (ret != 0) { throw new OutOfMemoryException( "Internal error, hash failed (usually because the operating system refused to allocate the amount of requested memory)."); } return(buffer); }
/// <summary> /// Derives a secret key of any size from a password and a salt. /// </summary> /// <param name="password">The password.</param> /// <param name="salt">The salt.</param> /// <param name="opsLimit">Represents a maximum amount of computations to perform.</param> /// <param name="memLimit">Is the maximum amount of RAM that the function will use, in bytes.</param> /// <param name="outputLength">The length of the computed output array.</param> /// <param name="alg">Argon Algorithm</param> /// <returns>Returns a byte array of the given size.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="SaltOutOfRangeException"></exception> /// <exception cref="OutOfMemoryException"></exception> public static byte[] ArgonHashBinary(byte[] password, byte[] salt, long opsLimit, int memLimit, long outputLength = ARGON_SALTBYTES, ArgonAlgorithm alg = ArgonAlgorithm.Argon_2I13) { if (password == null) { throw new ArgumentNullException(nameof(password), "Password cannot be null"); } if (salt == null) { throw new ArgumentNullException(nameof(salt), "Salt cannot be null"); } if (salt.Length != ARGON_SALTBYTES) { throw new SaltOutOfRangeException($"Salt must be {ARGON_SALTBYTES} bytes in length."); } if (opsLimit < 3) { throw new ArgumentOutOfRangeException(nameof(opsLimit), "opsLimit the number of passes, has to be at least 3"); } if (memLimit <= 0) { throw new ArgumentOutOfRangeException(nameof(memLimit), "memLimit cannot be zero or negative"); } if (outputLength <= 0) { throw new ArgumentOutOfRangeException(nameof(outputLength), "OutputLength cannot be zero or negative"); } var buffer = new byte[outputLength]; SodiumCore.Init(); var ret = SodiumLibrary.crypto_pwhash(buffer, buffer.Length, password, password.Length, salt, opsLimit, memLimit, (int)alg); if (ret != 0) { throw new OutOfMemoryException("Internal error, hash failed (usually because the operating system refused to allocate the amount of requested memory)."); } return(buffer); }