/// <summary>Generates a hash based on a key, salt and personal bytes</summary> /// <returns><c>byte</c> hashed message</returns> /// <param name="message">Message.</param> /// <param name="key">Key.</param> /// <param name="salt">Salt.</param> /// <param name="personal">Personal string.</param> /// <param name="bytes">The size (in bytes) of the desired result.</param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="SaltOutOfRangeException"></exception> /// <exception cref="PersonalOutOfRangeException"></exception> public static byte[] HashSaltPersonal(byte[] message, byte[] key, byte[] salt, byte[] personal, int bytes = OUT_BYTES) { if (message == null) { throw new ArgumentNullException("message", "Message cannot be null"); } if (salt == null) { throw new ArgumentNullException("salt", "Salt cannot be null"); } if (personal == null) { throw new ArgumentNullException("personal", "Personal string cannot be null"); } if (key != null && (key.Length > KEY_BYTES_MAX || key.Length < KEY_BYTES_MIN)) { throw new KeyOutOfRangeException(string.Format("key must be between {0} and {1} bytes in length.", KEY_BYTES_MIN, KEY_BYTES_MAX)); } if (key == null) { key = new byte[0]; } if (salt.Length != SALT_BYTES) { throw new SaltOutOfRangeException(string.Format("Salt must be {0} bytes in length.", SALT_BYTES)); } if (personal.Length != PERSONAL_BYTES) { throw new PersonalOutOfRangeException(string.Format("Personal bytes must be {0} bytes in length.", PERSONAL_BYTES)); } //validate output length if (bytes > BYTES_MAX || bytes < BYTES_MIN) { throw new BytesOutOfRangeException("bytes", bytes, string.Format("bytes must be between {0} and {1} bytes in length.", BYTES_MIN, BYTES_MAX)); } var buffer = new byte[bytes]; SodiumLibrary.crypto_generichash_blake2b_salt_personal(buffer, buffer.Length, message, message.LongLength, key, key.Length, salt, personal); return(buffer); }