/// <summary> /// Extracts the memory cost, time cost, etc. used to generate the Argon2 hash. /// <param name="formattedHash">An encoded Argon2 hash created by the Hash method</param> /// <returns>The hash metadata or null if the formattedHash was not a valid encoded Argon2 hash</returns> /// </summary> public static HashMetadata ExtractMetadata(string formattedHash) { CheckNull("ExtractMetadata", "formattedHash", formattedHash); var context = new Argon2Context { Out = Marshal.AllocHGlobal(formattedHash.Length), // ensure the space to hold the hash is long enough OutLen = (uint)formattedHash.Length, Pwd = Marshal.AllocHGlobal(1), PwdLen = 1, Salt = Marshal.AllocHGlobal(formattedHash.Length), // ensure the space to hold the salt is long enough SaltLen = (uint)formattedHash.Length, Secret = Marshal.AllocHGlobal(1), SecretLen = 1, AssocData = Marshal.AllocHGlobal(1), AssocDataLen = 1, TimeCost = 0, MemoryCost = 0, Lanes = 0, Threads = 0 }; try { var type = (formattedHash.StartsWith("$argon2i") ? Argon2Type.Argon2i : Argon2Type.Argon2d); var result = (Argon2Error)crypto_decode_string(context, Encoding.ASCII.GetBytes(formattedHash + "\0"), (int)type); if (result != Argon2Error.OK) { return(null); } var salt = new byte[context.SaltLen]; var hash = new byte[context.OutLen]; Marshal.Copy(context.Salt, salt, 0, salt.Length); Marshal.Copy(context.Out, hash, 0, hash.Length); return(new HashMetadata { ArgonType = type, MemoryCost = context.MemoryCost, TimeCost = context.TimeCost, Parallelism = context.Threads, Salt = salt, Hash = hash }); } finally { Marshal.FreeHGlobal(context.Out); Marshal.FreeHGlobal(context.Pwd); Marshal.FreeHGlobal(context.Salt); Marshal.FreeHGlobal(context.Secret); Marshal.FreeHGlobal(context.AssocData); } }
private static extern int crypto_decode_string(Argon2Context ctx, byte[] str, int type);
/// <summary> /// Extracts the memory cost, time cost, etc. used to generate the Argon2 hash. /// <param name="formattedHash">An encoded Argon2 hash created by the Hash method</param> /// <returns>The hash metadata or null if the formattedHash was not a valid encoded Argon2 hash</returns> /// </summary> public static HashMetadata ExtractMetadata(string formattedHash) { CheckNull("ExtractMetadata", "formattedHash", formattedHash); var context = new Argon2Context { Out = Marshal.AllocHGlobal(formattedHash.Length), // ensure the space to hold the hash is long enough OutLen = (uint)formattedHash.Length, Pwd = Marshal.AllocHGlobal(1), PwdLen = 1, Salt = Marshal.AllocHGlobal(formattedHash.Length), // ensure the space to hold the salt is long enough SaltLen = (uint)formattedHash.Length, Secret = Marshal.AllocHGlobal(1), SecretLen = 1, AssocData = Marshal.AllocHGlobal(1), AssocDataLen = 1, TimeCost = 0, MemoryCost = 0, Lanes = 0, Threads = 0 }; try { var type = (formattedHash.StartsWith("$argon2i") ? Argon2Type.Argon2i : Argon2Type.Argon2d); var result = (Argon2Error)crypto_decode_string(context, Encoding.ASCII.GetBytes(formattedHash + "\0"), (int)type); if (result != Argon2Error.OK) return null; var salt = new byte[context.SaltLen]; var hash = new byte[context.OutLen]; Marshal.Copy(context.Salt, salt, 0, salt.Length); Marshal.Copy(context.Out, hash, 0, hash.Length); return new HashMetadata { ArgonType = type, MemoryCost = context.MemoryCost, TimeCost = context.TimeCost, Parallelism = context.Threads, Salt = salt, Hash = hash }; } finally { Marshal.FreeHGlobal(context.Out); Marshal.FreeHGlobal(context.Pwd); Marshal.FreeHGlobal(context.Salt); Marshal.FreeHGlobal(context.Secret); Marshal.FreeHGlobal(context.AssocData); } }
private static extern int crypto_decode_string(Argon2Context ctx, byte[] str, int type);