Нашел на cyberforum.ru вот такой класс для хешрования паролей с солью.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;

namespace ppo_admin
{
    class Password
    {
        private byte[] _salt;       // синхропосылка
        private byte[] _hash;       // хэш пароля
        /*все четыре свойства просто возвращают значения
         * соответствующих полей объекта
         */
        internal string Salt
        {
            get { return Convert.ToBase64String(_salt); }
        }

        internal string Hash
        {
            get { return Convert.ToBase64String(_hash); }
        }

        internal byte[] RawSalt
        {
            get { return (byte[])_salt.Clone(); }
        }

        internal byte[] RawHash
        {
            get { return (byte[])_hash.Clone(); }
        }
        internal Password(string salt, string hash)
        {
            /*Конструктор с двумя строковыми аргументами
             * просто преобразует синхропосылку и хэш из base64
             * в двоичное представление и сохраняет в
             * соответствующих полях класса
             * В конструктор передаем полученную соль и хэш пароля
             */
            _salt = Convert.FromBase64String(salt);
            _hash = Convert.FromBase64String(hash);
        }
        internal Password(byte[] salt, byte[] hash)
        {
            /*Конструктор, принимающий массивы байт,
             * создает копии входных массивов
             * В конструктор передаем полученную соль и хэш пароля
             */
            _salt = (byte[])salt.Clone();
            _hash = (byte[])hash.Clone();
        }
        internal Password(char[] clearText)
        {
            /*Генерация соли и пароля
             * Конструктор с одним аргументом генерирует
             * случайную синхропосылку и вычисляет хэш
             * предоставленного пароля, используя внутренний
             * метод HashPassword()
             */
            _salt = GenerateRandom(6);
            _hash = HashPassword(clearText);
        }
        /*Метод Verify сначала вычисляет хэш предоставленного
         * пароля, используя все тот же внутренний метод
         * HashPassword, после чего сравнивает байты сохраненного
         * хэша с байтами только что вычисленного хэша. Совпадение
         * всех до одного байтов хэша означает, что пароль верный.
         */

        /// 

<summary>
        /// 
        /// </summary>


        /// <param name="clearText">Передаем введенный пароля для проверки.</param>
        /// <returns>Возвращаем если все ок. или не ок</returns>
        internal bool Verify(char[] clearText)
        {
            byte[] hash = HashPassword(clearText);

            if (hash.Length == _hash.Length)
            {
                for (int i = 0; i < hash.Length; i++)
                {
                    if (hash[i] != _hash[i])
                        return false;
                }

                return true;
            }

            return false;
        }
        /*Статический метод Generate просто генерирует
         * массив случайных байтов и преобразует его
         * в base64-строку.
         */
        private static char[] Generate()
        {
            char[] random = new char[12];

            // генерируем 9 случайных байтов; этого достаточно, чтобы
            // получить 12 случайных символов из набора base64
            byte[] rnd = GenerateRandom(9);

            // конвертируем случайные байты в base64
            Convert.ToBase64CharArray(rnd, 0, rnd.Length, random, 0);

            // очищаем рабочий массив
            Array.Clear(rnd, 0, rnd.Length);

            return random;
        }
        /* Метод записывает синхропосылку и пароль в поток на
         * основе массива байтов, а затем вычисляет хэш
         * содержимого потока. В качестве хэш-функции используется
         * алгоритм SHA-256.
         */
        private byte[] HashPassword(char[] clearText)
        {
            Encoding utf8 = Encoding.UTF8;
            byte[] hash;

            // создаем рабочий массив достаточного размера, чтобы вместить
            byte[] data = new byte[_salt.Length
                        + utf8.GetMaxByteCount(clearText.Length)];

            try
            {
                // копируем синхропосылку в рабочий массив
                Array.Copy(_salt, 0, data, 0, _salt.Length);

                // копируем пароль в рабочий массив, преобразуя его в UTF-8
                int byteCount = utf8.GetBytes(clearText, 0, clearText.Length,
                  data, _salt.Length);

                // хэшируем данные массива
                using (HashAlgorithm alg = new SHA256Managed())
                    hash = alg.ComputeHash(data, 0, _salt.Length + byteCount);
            }
            finally
            {
                // очищаем рабочий массив в конце работы, чтобы избежать
                // утечки открытого пароля
                Array.Clear(data, 0, data.Length);
            }

            return hash;
        }
        /*Метод GenerateRandom генерирует массив указанной длины,
         * состоящий из случайных байтов.
         */
        private static byte[] GenerateRandom(int size)
        {
            byte[] random = new byte[size];
            RandomNumberGenerator.Create().GetBytes(random);
            return random;
        }
    }
}

Для генерации паролей создаем форму

    public partial class GeneratePassword : Form
    {
        Password pwd;

        public GeneratePassword()
        {
            InitializeComponent();
        }

        private void btExit_Click(object sender, EventArgs e)
        {
            this.Close();

        }

        private void btGenerate_Click(object sender, EventArgs e)
        {
            //tbNewPassword - textBox для ввода пароля
            //tbSalt        - textBox для вывода сгенерированной соли
            //tbHash        - textBox для вывода сгенерированного пароля
            pwd = new Password(tbNewPassword.Text.ToCharArray());
            tbSalt.Text = pwd.Salt;
            tbHash.Text = pwd.Hash;
        }
    }

Для проверки валидности пароля надо передать соль и хеш.

                SqlConnection con = new SqlConnection(@"Data Source=(localdb)\MyInstance;Initial Catalog=DBase;Integrated Security=true ");
                SqlDataAdapter sda = new SqlDataAdapter("Select * From tb_Users where UserName='" + tbLogin.Text + "'", con);
                DataTable dt = new DataTable();
                sda.Fill(dt);
                if (dt.Rows[0][0] != null)
                {
                    string id   = dt.Rows[0][0].ToString().Trim();
                    string user = dt.Rows[0][1].ToString().Trim();
                    string salt = dt.Rows[0][2].ToString().Trim();
                    string hash = dt.Rows[0][3].ToString().Trim();
                    Password pwd = new Password(salt, hash);
                    if (pwd.Verify(tbPassword.Text.ToCharArray()))
                    {
                        MainForm MainFrm = new MainForm();
                        FormEditUsers edtuser = new FormEditUsers();
                        edtuser.dbstring = "local";
                        MainFrm.Show();
                        this.Hide();
                    }
                    else
                    {
                        MessageBox.Show("Invalide password!");
                    }
                }

Структура таблицы такая

CREATE TABLE [dbo].[tb_Users] (
    [Id]       INT        NOT NULL,
    [UserName] NCHAR (10) NULL,
    [Salt]     NCHAR (10) NULL,
    [Hash]     NCHAR (55) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.