首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >一个简单的加密方案2.0

一个简单的加密方案2.0
EN

Code Review用户
提问于 2021-04-20 17:41:28
回答 1查看 152关注 0票数 1

这是对我以前的职位的跟进。

我使用了一个BCrypt库从传入的密码中创建一个密钥。然后,我将盐从散列中分离出来。加密使用连接到哈希的salt完成,但只有哈希返回给用户。盐被加到加密的数据中。

键(salt+ hash)用于使用SHA3512创建一个512位哈希。数据的每个字节都是用键的一个字节和新哈希的一个字节编辑的。哈希的这个字节被XOR‘’ed替换为键的字节。当到达哈希结束时,这个包含所有新值的字节数组将被散列,并用于下一个64个字节的数据。

解密分离出salt,并将其与传递的密钥组合起来,以创建原始哈希,并继续原始加密步骤。

代码语言:javascript
复制
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}

EN

回答 1

Code Review用户

发布于 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都没有效率。只需使用byte[]。
  • 有人试图用位变换来提高效率。只需使用%并将其留给编译器。考虑到其余的代码看起来并不是最有效的实现(IEnumerable,产率.)牺牲可读性是没有意义的。
  • 为此目的-添加其他评论。考虑到GetBytes的通用名称和缺乏注释,还不清楚它应该实现什么。
  • 如果密码为空、空或字符串低于一定长度-抛出异常。用空密码加密某样东西是没有意义的
  • 正确地命名事物。byte offset不是偏移量(应该是i % key.Length),它是键的一个字节
  • 使用常量而不是分散在代码中的神奇值。
  • 熟悉常见的加密库并尝试遵循它们的模式,不要重新发明不需要重新发明的轮子
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/259768

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档