Это продолжение моей предыдущей публикации.
Я использовал библиотеку 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 ответ
Слишком необычно, слишком сложно читать. Весь код можно сжать во что-то вроде 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), это байт от ключаиспользуйте константы вместо магических значений, разбросанных по коду.
ознакомьтесь с общими библиотеками шифрования и постарайтесь следовать их шаблонам, не изобретайте колеса, которые не нужно изобретать заново
