Простая схема шифрования 2.0

Это продолжение моей предыдущей публикации.

Я использовал библиотеку BCrypt для создания ключа из переданного пароля. Затем я отделил соль от хеша. Шифрование выполняется с использованием соли, объединенной с хешем, но пользователю возвращается только хеш. К зашифрованным данным добавляется соль.

Ключ (соль + хеш) используется для создания 512-битного хеша с использованием SHA3512. Каждый байт данных подвергается операции XOR с байтом ключа и байтом нового хэша. Этот байт хеша заменяется XOR с байтом ключа. Когда достигается конец хэша, этот массив байтов со всеми новыми значениями затем хешируется и используется для следующих 64 байтов данных.

Расшифровка отделяет соль и объединяет ее с переданным ключом, чтобы создать исходный хэш и продолжить исходные шаги шифрования.

using System.Text;
using System.Linq;
using System.Collections.Generic;
using SHA3.Net;
using BCrypt.Net;

class Cipher
{
    public static IEnumerable<byte> Encrypt(string password, IEnumerable<byte> data,out string key)
    {
        if (password == null)
        {
            password = "";
        }
        if (data == null)
        {
            data = new byte[] { 0 };
        }
        var hash = MakeKey(password);
        key = new string(hash, 22, 31);
        string salt = new string(hash, 0, 22);
        return GetBytes(data, key,salt);
    }
    public static IEnumerable<byte> Decrypt(IEnumerable<byte> data, string key)
    {
        if (data == null)
        {
            data = new byte[] { 0 };
        }
        return GetBytes(data, key);
    }
    static IEnumerable<byte> GetBytes(IEnumerable<byte> data, string key, string salt = "")
    {
        int saltLength = 0;
        if(salt == "")
        {
            salt = new string(data.Take(22).Select(x => (char)x).ToArray());
            saltLength = 22;
        }
        else
        {
            foreach(char c in salt)
            {
                yield return (byte)c;
            }
        }
        key = $"{salt}{key}";               
        var hash = Sha3.Sha3512().ComputeHash(Encoding.UTF8.GetBytes(key));
        int i = 0;
        foreach (var b in data.Skip(saltLength))
        {
            //modulo 64
            int hashIndex = (int)(((uint)i << 26) >> 26);
            if (i > 0 && hashIndex == 0)
            {
                hash = Sha3.Sha3512().ComputeHash(hash);
            }
            byte offset = (byte)key[i % key.Length];
            var retVal = (byte)(b ^ offset ^ hash[hashIndex]);
            hash[hashIndex] ^= offset;
            ++i;
            yield return retVal;
        }
    }

    static char[] MakeKey(string password) => BCrypt.Net.BCrypt.HashPassword(password).Skip(7).ToArray();
}

Вот как могут выглядеть зашифрованные данные:

{86, 110, 68, 77, 68, 75, 46, 116, 73, 99, 50, 53, 114, 57, 89, 47, 109, 70, 88, 105, 114, 117, 233, 83, 221 , 231, 216, 45, 118, 223, 227, 185, 170, 177, 131, 154, 240, 170, 72, 192, 182, 112, 149, 208, 102, 235, 252, 156, 127, 189 , 255, 240, 203, 152, 142, 189, 140, 64, 166, 196, 13, 254, 138, 159, 229, 199, 80, 80, 113, 162, 137, 87, 216, 59, 81 , 140, 123, 199, 211, 75, 43, 62, 11, 3}

1 ответ
1

Слишком необычно, слишком сложно читать. Весь код можно сжать во что-то вроде
BCrypt.Net.BCrypt.HashPassword(salt+password).ToArray()

Посмотрите, как использовать эту функцию здесь: https://jasonwatmore.com/post/2020/07/16/aspnet-core-3-hash-and-verify-passwords-with-bcrypt

Самое главное: нет смысла использовать мощное хеширование, такое как SHA3 и BCrypt, только для использования какой-то вымышленной схемы шифрования XOR. Используйте стандартный алгоритм шифрования из авторитетной библиотеки.

Помимо этого, у меня есть другие проблемы с этим кодом:

  • Является .Skip(7) предполагается как-то удалить соль? Вы не можете «удалить» соль, строка, которую вы получаете от этой функции, больше не является вашим вводом, это совершенно другая строка (также известная как хеш).

  • Все эти IEnumerable неэффективны. Просто используйте байт[].

  • есть попытка эффективно использовать битовые сдвиги. Просто используйте % и оставьте это компилятору. Учитывая, что остальная часть кода не похожа на наиболее эффективную реализацию (IEnumerable, yield …), нет смысла жертвовать удобочитаемостью

  • с этой целью — добавить другие комментарии. Непонятно что GetBytes предполагается достичь, учитывая его общее название и отсутствие комментариев.

  • если пароль нулевой, пустой или строка меньше определенной длины — выбросить исключение. Нет смысла шифровать что-то пустым паролем

  • назовите вещи правильно. byte offset не смещение (это было бы i % key.Length), это байт от ключа

  • используйте константы вместо магических значений, разбросанных по коду.

  • ознакомьтесь с общими библиотеками шифрования и постарайтесь следовать их шаблонам, не изобретайте колеса, которые не нужно изобретать заново

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

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