这是对我以前的职位的跟进。
我使用了一个BCrypt库从传入的密码中创建一个密钥。然后,我将盐从散列中分离出来。加密使用连接到哈希的salt完成,但只有哈希返回给用户。盐被加到加密的数据中。
键(salt+ hash)用于使用SHA3512创建一个512位哈希。数据的每个字节都是用键的一个字节和新哈希的一个字节编辑的。哈希的这个字节被XOR‘’ed替换为键的字节。当到达哈希结束时,这个包含所有新值的字节数组将被散列,并用于下一个64个字节的数据。
解密分离出salt,并将其与传递的密钥组合起来,以创建原始哈希,并继续原始加密步骤。
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}
发布于 2021-04-21 22:59:02
太花哨,太难读。可以将整个代码压缩为类似于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加密方案是没有意义的。使用来自信誉库的标准加密算法。如果您不信任任何库或算法,那么使用两种不同的算法、不同的密钥以及可能使用来自不同供应商的库进行2次加密。
除此之外,下面还有关于这个代码的其他问题:
.Skip(7)应该以某种方式除去盐吗?您不能“删除”salt,从该函数获得的字符串不再是您的输入,它是一个完全不同的字符串(也称为散列)。%并将其留给编译器。考虑到其余的代码看起来并不是最有效的实现(IEnumerable,产率.)牺牲可读性是没有意义的。GetBytes的通用名称和缺乏注释,还不清楚它应该实现什么。byte offset不是偏移量(应该是i % key.Length),它是键的一个字节https://codereview.stackexchange.com/questions/259768
复制相似问题