繁体   English   中英

为鳄梨酱生成散列密码

[英]Generating hashed passwords for Guacamole

Guacamole提供了一个默认的用户名和密码( guacadminguacadmin ),这些用户名和密码在 postgres 数据库中初始化,如下所示:

INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
SELECT
    entity_id,
    decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'),  -- 'guacadmin'
    decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'),
    CURRENT_TIMESTAMP
FROM guacamole_entity WHERE name = 'guacadmin' AND guacamole_entity.type = 'USER';

我试图了解密码 hash 是如何生成的。 从文档中:

每个用户在 guacamole_user 和 guacamole_entity 表中都有对应的条目。 每个用户都有一个相应的唯一用户名,通过 guacamole_entity 和加盐密码指定。 加盐密码分为两列:一列包含盐,另一列包含用 SHA-256 散列的密码。

[...]

password_hash

使用 SHA-256 散列用户密码与 password_salt 的内容的结果。 在散列之前将盐附加到密码。

password_salt

一个 32 字节的随机值。 当从 web 接口创建新用户时,该值是使用加密安全随机数生成器随机生成的。

我认为相应的 Java 代码在这里

            StringBuilder builder = new StringBuilder();
            builder.append(password);

            if (salt != null)
                builder.append(BaseEncoding.base16().encode(salt));

            // Hash UTF-8 bytes of possibly-salted password
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(builder.toString().getBytes("UTF-8"));
            return md.digest();

我试图在 Python 中重现这一点。看起来他们正在获取密码,附加十六进制编码的盐,然后计算生成的字节字符串的 sha256 校验和。 那应该是这样的:

>>> from hashlib import sha256
>>> password_salt = bytes.fromhex('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264')
>>> password_hash = sha256('guacadmin'.encode() + password_salt.hex().encode())
>>> password_hash.hexdigest()
'523912c05f1557e2da15350fae7217c04ee326edacfaa116248c1ee4e680bd57'

...但我没有得到相同的结果。 我是否误读(或误解)了 Java 代码?

...当然,我在发布问题后就想通了。 区别在于BaseEncoding.base16().encode(...)使用大写字符生成十六进制编码,而 Python 的hex()方法使用小写。 这意味着等效代码实际上是:

>>> from hashlib import sha256
>>> password_salt = bytes.fromhex('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264')
>>> password_hash = sha256("guacadmin".encode() + password_salt.hex().upper().encode())
>>> password_hash.hexdigest()
'ca458a7d494e3be824f5e1e175a1556c0f8eef2c2d7df3633bec4a29c4411960'

万一有人遇到同样的问题,我能够将 Java 代码提取到一个简单的测试用例中:

import com.google.common.io.BaseEncoding;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;

class Main {  
  public static void main(String args[]) { 
      String password = "guacadmin";
      byte[] salt = HexFormat.of().parseHex("FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264");

    try {
            StringBuilder builder = new StringBuilder();
            builder.append(password);

            if (salt != null)
                builder.append(BaseEncoding.base16().encode(salt));

        System.out.println("builder is: " + builder.toString());

            // Hash UTF-8 bytes of possibly-salted password
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(builder.toString().getBytes("UTF-8"));
        System.out.println(BaseEncoding.base16().encode(md.digest()));
    }
    catch (UnsupportedEncodingException e) {
        System.out.println("no such encoding");
    }
    catch (NoSuchAlgorithmException e) {
        System.out.println("no such algorithm");
    }
  } 
}

这给了我一些东西来交互运行并检查 output。这需要番石榴库,并且可以像这样编译:

$ javac -classpath .:guava-31.1-jre.jar -d . Main.java

像这样运行:

$ java -classpath .:guava-31.1-jre.jar Main

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM