/// <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();
            }
        }
        // ReSharper disable once UnusedMember.Global

        /// <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="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,
            SecureArrayCall secureArrayCall = null)
        {
            return(Verify(encoded, password, null, secureArrayCall));
        }
 /// <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,
     }));
 }
 /// <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));
 }
示例#5
0
        static readonly byte[] personalization = new byte[] { 99, 107, 98, 45, 100, 101, 102, 97, 117, 108, 116, 45, 104, 97, 115, 104 }; // ckb-default-hash

        public static byte[] ComputeHash(byte[] data)
        {
            Blake2BConfig config = new Blake2BConfig
            {
                Personalization   = personalization,
                OutputSizeInBytes = 32
            };
            SecureArrayCall secureArrayCall = default;

            return(Blake2B.ComputeHash(data, config, secureArrayCall));
        }
        /// <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>
        /// <param name="secret">
        /// The secret hashed into the password.
        /// </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,
            byte[] password,
            byte[] secret,
            SecureArrayCall secureArrayCall = null)
        {
            var configToVerify = new Argon2Config
            {
                Password        = password,
                Secret          = secret,
                SecureArrayCall = secureArrayCall ?? SecureArray.DefaultCall,
            };

            return(Verify(encoded, configToVerify));
        }
示例#7
0
        /// <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);
        }
示例#9
0
        public Blake2BHasher(Blake2BConfig config, SecureArrayCall secureArrayCall)
        {
            if (config == null)
            {
                config = DefaultConfig;
            }
            this.core      = new Blake2BCore(secureArrayCall, config.LockMemoryPolicy);
            this.rawConfig = Blake2IvBuilder.ConfigB(config, null, secureArrayCall);
            if (config.Key != null && config.Key.Length != 0)
            {
                switch (config.LockMemoryPolicy)
                {
                case LockMemoryPolicy.None:
                    this.key = new SecureArray <byte>(128, SecureArrayType.ZeroedAndPinned, secureArrayCall);
                    break;

                case LockMemoryPolicy.BestEffort:
                    try
                    {
                        this.key = new SecureArray <byte>(128, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall);
                    }
                    catch (LockFailException e)
                    {
                        this.key = new SecureArray <byte>(128, SecureArrayType.ZeroedAndPinned, secureArrayCall);
                    }

                    break;

                default:
                    this.key = new SecureArray <byte>(128, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall);
                    break;
                }

                Array.Copy(config.Key, this.key.Buffer, config.Key.Length);
            }

            this.outputSizeInBytes   = config.OutputSizeInBytes;
            this.defaultOutputBuffer = config.Result64ByteBuffer;
            this.Init();
        }
示例#10
0
        /// <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();
            }
        }
示例#11
0
 // ReSharper disable once UnusedMember.Global
 /// <summary>
 /// Perform a default Blake2 hash on the given buffer.
 /// </summary>
 /// <param name="data">
 /// The buffer 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>
 /// <returns>
 /// The hash of the buffer.
 /// </returns>
 public static byte[] ComputeHash(byte[] data, SecureArrayCall secureArrayCall)
 {
     return(ComputeHash(data, 0, data.Length, null, secureArrayCall));
 }
示例#12
0
 /// <summary>
 /// Perform a Blake2 hash on the given buffer using the given Blake2
 /// configuration.
 /// </summary>
 /// <param name="data">
 /// The buffer to hash.
 /// </param>
 /// <param name="config">
 /// The configuration to use.
 /// </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 hash of the buffer.
 /// </returns>
 public static byte[] ComputeHash(byte[] data, Blake2BConfig config, SecureArrayCall secureArrayCall)
 {
     return(ComputeHash(data, 0, data.Length, config, secureArrayCall));
 }
示例#13
0
 /// <summary>
 /// Perform a Blake2 hash on the given buffer using the given Blake2
 /// configuration.
 /// </summary>
 /// <param name="data">
 /// The buffer to hash.
 /// </param>
 /// <param name="start">
 /// The byte in the buffer to start hashing.
 /// </param>
 /// <param name="count">
 /// The number of bytes to hash.
 /// </param>
 /// <param name="config">
 /// The configuration to use.
 /// </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 hash of the buffer.
 /// </returns>
 public static byte[] ComputeHash(byte[] data, int start, int count, Blake2BConfig config, SecureArrayCall secureArrayCall)
 {
     using (var hasher = Create(config, secureArrayCall))
     {
         hasher.Update(data, start, count);
         return(hasher.Finish());
     }
 }
示例#14
0
 // ReSharper disable once UnusedMember.Global
 /// <summary>
 /// Create a default Blake2 hash.
 /// </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>
 /// <returns>
 /// A <see cref="Hasher"/> that can be converted to a <see cref="HashAlgorithm"/>.
 /// </returns>
 public static Hasher Create(SecureArrayCall secureArrayCall)
 {
     return(Create(new Blake2BConfig(), secureArrayCall));
 }
示例#15
0
 /// <summary>
 /// Create a Blake2 hash with the given configuration.
 /// </summary>
 /// <param name="config">
 /// The configuration to use.
 /// </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>
 /// A <see cref="Hasher"/> that can be converted to a <see cref="HashAlgorithm"/>.
 /// </returns>
 public static Hasher Create(Blake2BConfig config, SecureArrayCall secureArrayCall)
 {
     return(new Blake2BHasher(config, secureArrayCall));
 }
