Java 的 sha1 加盐 加密和 node 实现的加密值不一样。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dennisge
V2EX    Node.js

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

  •  
  •   dennisge 2017-12-19 19:58:47 +08:00 10003 次点击
    这是一个创建于 2853 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    55 条回复    2017-12-22 10:12:52 +08:00
    sagaxu
        1
    sagaxu  
       2017-12-19 20:01:28 +08:00 via Android   2
    那只能说明你写错了
    Jaylee
        2
    Jaylee  
       2017-12-19 20:15:02 +08:00
    如果要加密的字符串有中文的话,node 需要指定编码
    mcfog
        3
    mcfog  
       2017-12-19 20:17:24 +08:00 via Android
    //密码学问题不要自作聪明,加盐就乖乖用 hmac 来加
    dennisge
        4
    dennisge  
    OP
       2017-12-19 20:41:47 +08:00
    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
        5
    dennisge  
    OP
       2017-12-19 20:45:18 +08:00
    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
        6
    dennisge  
    OP
       2017-12-19 20:45:45 +08:00
    @mcfog 用 hmac 也不一致
    dennisge
        7
    dennisge  
    OP
       2017-12-19 20:45:56 +08:00
    @sagaxu 请赐教
    dennisge
        8
    dennisge  
    OP
       2017-12-19 20:46:17 +08:00
    @Jaylee 没有中文,全是英文的
    SlipStupig
        9
    SlipStupig  
       2017-12-19 20:54:17 +08:00
    我遇到过 pypy 和 python hmac 不一样过......
    Liang
        10
    Liang  
       2017-12-19 20:55:25 +08:00
    试过.net 和 java 不一样,调试了 2 天。。。
    应该是我能力问题
    lihongjie0209
        11
    lihongjie0209  
       2017-12-19 20:56:29 +08:00
    盐( Salt ),在密码学中,是指在散列之前将散列内容(例如:密码)的任意固定位置插入特定的字符串。这个在散列中加入字符串的方式称为“加盐”。其作用是让加盐后的散列结果和没有加盐的结果不相同,在不同的应用情景中,这个处理可以增加额外的安全性。
    在大部分情况,盐是不需要保密的。盐可以是随机产生的字符串,**其插入的位置可以也是随意而定**。如果这个散列结果在将来需要进行验证(例如:验证用户输入的密码),则需要将已使用的盐记录下来。

    加盐的位置是随机的.
    rrfeng
        12
    rrfeng  
       2017-12-19 20:57:14 +08:00 via Android
    一般来说就是参数不一致。
    不同语言的库可能有不同的默认参数的,仔细看一下文档应该能解决。
    dennisge
        13
    dennisge  
    OP
       2017-12-19 20:58:55 +08:00
    @lihongjie0209 解释的很详细。但是我现在就是 java 加密的密码,用相同的盐,结果 node 却解不出来
    dennisge
        14
    dennisge  
    OP
       2017-12-19 20:59:48 +08:00
    @rrfeng 翻遍了代码哦,不然不会随便问问题的。通读了文档,尝试了很多次,实在没办法,才开问。
    dennisge
        15
    dennisge  
    OP
       2017-12-19 21:04:10 +08:00
    我怀疑是不是 java 支持的带符号整型,而 node 不支持。af350c3413179ab4 。这个是 salt 的 hex 值,java 的 8 个字节有负数,而 node 是不支持的,这个造成了 salt 不一样???
    hsuan
        16
    hsuan  
       2017-12-19 21:38:30 +08:00 via Android
    sha1 能叫加密吗
    metrxqin
        17
    metrxqin  
       2017-12-19 22:07:11 +08:00
    代码能贴完整点吗?
    zhicheng
        18
    zhicheng  
       2017-12-19 22:12:37 +08:00   1
    原因很简单,你写错了。
    sagaxu
        19
    sagaxu  
       2017-12-19 22:17:08 +08:00
    sagaxu
        20
    sagaxu  
       2017-12-19 22:18:03 +08:00
    node 结点的黑底白字配色,让我这个近视加散光严重的,彻底受不了了,逃离
    neoblackcap
        21
    neoblackcap  
       2017-12-19 22:27:25 +08:00
    在一段时间我曾经写过多种语言的客户端校验模块,曾用了多种语言自带的 sha1 等实现。针对题主的问题,我只能很肯定地说你写错了。
    我只能猜你那 digest 函数出问题了,你那多次的迭代是干嘛的?我没看到 node 版本有多次迭代,你若要比较请给出你的迭代参数 iterations
    superhan
        22
    superhan  
       2017-12-19 22:49:37 +08:00 via Android
    dennisge
        23
    dennisge  
    OP
       2017-12-19 23:22:12 +08:00
    @zhicheng 望指教
    dennisge
        24
    dennisge  
    OP
       2017-12-19 23:22:38 +08:00
    @sagaxu 哈哈
    dennisge
        25
    dennisge  
    OP
       2017-12-19 23:24:42 +08:00
    @neoblackcap 上面的 java 实现,是先人的代码,我也不清楚那个多个迭代的作用。iterations 是 1024。不懂 java,所以没理解透。
    dennisge
        26
    dennisge  
    OP
       2017-12-19 23:27:29 +08:00
    @superhan 看了您发的这个,学习了。但和我的场景有些不一样。以前他们 java 生成的密码加密值,现在用 node 得不到。你给的例子,salt 的都是 string 的,而这里 salt 是一个 bytes [], 这个会有关系吗?
    zhicheng
        27
    zhicheng  
       2017-12-19 23:43:03 +08:00
    @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
        28
    dennisge  
    OP
       2017-12-19 23:51:22 +08:00
    @zhicheng 感谢您的回答,但是您能得到这个最终的加密值吗? 79893503e8074330321974fa14dc44f8aa1b3df0。 我感觉和你用的方法没啥不一样啊,但就是得不到最后的值。是不是和原 java 实现的
    for (int i = 1; i < iterations; i++) {
    digest.reset();
    result = digest.digest(result);
    }
    有关系?
    dennisge
        29
    dennisge  
    OP
       2017-12-20 00:00:03 +08:00
    @zhicheng 如果只是你说的简单的方法,我觉得结果早就出来了。如果你能得到上面的这个加密值,那我闭嘴.
    neoblackcap
        30
    neoblackcap  
       2017-12-20 00:02:10 +08:00
    @dennisge 我看你这 Java 实现是对加盐并 sha1 处理一次后的二进制流再进行了 1024 次的 sha1 迭代。你试试用 node 版本对你现在的结果再进行 1024 次 sha1 看看
    dennisge
        31
    dennisge  
    OP
       2017-12-20 00:05:19 +08:00
    @neoblackcap java 是以前别人的代码。并没有理解透。能麻烦您你解释下吗
    zhicheng
        32
    zhicheng  
       2017-12-20 00:06:45 +08:00
    @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
        33
    dennisge  
    OP
       2017-12-20 00:07:44 +08:00
    @zhicheng 你用 node 试试?
    zhicheng
        34
    zhicheng  
       2017-12-20 00:08:31 +08:00
    @dennisge 付钱不?
    dennisge
        35
    dennisge  
    OP
       2017-12-20 00:10:10 +08:00
    @zhicheng O(∩_∩)O 哈哈~,太感谢你了。你真的太好了~~~看了你的微博,送书计划真的很赞
    dennisge
        36
    dennisge  
    OP
       2017-12-20 00:32:55 +08:00
    @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
        37
    lcdtyph  
       2017-12-20 01:12:38 +08:00 via iPhone
    @dennisge 你这个 node 循环了 1024 次,上面 java 循环了 1023 次
    ryd994
        38
    ryd994  
       2017-12-20 03:40:49 +08:00 via Android
    循环 hash1024 次,真是意义不明
    反复 hash 只会减小值域不可能增加
    初中数学去哪了?
    ryd994
        39
    ryd994  
       2017-12-20 03:44:40 +08:00 via Android
    还有,就算是 1024 次 sha1 也是快的一比
    bcrypt 调调难度系数,分分钟超过你的兔子算法
    密码储存讲究的是慢,才能避免字典攻击
    dennisge
        40
    dennisge  
    OP
       2017-12-20 08:28:27 +08:00
    @lcdtyph 恩,1023 的也不好用。上面复制的之前的。
    dennisge
        41
    dennisge  
    OP
       2017-12-20 08:30:04 +08:00
    @ryd994 恩,因为 java 代码是以前别人 java 实现了。现在我们要 node 重写,只能按以前的破逻辑重写了。不过你说的 bcrypt 会更好吗,还会引入 node-gyp
    dexterlei
        42
    dexterlei  
       2017-12-20 09:08:06 +08:00
    我的经验是,总可以发现是自己写错了
    dennisge
        43
    dennisge  
    OP
       2017-12-20 09:26:22 +08:00
    @zhicheng 感谢大神,终于成功了!!
    kohos
        44
    kohos  
       2017-12-20 09:31:29 +08:00
    这种加盐迭代 sha1 的方法应该就是 pbkdf2 算法吧……恭喜解决问题
    dennisge
        45
    dennisge  
    OP
       2017-12-20 09:39:15 +08:00
    @kohos 对啊,node 现在建议的也是 pbkdf2。我看 @zhicheng 的文章也是。但因为重写 java 的实现,不能改以前的逻辑。
    vefawn1
        46
    vefawn1  
       2017-12-20 09:46:38 +08:00 via Android
    我很好奇,为何打开这个页面后网页背景变黑了?
    quickma
        47
    quickma  
       2017-12-20 10:12:38 +08:00
    @vefawn1 node 节点自带出场背景

    原则 2:所有编程的技术问题,统统自己找答案
    pusadao
        48
    pusadao  
       2017-12-20 10:21:56 +08:00
    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
        49
    hantsy  
       2017-12-20 11:53:12 +08:00
    不同语言加密结果不一样的可能性不大。

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

    1. crypt
    2. salt
    3. hash
    等等
    dennisge
        51
    dennisge  
    OP
       2017-12-20 12:43:20 +08:00
    @hantsy 是的,这方便深究还挺多要点的
    dennisge
        52
    dennisge  
    OP
       2017-12-20 12:44:37 +08:00
    @pusadao 赞,后来也是这样的。关键对于 node 的 digest,以及后面的多次加密没理解透。
    dennisge
        53
    dennisge  
    OP
       2017-12-20 12:45:14 +08:00
    @x7395759 对的~
    metrxqin
        54
    metrxqin  
       2017-12-20 15:46:13 +08:00
    `高手` **如云**!
    edsgerlin
        55
    edsgerlin  
       2017-12-22 10:12:52 +08:00
    密码加密乖乖用 PBKDF2, BCrypt, Argon2 这些专业的 KDF,别自己瞎搞。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2561 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 04:44 PVG 12:44 LAX 21:44 JFK 00:44
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86