为鳄梨酱生成哈希密码
Guacamole 提供默认用户名和密码(guacadmin
和 guacadmin) 在 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';
我试图了解密码哈希是如何生成的。从文档中:
每个用户在 guacamole_user 和 guacamole_entity 表中都有一个相应的条目。每个用户都有一个相应的唯一用户名(通过 guacamole_entity 指定)和加盐密码。加盐密码分为两列:一列包含盐,另一列包含使用 SHA-256 哈希的密码。
[...]
密码哈希
使用 SHA-256 对用户密码与 password_salt 的内容进行哈希处理的结果。在散列之前,盐会附加到密码中。
password_salt
32 字节随机值。当从网络界面创建新用户时,该值是使用加密安全随机数生成器随机生成的。
我认为相应的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 代码?
Guacamole provides a default username and password (guacadmin
and guacadmin
) initialized in a postgres database like this:
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';
I'm trying to to understand how that password hash was generated. From the documentation:
Every user has a corresponding entry in the guacamole_user and guacamole_entity tables. Each user has a corresponding unique username, specified via guacamole_entity, and salted password. The salted password is split into two columns: one containing the salt, and the other containing the password hashed with SHA-256.
[...]
password_hash
The result of hashing the user’s password concatenated with the contents of password_salt using SHA-256. The salt is appended to the password prior to hashing.
password_salt
A 32-byte random value. When a new user is created from the web interface, this value is randomly generated using a cryptographically-secure random number generator.
And I think the corresponding Java code is here:
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();
I'm trying to reproduce this in Python. It looks like they're taking
the password, appending the hex-encoded salt, and then calculating the
sha256 checksum of the resulting byte string. That should be this:
>>> from hashlib import sha256
>>> password_salt = bytes.fromhex('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264')
>>> password_hash = sha256('guacadmin'.encode() + password_salt.hex().encode())
>>> password_hash.hexdigest()
'523912c05f1557e2da15350fae7217c04ee326edacfaa116248c1ee4e680bd57'
...but I'm not getting the same result. Am I misreading (or
misunderstanding) the Java code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
...当然,我在发布问题后就明白了。区别在于
BaseEncoding.base16().encode(...)
使用大写字符生成十六进制编码,而 Python 的hex()
方法使用小写字符。这意味着等效的代码实际上是:万一有人偶然发现同样的问题,我能够将 Java 代码提取到一个简单的测试用例中:
这给了我一些可以交互式运行并检查输出的东西。这需要 guava 库,并且可以像这样编译:
并像这样运行:
...and of course I figured it out right after posting the question. The difference is that
BaseEncoding.base16().encode(...)
produces a hex encoding using upper-case characters, while Python'shex()
method uses lower case. That means the equivalent code is in fact:In case anyone stumbles across the same issue, I was able to extract the Java code into a simple test case:
This gave me something to run interactively and check the output. This requires the guava library, and can be compiled like this:
And run like this:
我写了这个方法,并且对最新的 apache guacamole 有效。
I wrote this method and is valid for the latest apache guacamole.