示例#16
0
        /// <summary>
        /// Look for leaks.
        /// </summary>
        /// <returns>String with pass/fail message.</returns>
        public static string TestLeaks()
        {
            var             locks           = new Dictionary <IntPtr, int>();
            int             lockCount       = 0;
            var             badLocks        = new List <int>();
            int             badUnlockCount  = 0;
            SecureArrayCall secureArrayCall = new SecureArrayCall(
                SecureArray.DefaultCall.ZeroMemory,
                (m, l) =>
            {
                string ret = SecureArray.DefaultCall.LockMemory(m, l);
                if (ret == null)
                {
                    lock (locks)
                    {
                        ++lockCount;
                        if (locks.ContainsKey(m))
                        {
                            badLocks.Add(lockCount);
                        }
                        else
                        {
                            locks.Add(m, lockCount);
                        }
                    }
                }

                return(ret);
            },
                (m, l) =>
            {
                lock (locks)
                {
                    if (locks.ContainsKey(m))
                    {
                        locks.Remove(m);
                        SecureArray.DefaultCall.UnlockMemory(m, l);
                    }
                    else
                    {
                        ++badUnlockCount;
                    }
                }
            });

            var       hashString   = "$argon2i$v=19$m=65536,t=3,p=1$M2f6+jnVc4dyL3BfMQRzoA==$jO/fOrgqxX90XDVhiYZgIVJJcw0lzIXtRFRCEggXYV8=";
            var       password     = "******";
            const int maxIteration = 10;
            var       memoryDiff   = new long[maxIteration];

            for (int i = 0; i < maxIteration; i++)
            {
                Console.WriteLine($"TestLeaks: Iteration {i + 1} of {maxIteration}");
                var prevTotalMemory = GC.GetTotalMemory(true);
                Argon2.Verify(hashString, password, secureArrayCall);
                var postTotalMemory = GC.GetTotalMemory(true);
                memoryDiff[i] = postTotalMemory - prevTotalMemory;
            }

            var errs = new List <string>();

            if (memoryDiff.All(v => v > 0))
            {
                errs.Add($"Leaked {memoryDiff.Min()} bytes");
            }

            if (badLocks.Any())
            {
                errs.Add($"{badLocks.Count} bad locks: [{string.Join(", ", badLocks.Select(l => $"{l}"))}].");
            }

            if (badUnlockCount > 0)
            {
                errs.Add($"{badUnlockCount} bad unlocks.");
            }

            if (locks.Any())
            {
                errs.Add($"Leaked {locks.Count} locks: addresses=[{string.Join(", ", locks.Keys.Select(k => $"0x{k.ToInt64():x8}"))}], lock index=[{string.Join(", ", locks.Keys.Select(k => $"{locks[k]}"))}].");
            }

            return(errs.Any() ? $"Leaks: FAILED: {string.Join(" ", errs)}" : "Leaks: Passed");
        }
        public static SecureArray <ulong> ConfigB(Blake2BConfig config, Blake2BTreeConfig treeConfig, SecureArrayCall secureArrayCall)
        {
            bool isSequential = treeConfig == null;

            if (isSequential)
            {
                treeConfig = SequentialTreeConfig;
            }

            SecureArray <ulong> rawConfig;

            try
            {
                rawConfig = new SecureArray <ulong>(8, SecureArrayType.ZeroedPinnedAndNoSwap, secureArrayCall);
            }
            catch (LockFailException)
            {
                rawConfig = new SecureArray <ulong>(8, SecureArrayType.ZeroedAndPinned, secureArrayCall);
            }

            //digest length
            if (config.OutputSizeInBytes <= 0 | config.OutputSizeInBytes > 64)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(config),
                          $"Expected 0 < config.OutputSizeInBytes <= 64, got {config.OutputSizeInBytes}");
            }

            rawConfig[0] |= (uint)config.OutputSizeInBytes;

            //Key length
            if (config.Key != null)
            {
                if (config.Key.Length > 64)
                {
                    throw new ArgumentException($"Expected key length <= 64, got {config.Key.Length}", nameof(config));
                }

                rawConfig[0] |= (uint)config.Key.Length << 8;
            }

            // FanOut
            rawConfig[0] |= (uint)treeConfig.FanOut << 16;

            // Depth
            rawConfig[0] |= (uint)treeConfig.MaxHeight << 24;

            // Leaf length
            rawConfig[0] |= ((ulong)(uint)treeConfig.LeafSize) << 32;

            // Inner length
            if (!isSequential && (treeConfig.IntermediateHashSize <= 0 || treeConfig.IntermediateHashSize > 64))
            {
                throw new ArgumentOutOfRangeException(
                          nameof(treeConfig),
                          $"Expected 0 < treeConfig.IntermediateHashSize <= 64, got {treeConfig.IntermediateHashSize}");
            }

            rawConfig[2] |= (uint)treeConfig.IntermediateHashSize << 8;

            // Salt
            if (config.Salt != null)
            {
                if (config.Salt.Length != 16)
                {
                    throw new ArgumentException("config.Salt has invalid length");
                }

                rawConfig[4] = Blake2BCore.BytesToUInt64(config.Salt, 0);
                rawConfig[5] = Blake2BCore.BytesToUInt64(config.Salt, 8);
            }

            // Personalization
            if (config.Personalization != null)
            {
                if (config.Personalization.Length != 16)
                {
                    throw new ArgumentException(
                              $"Expected config.Personalization == 16, got {config.Personalization.Length}",
                              nameof(config));
                }

                rawConfig[6] = Blake2BCore.BytesToUInt64(config.Personalization, 0);
                rawConfig[7] = Blake2BCore.BytesToUInt64(config.Personalization, 8);
            }

            return(rawConfig);
        }
示例#18
0
 // ReSharper disable once UnusedMember.Global
 /// <summary>
 /// Perform a default Blake2 hash on the given buffer.
 /// </summary>
 /// <param name="data">
 /// The buffer to hash.
 /// </param>
 /// <param name="start">
 /// The byte in the buffer to start hashing.
 /// </param>
 /// <param name="count">
 /// The number of bytes 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>
 /// <returns>
 /// The hash of the buffer.
 /// </returns>
 public static byte[] ComputeHash(byte[] data, int start, int count, SecureArrayCall secureArrayCall)
 {
     return(ComputeHash(data, start, count, null, secureArrayCall));
 }