public Argon2Parameters(Argon2Type type, byte[] salt, byte[] secret, byte[] additional, int iterations, int memory, int lanes, Argon2Version version) { if (salt == null) { throw new ArgumentNullException(nameof(salt)); } if (secret == null) { throw new ArgumentNullException(nameof(secret)); } if (additional == null) { throw new ArgumentNullException(nameof(additional)); } _salt = ArrayUtils.Clone(salt); _secret = ArrayUtils.Clone(secret); _additional = ArrayUtils.Clone(additional); Iterations = iterations; Memory = memory; Lanes = lanes; Type = type; Version = version; }
/// <summary> /// Initializes a new instance of the <see cref="Argon2TestVector"/> class. /// </summary> /// <param name="name"> /// name of the vector /// </param> /// <param name="type"> /// Data-driven or independent. /// </param> /// <param name="version"> /// The Argon2 version. /// </param> /// <param name="iterations"> /// The number of iterations. /// </param> /// <param name="memoryKBytes"> /// The memory to use. /// </param> /// <param name="parallelism"> /// The number of threads to use. /// </param> /// <param name="tagLength"> /// How many bytes to output. /// </param> /// <param name="password"> /// The password to hash. /// </param> /// <param name="salt"> /// The salt to use in the hash. Minimum of 8 bytes. 16 recommended. /// </param> /// <param name="secret"> /// The secret to use in the hash. /// </param> /// <param name="associatedData"> /// The associated data to use in the hash (like a salt but can be shorter). /// </param> /// <param name="tag"> /// The expected hash created from the above parameters. /// </param> public Argon2TestVector( string name, Argon2Type type, Argon2Version version, int iterations, int memoryKBytes, int parallelism, int tagLength, string password, string salt, string secret, string associatedData, string tag) { this.Name = name; this.Type = type; this.Version = version; this.Iterations = iterations; this.MemoryKBytes = memoryKBytes; this.Parallelism = parallelism; this.TagLength = tagLength; this.Password = ToBytes(password); this.Salt = ToBytes(salt); this.Secret = ToBytes(secret); this.AssociatedData = ToBytes(associatedData); this.Tag = ToBytes(tag); }
/// <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> /// 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="secret"> /// The secret to use in creating the hash. UTF-8 encoded before hashing. May be null. A /// <see cref="string"/>.<see cref="string.Empty"/> is treated the same as null. /// </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, data-independent, or hybrid. Defaults to hybrid /// (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> /// <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> /// The Argon2 hash of the given password. /// </returns> public static string Hash( byte[] password, byte[] secret, int timeCost = 3, int memoryCost = 65536, int parallelism = 1, Argon2Type type = Argon2Type.HybridAddressing, int hashLength = 32, SecureArrayCall secureArrayCall = null) { byte[] salt = new byte[16]; RandomNumberGenerator.Create().GetBytes(salt); return(Hash( new Argon2Config { TimeCost = timeCost, MemoryCost = memoryCost, Threads = parallelism, Lanes = parallelism, Password = password, Secret = secret, Salt = salt, HashLength = hashLength, Version = Argon2Version.Nineteen, Type = type, })); }
public Argon2Hasher(int hashLength = 32, Argon2Type argonType = Argon2Type.Argon2I, uint iterations = 10, uint costMemKb = 131072, uint parallelism = 1) { _iterations = iterations; _costMemKb = costMemKb; _parallelism = parallelism; _argonType = argonType; _hashLength = hashLength; }
} // end cctr protected Argon2ParametersBuilder(Argon2Type a_Type) { Lanes = DEFAULT_LANES; Memory = 1 << DEFAULT_MEMORY_COST; Iterations = DEFAULT_ITERATIONS; Type = a_Type; Version = DEFAULT_VERSION; } //
public Argon2Kdf(Argon2Type t) { if ((t != Argon2Type.D) && (t != Argon2Type.ID)) { throw new NotSupportedException(); } m_t = t; }
/// <summary> /// Initialize the Argon2 PasswordHasher with the performance and algorithm settings to use while hashing /// <param name="timeCost">How many iterations of the Argon2 hash to perform (default: 3, must be at least 1)</param> /// <param name="memoryCost">How much memory to use while hashing in kibibytes (KiB) (default: 8192 KiB [8 MiB], must be at least 8 KiB)</param> /// <param name="parallelism">How many threads to use while hashing (default: 1, must be at least 1)</param> /// <param name="argonType">The type of Argon2 hashing algorithm to use (Independent [default] or Dependent)</param> /// <param name="hashLength">The length of the resulting hash in bytes (default: 32)</param> /// </summary> public PasswordHasher(uint timeCost = 3, uint memoryCost = 8192, uint parallelism = 1, Argon2Type argonType = Argon2Type.Argon2i, uint hashLength = 32) { TimeCost = timeCost; MemoryCost = memoryCost; Parallelism = parallelism; ArgonType = argonType; HashLength = hashLength; StringEncoding = Encoding.UTF8; }
/// <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, data-independent, or hybrid. Defaults to hybrid /// (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> /// <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> /// 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.HybridAddressing, int hashLength = 32, SecureArrayCall secureArrayCall = null) { return(Hash(password, null, timeCost, memoryCost, parallelism, type, hashLength, secureArrayCall)); }
private Argon2ParametersBuilder() { _salt = new byte[0]; _secret = new byte[0]; _additional = new byte[0]; _type = DEFAULT_TYPE; _version = DEFAULT_VERSION; _iterations = DEFAULT_ITERATIONS; _memory = 1 << DEFAULT_MEMORY_COST; _lanes = DEFAULT_LANES; }
protected Argon2ParametersBuilder(Argon2Type a_Type, byte[] a_Salt, byte[] a_Secret, byte[] a_Additional, Int32 a_Iterations, Int32 a_Memory, Int32 a_Lanes, Argon2Version a_Version) { Salt = a_Salt.DeepCopy(); Secret = a_Secret.DeepCopy(); Additional = a_Additional.DeepCopy(); Iterations = a_Iterations; Memory = a_Memory; Lanes = a_Lanes; Type = a_Type; Version = a_Version; } // end cctr
/// <summary> /// Initializes a new instance of the <see cref="Argon2HashAlgorithm"/> class with the specified parameters. /// </summary> /// <param name="type">The Argon2 algorithm type to use.</param> /// <param name="version">The Argon2 version to use.</param> /// <param name="parallelism">The number of lanes to use while processing the hash.</param> /// <param name="memorySize">The amount of memory (in MB) to use while processing the hash.</param> /// <param name="hashLength">The size of the output hash (in bytes). 16 bytes is recommended for password hashing.</param> public Argon2HashAlgorithm(Argon2Type type, Argon2Version version, int parallelism, int memorySize, int hashLength = 16) : base($"{type}V{(int)version}-{hashLength * 8}-{parallelism}P-{memorySize}MB") { // Inputs: // password (P): Bytes (0..2^32-1) Password (or message) to be hashed // salt (S): Bytes (8..2^32-1) Salt (16 bytes recommended for password hashing) // parallelism (p): Number (1..2^24-1) Degree of parallelism (i.e. number of threads) // tagLength (T): Number (4..2^32-1) Desired number of returned bytes // memorySizeKB (m): Number (8p..2^32-1) Amount of memory (in kibibytes) to use // iterations (t): Number (1..2^32-1) Number of iterations to perform // version (v): Number (0x13) The current version is 0x13 (19 decimal) // key (K): Bytes (0..2^32-1) Optional key (Errata: PDF says 0..32 bytes, RFC says 0..232 bytes) // associatedData (X): Bytes (0..2^32-1) Optional arbitrary extra data // hashType (y): Number (0=Argon2d, 1=Argon2i, 2=Argon2id) // Output: // tag: Bytes (tagLength) The resulting generated bytes, tagLength bytes long if (!Enum.IsDefined(typeof(Argon2Type), type)) { throw new ArgumentOutOfRangeException(nameof(type)); } if (!Enum.IsDefined(typeof(Argon2Version), version)) { throw new ArgumentOutOfRangeException(nameof(version)); } if (parallelism < 1) { throw new ArgumentOutOfRangeException(nameof(parallelism)); } if (memorySize * 1024 < parallelism * 8 || memorySize > 4194303) { throw new ArgumentOutOfRangeException(nameof(memorySize)); } if (hashLength < 4) { throw new ArgumentOutOfRangeException(nameof(hashLength)); } Parallelism = parallelism; MemorySize = memorySize; HashLength = hashLength; }
public Argon2PasswordHasher( uint time = 3, uint memory = 8192, uint parallel = 1, Argon2Type type = Argon2Type.Argon2i, uint hashLength = 32, uint saltLength = 16, Encoding encoding = null, RandomNumberGenerator rng = null ) { TimeCost = time; MemoryCost = memory; Parallelism = parallel; ArgonType = type; HashLength = hashLength; SaltLength = saltLength; StringEncoding = encoding ?? Encoding.UTF8; Rng = rng ?? RandomNumberGenerator.Create(); }
/// <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="secret"> /// The secret to use in creating the hash. UTF-8 encoded before hashing. May be null. A /// <see cref="string"/>.<see cref="string.Empty"/> is treated the same as null. /// </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, data-independent, or hybrid. Defaults to hybrid /// (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> /// <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> /// The Argon2 hash of the given password. /// </returns> public static string Hash( string password, string secret, int timeCost = 3, int memoryCost = 65536, int parallelism = 1, Argon2Type type = Argon2Type.HybridAddressing, int hashLength = 32, 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(Hash( passwordBuf.Buffer, secretBuf?.Buffer, timeCost, memoryCost, parallelism, type, hashLength, secureArrayCall)); } } finally { secretBuf?.Dispose(); } }
static void Main(string[] args) { uint m_cost = (uint)(1 << LOG_M_COST_DEF); uint t_cost = T_COST_DEF; uint threads = THREADS_DEF; uint hash_len = HASH_LEN_DEF; Argon2Type type = Argon2Type.Argon2i; bool rawOnly = false; bool encodedOnly = false; if (args.Length == 0) { Usage(); Environment.Exit(30); } var pwd = Console.In.ReadToEnd(); if (pwd.EndsWith("\r\n")) { pwd = pwd.Substring(0, pwd.Length - 2); } else if (pwd.EndsWith("\n")) { pwd = pwd.Substring(0, pwd.Length - 1); } if (args[0].Length > SALT_LEN) { Fatal("salt too long"); } var salt = args[0] + new string('\0', SALT_LEN - args[0].Length); for (var i = 1; i < args.Length; i++) { switch (args[i]) { case "-m": m_cost = (1U << (int)ReadArg(args, ++i, "-m", 1, 32)); break; case "-t": t_cost = ReadArg(args, ++i, "-t", 1, int.MaxValue); break; case "-p": threads = ReadArg(args, ++i, "-p", 1, 0xFFFFFF); break; case "-h": hash_len = ReadArg(args, ++i, "-h", 4, int.MaxValue); break; case "-d": type = Argon2Type.Argon2d; break; case "-e": case "-encoded": encodedOnly = true; break; case "-r": case "-raw": rawOnly = true; break; default: Fatal("unknown argument " + args[i]); break; } } if (encodedOnly && rawOnly) { Fatal("Only one of -e or -r may be specified"); } if (!encodedOnly && !rawOnly) { Console.WriteLine("Type:\t\t{0}", type); Console.WriteLine("Iterations:\t{0}", t_cost); Console.WriteLine("Memory:\t\t{0} KiB", m_cost); Console.WriteLine("Parallelism:\t{0}", threads); } var hasher = new PasswordHasher(t_cost, m_cost, threads, type, hash_len); Run(hasher, pwd, salt, rawOnly, encodedOnly); }
public static string CalcArgon2(string password, string salt) { // defaults uint iterations = 3; uint memoryCost = 1024; uint parallelism = 2; uint hashLength = 20; Argon2Type argonType = Argon2Type.Argon2d; string justSalt = salt; // check if salt has settings encoded in it if (salt.StartsWith("$argon2")) { // apparently has settings encoded in it - use these if (salt.StartsWith("$argon2i")) { argonType = Argon2Type.Argon2i; } String[] saltComponents = salt.Split('$'); if (saltComponents.Length == 5) { // make sure Base64 encoded salt length is a multiple of 4 - if not pad justSalt = Encoding.UTF8.GetString(DecodeBase64(saltComponents[4])); String[] saltParams = saltComponents[3].Split(','); foreach (string saltParam in saltParams) { String[] saltParamValues = saltParam.Split('='); switch (saltParamValues[0]) { case "t": if (!uint.TryParse(saltParamValues[1], out iterations)) { iterations = 3; } break; case "m": if (!uint.TryParse(saltParamValues[1], out memoryCost)) { memoryCost = 1024; } break; case "p": if (!uint.TryParse(saltParamValues[1], out parallelism)) { parallelism = 2; } break; case "l": if (!uint.TryParse(saltParamValues[1], out hashLength)) { hashLength = 20; } break; } } } } return(new PasswordHasher(iterations, memoryCost, parallelism, argonType, hashLength).Hash(password, justSalt)); }
/// <summary> Creates an Argon2 <see cref="HashFn"/> with the given parameters. </summary> /// <param name="iterations"> Iterations/'timeCost' to use </param> /// <param name="secret"> Optional secret to use </param> /// <param name="memoryCost"> Memory Cost to use </param> /// <param name="threads"> Threads to use </param> /// <param name="type"> Variant of Argon2 to use </param> /// <param name="size"> Hash length </param> /// <returns> <see cref="HashFn"/> that performs Argon2 with the given parameters </returns> public static HashFn Argon2Hash(int iterations = 3, int memoryCost = 1024 *32, int threads = 8, string secret = null, Argon2Type type = Argon2Type.HybridAddressing, int size = 32) { return((pass) => { DateTime start = DateTime.UtcNow; var result = Argon2.Hash(pass, secret, iterations, memoryCost, threads, type, size); DateTime end = DateTime.UtcNow; Log.Debug($"Argon2.Hash({iterations}, {memoryCost}, {threads}, {type}, {size}) completed in {(end - start).TotalMilliseconds}ms"); return result; }); }
public Argon2ParametersBuilder WithType(Argon2Type type) { _type = type; return(this); }