dennisge
V2EX  ›  Node.js

Java 的 sha1 加盐 加密和 node 实现的加密值不一样。

  •  
  •   dennisge · Dec 19, 2017 · 10869 views
    This topic created in 3244 days ago, the information mentioned may be changed or developed.

    通过 java 的 sha1 加 salt 加密,和 node crypto 生成的加密值不一致。有踩过坑的吗?

    55 replies  •  2017-12-22 10:12:52 +08:00
    sagaxu
    sagaxu
    Dec 19, 2017 via Android❤️2
    1
    那只能说明你写错了
    Jaylee
    Jaylee
    Dec 19, 2017
    2
    如果要加密的字符串有中文的话,node 需要指定编码
    mcfog
    mcfog
    Dec 19, 2017 via Android
    3
    //密码学问题不要自作聪明,加盐就乖乖用 hmac 来加
    dennisge
    dennisge
    OP
    Dec 19, 2017
    4
    1. 这是原 java 的加密
    a123456 => 79893503e8074330321974fa14dc44f8aa1b3df0
    plainPassword = StringUtils.trim(plainPassword);
    byte[] salt = Digests.generateSalt(SALT_SIZE); // af350c3413179ab4
    byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), salt, HASH_INTERATIONS);

    private static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
    try {
    MessageDigest digest = MessageDigest.getInstance(algorithm);

    if (salt != null) {
    digest.update(salt);
    }

    byte[] result = digest.digest(input);

    for (int i = 1; i < iterations; i++) {
    digest.reset();
    result = digest.digest(result);
    }
    return result;
    } catch (GeneralSecurityException e) {
    throw Exceptions.unchecked(e);
    }
    }

    2. node
    dennisge
    dennisge
    OP
    Dec 19, 2017
    5
    2.node
    const old = 'af350c3413179ab479893503e8074330321974fa14dc44f8aa1b3df0';
    const origin = 'a123456';
    const saltStr = old.substring(0, 16);
    const salt = new Buffer(saltStr, 'hex');

    const originBuf = new Buffer(origin);
    console.log('originBuf>>');
    console.log(originBuf);
    console.log(originBuf.length);


    const encrypt1 = crypto.createHash('sha1')
    .update(salt)
    .update(originBuf)
    .digest('hex');

    const encrypt2 = crypto.createHmac('sha1', salt)
    .update(originBuf)
    .digest('hex');

    console.log(encrypt1);
    console.log(encrypt2);

    =>
    originBuf>>
    <Buffer 61 31 32 33 34 35 36>
    7
    e03f07ac2befce638c5886adecbec96a06ce5a51
    ab7b28b75346d63105a9bdc5a0365c1967eb132c
    dennisge
    dennisge
    OP
    Dec 19, 2017
    6
    @mcfog 用 hmac 也不一致
    dennisge
    dennisge
    OP
    Dec 19, 2017
    7
    @sagaxu 请赐教
    dennisge
    dennisge
    OP
    Dec 19, 2017
    8
    @Jaylee 没有中文,全是英文的
    SlipStupig
    SlipStupig
    Dec 19, 2017
    9
    我遇到过 pypy 和 python hmac 不一样过......
    Liang
    Liang
    Dec 19, 2017
    10
    试过.net 和 java 不一样,调试了 2 天。。。
    应该是我能力问题
    lihongjie0209
    lihongjie0209
    Dec 19, 2017
    11
    盐( Salt ),在密码学中,是指在散列之前将散列内容(例如:密码)的任意固定位置插入特定的字符串。这个在散列中加入字符串的方式称为“加盐”。其作用是让加盐后的散列结果和没有加盐的结果不相同,在不同的应用情景中,这个处理可以增加额外的安全性。
    在大部分情况,盐是不需要保密的。盐可以是随机产生的字符串,**其插入的位置可以也是随意而定**。如果这个散列结果在将来需要进行验证(例如:验证用户输入的密码),则需要将已使用的盐记录下来。

    加盐的位置是随机的.
    rrfeng
    rrfeng
    Dec 19, 2017 via Android
    12
    一般来说就是参数不一致。
    不同语言的库可能有不同的默认参数的,仔细看一下文档应该能解决。
    dennisge
    dennisge
    OP
    Dec 19, 2017
    13
    @lihongjie0209 解释的很详细。但是我现在就是 java 加密的密码,用相同的盐,结果 node 却解不出来
    dennisge
    dennisge
    OP
    Dec 19, 2017
    14
    @rrfeng 翻遍了代码哦,不然不会随便问问题的。通读了文档,尝试了很多次,实在没办法,才开问。
    dennisge
    dennisge
    OP
    Dec 19, 2017
    15
    我怀疑是不是 java 支持的带符号整型,而 node 不支持。af350c3413179ab4 。这个是 salt 的 hex 值,java 的 8 个字节有负数,而 node 是不支持的,这个造成了 salt 不一样???
    hsuan
    hsuan
    Dec 19, 2017 via Android
    16
    sha1 能叫加密吗
    metrxqin
    metrxqin
    Dec 19, 2017
    17
    代码能贴完整点吗?
    zhicheng
    zhicheng
    Dec 19, 2017❤️1
    18
    原因很简单,你写错了。
    sagaxu
    sagaxu
    Dec 19, 2017
    20
    node 结点的黑底白字配色,让我这个近视加散光严重的,彻底受不了了,逃离
    neoblackcap
    neoblackcap
    Dec 19, 2017
    21
    在一段时间我曾经写过多种语言的客户端校验模块,曾用了多种语言自带的 sha1 等实现。针对题主的问题,我只能很肯定地说你写错了。
    我只能猜你那 digest 函数出问题了,你那多次的迭代是干嘛的?我没看到 node 版本有多次迭代,你若要比较请给出你的迭代参数 iterations
    dennisge
    dennisge
    OP
    Dec 19, 2017
    23
    @zhicheng 望指教
    dennisge
    dennisge
    OP
    Dec 19, 2017
    24
    @sagaxu 哈哈
    dennisge
    dennisge
    OP
    Dec 19, 2017
    25
    @neoblackcap 上面的 java 实现,是先人的代码,我也不清楚那个多个迭代的作用。iterations 是 1024。不懂 java,所以没理解透。
    dennisge
    dennisge
    OP
    Dec 19, 2017
    26
    @superhan 看了您发的这个,学习了。但和我的场景有些不一样。以前他们 java 生成的密码加密值,现在用 node 得不到。你给的例子,salt 的都是 string 的,而这里 salt 是一个 bytes [], 这个会有关系吗?
    zhicheng
    zhicheng
    Dec 19, 2017
    27
    @dennisge 你写错了,不要怀疑语言,不要怀疑算法,不要怀疑类库,不要找借口,不要说这是坑。

    没有什么可指教的,就是调用一个函数的事儿,我不知道这种事情怎么“指教”,要是还不懂,就把上边那句话再念一遍。

    Java
    ```
    import java.security.MessageDigest;
    import javax.xml.bind.DatatypeConverter;

    class a {
    public static void main(String args[]) {
    String str = "a123456";
    String salt = "af350c3413179ab4";
    try {
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    md.update(DatatypeConverter.parseHexBinary(salt));
    md.update(str.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(md.digest()));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    ```
    JS
    ```
    crypto = require('crypto');
    const str = 'a123456';
    const salt = new Buffer('af350c3413179ab4', 'hex');

    console.log(crypto.createHash('sha1').update(salt).update(str).digest('hex'));
    ```
    Python
    ```
    import hashlib
    print hashlib.sha1('af350c3413179ab4'.decode('hex') + 'a123456').hexdigest()
    ```
    dennisge
    dennisge
    OP
    Dec 19, 2017
    28
    @zhicheng 感谢您的回答,但是您能得到这个最终的加密值吗? 79893503e8074330321974fa14dc44f8aa1b3df0。 我感觉和你用的方法没啥不一样啊,但就是得不到最后的值。是不是和原 java 实现的
    for (int i = 1; i < iterations; i++) {
    digest.reset();
    result = digest.digest(result);
    }
    有关系?
    dennisge
    dennisge
    OP
    Dec 20, 2017
    29
    @zhicheng 如果只是你说的简单的方法,我觉得结果早就出来了。如果你能得到上面的这个加密值,那我闭嘴.
    neoblackcap
    neoblackcap
    Dec 20, 2017
    30
    @dennisge 我看你这 Java 实现是对加盐并 sha1 处理一次后的二进制流再进行了 1024 次的 sha1 迭代。你试试用 node 版本对你现在的结果再进行 1024 次 sha1 看看
    dennisge
    dennisge
    OP
    Dec 20, 2017
    31
    @neoblackcap java 是以前别人的代码。并没有理解透。能麻烦您你解释下吗
    zhicheng
    zhicheng
    Dec 20, 2017
    32
    @dennisge 我并不想打击你,这真的是一眨眼,一个函数调用的事儿。

    ```
    import hashlib
    result = hashlib.sha1('af350c3413179ab4'.decode('hex') + 'a123456').digest()
    for i in range(1, 1024):
    result = hashlib.sha1(result).digest()

    print result.encode('hex')
    ```
    79893503e8074330321974fa14dc44f8aa1b3df0
    dennisge
    dennisge
    OP
    Dec 20, 2017
    33
    @zhicheng 你用 node 试试?
    zhicheng
    zhicheng
    Dec 20, 2017
    34
    @dennisge 付钱不?
    dennisge
    dennisge
    OP
    Dec 20, 2017
    35
    @zhicheng O(∩_∩)O 哈哈~,太感谢你了。你真的太好了~~~看了你的微博,送书计划真的很赞
    dennisge
    dennisge
    OP
    Dec 20, 2017
    36
    @zhicheng 不过我刚用 node 实现一遍,还是不一样哦,结果不对。
    const crypto = require('crypto');

    const salt = 'af350c3413179ab4';
    const saltStr = new Buffer(salt, 'hex').toString('utf8');
    console.log(saltStr);
    let result = crypto.createHash('sha1').update(saltStr + 'a123456').digest('hex');
    for (let i = 1; i <= 1024; i++) {
    result = crypto.createHash('sha1').update(result).digest('hex');
    }

    console.log(result);
    lcdtyph
    lcdtyph
    Dec 20, 2017 via iPhone
    37
    @dennisge 你这个 node 循环了 1024 次,上面 java 循环了 1023 次
    ryd994
    ryd994
    Dec 20, 2017 via Android
    38
    循环 hash1024 次,真是意义不明
    反复 hash 只会减小值域不可能增加
    初中数学去哪了?
    ryd994
    ryd994
    Dec 20, 2017 via Android
    39
    还有,就算是 1024 次 sha1 也是快的一比
    bcrypt 调调难度系数,分分钟超过你的兔子算法
    密码储存讲究的是慢,才能避免字典攻击
    dennisge
    dennisge
    OP
    Dec 20, 2017
    40
    @lcdtyph 恩,1023 的也不好用。上面复制的之前的。
    dennisge
    dennisge
    OP
    Dec 20, 2017
    41
    @ryd994 恩,因为 java 代码是以前别人 java 实现了。现在我们要 node 重写,只能按以前的破逻辑重写了。不过你说的 bcrypt 会更好吗,还会引入 node-gyp
    dexterlei
    dexterlei
    Dec 20, 2017
    42
    我的经验是,总可以发现是自己写错了
    dennisge
    dennisge
    OP
    Dec 20, 2017
    43
    @zhicheng 感谢大神,终于成功了!!
    kohos
    kohos
    Dec 20, 2017
    44
    这种加盐迭代 sha1 的方法应该就是 pbkdf2 算法吧……恭喜解决问题
    dennisge
    dennisge
    OP
    Dec 20, 2017
    45
    @kohos 对啊,node 现在建议的也是 pbkdf2。我看 @zhicheng 的文章也是。但因为重写 java 的实现,不能改以前的逻辑。
    vefawn1
    vefawn1
    Dec 20, 2017 via Android
    46
    我很好奇,为何打开这个页面后网页背景变黑了?
    quickma
    quickma
    Dec 20, 2017
    47
    @vefawn1 node 节点自带出场背景

    原则 2:所有编程的技术问题,统统自己找答案
    pusadao
    pusadao
    Dec 20, 2017
    48
    const crypto = require('crypto')

    const sha1 = crypto.createHash('sha1')
    const salt = new Buffer('af350c3413179ab4', 'hex')
    const origin = new Buffer('a123456')
    sha1.update(salt)
    sha1.update(origin)
    let result = sha1.digest()

    for (let i = 1; i < 1024; i++) {
    result = crypto.createHash('sha1').update(result).digest()
    }

    console.log(result.toString('hex')) // 79893503e8074330321974fa14dc44f8aa1b3df0
    hantsy
    hantsy
    Dec 20, 2017
    49
    不同语言加密结果不一样的可能性不大。

    对 Spring Stack, Spring Security 4 开始使用新的 PasswordEncoder,早不需要 Salt 了,我早不关心 Salt 了。一直其使用推荐的 BCrypt,即使密码相同,加密结果也不一样,不用担心密码碰撞问题 。
    Spring Secuirty 5 也加强更为现代的 PasswordEncoder 功能, BCrypt 是默认的(如果启用的话)。
    hantsy
    hantsy
    Dec 20, 2017
    50
    不过我对密码加密之类没什么太多的研究,有这方面经验的人,不妨分享一下一些基本的知识:

    1. crypt
    2. salt
    3. hash
    等等
    dennisge
    dennisge
    OP
    Dec 20, 2017
    51
    @hantsy 是的,这方便深究还挺多要点的
    dennisge
    dennisge
    OP
    Dec 20, 2017
    52
    @pusadao 赞,后来也是这样的。关键对于 node 的 digest,以及后面的多次加密没理解透。
    dennisge
    dennisge
    OP
    Dec 20, 2017
    53
    @x7395759 对的~
    metrxqin
    metrxqin
    Dec 20, 2017
    54
    `高手` **如云**!
    edsgerlin
    edsgerlin
    Dec 22, 2017
    55
    密码加密乖乖用 PBKDF2, BCrypt, Argon2 这些专业的 KDF,别自己瞎搞。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2174 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 13:19 · PVG 21:19 · LAX 05:19 · JFK 08:19
    ♥ Do have faith in what you're doing.