MongooseIM/ejabberd: 使用 scram 的 http 身份验证
MongooseIM/ejabberd: http auth using scram
我目前正在尝试使用 MongooseIM 并希望将 HTTP 身份验证与 scram 一起使用。我正在使用 python passlib 创建 scram 哈希:
import sys
from passlib.hash import scram
def main():
hash = scram.encrypt(sys.argv[1], rounds=4096, salt_size=16)
print hash
if __name__ == "__main__":
main()
然后我得到这样的结果:
$scram96$BmAsRcgZA4AwRijl3FtLyQ$sha-1=AXh5FzYzEnf6PaVQNR79AZhkwz8,sha-256=YZceXCVhfCBrr8sM9k3eS.5bztHugerGzjO97emvn20,sha-512=2NyVspiE7MP6xBAEycAV5Z/nIbBlki3sHfWvVUPPnEkMt5b4VbZfDZ0s8lvE/ns0scPGWmfKhUobmZbjfFH6RA
很遗憾,MongooseIM 的 HTTP 验证不接受这种格式。我查看了代码并试图找出 scram 哈希密码的序列化形式在此处的样子:https://github.com/esl/MongooseIM/blob/master/apps/ejabberd/src/scram.erl
deserialize(<<?SCRAM_SERIAL_PREFIX, Serialized/binary>>) ->
case catch binary:split(Serialized, <<",">>, [global]) of
[StoredKey, ServerKey,Salt,IterationCount] ->
{ok, #scram{storedkey = StoredKey,
serverkey = ServerKey,
salt = Salt,
iterationcount = binary_to_integer(IterationCount)}};
_ ->
?WARNING_MSG("Incorrect serialized SCRAM: ~p, ~p", [Serialized]),
{error, incorrect_scram}
end;
据我所知,从 passlib 中我得到了加盐(散列)密码的加盐、迭代计数和实际摘要(sha-1、sha-256、sha-512),但是 StoredKey 呢和Erlang代码中的ServerKey? host/get_password 返回的正确的序列化 HTTP 正文会是什么样子?
提前致谢,
马格努斯
这是一个很好的问题,实际上让我意识到我们没有记录它。我们会修复它。
目前预期的格式如下所示(您可以使用 MongooseIM 的调试 shell 来生成它)。
scram:serialize(scram:password_to_scram(<<"ala_ma_kota">>, 4096)).
<<"==SCRAM==,xB2++RvZklv0rV5I1iuCpoxLqL0=,sKXBkOFrtyGxKqYo/dlzeKfYszU=,oplvMJ5VDxQ7rJZuIj0ZfA==,4096">>
换句话说,MongooseIM 期望格式为:
==SCRAM==,StoredKey,ServerKey,Salt,IterationCount
==SCRAM==前缀不变,其他部分取决于密码。
希望对您有所帮助。
所以我想通了并写了一个小 python 脚本来生成预期的格式。
import base64
import hashlib
import hmac
import sys
from passlib.hash import scram
# password_to_scram(Password, IterationCount) ->
# Salt = crypto:rand_bytes(?SALT_LENGTH),
# SaltedPassword = salted_password(Password, Salt, IterationCount),
# StoredKey = stored_key(scram:client_key(SaltedPassword)),
# ServerKey = server_key(SaltedPassword),
# #scram{storedkey = base64:encode(StoredKey),
# serverkey = base64:encode(ServerKey),
# salt = base64:encode(Salt),
# iterationcount = IterationCount}.
def main():
rounds = 4096
hash = scram.encrypt(sys.argv[1], rounds=rounds, salt_size=16)
hash = scram.encrypt('1234', rounds=rounds, salt='salt')
salt, iterations, salted_password = scram.extract_digest_info(hash, "sha-1")
# server_key(SaltedPassword) ->
# crypto:hmac(sha, SaltedPassword, <<"Server Key">>).
server_key = hmac.new(key=salted_password, msg='Server Key', digestmod=hashlib.sha1).digest()
# client_key(SaltedPassword) ->
# crypto:hmac(sha, SaltedPassword, <<"Client Key">>).
client_key = hmac.new(key=salted_password, msg='Client Key', digestmod=hashlib.sha1).digest()
# StoredKey = stored_key(scram:client_key(SaltedPassword)),
stored_key = hashlib.sha1(client_key).digest()
result = '==SCRAM==,%s,%s,%s,%d' % \
(base64.b64encode(stored_key), base64.b64encode(server_key), base64.b64encode(salt), rounds)
print result
if __name__ == '__main__':
main()
验证:
(mongooseim@localhost)2> base64:encode(scram:salted_password(<<"1234">>, <<"salt">>, 4096)).
<<"vbpf4gmRPxs/+ru4TZJO3toJdw0=">>
(mongooseim@localhost)4> base64:encode(scram:stored_key(scram:client_key(scram:salted_password(<<"1234">>, <<"salt">>, 4096)))).
<<"bXKEekOUoWNAx0f21H/fIZ4dj6Y=">>
(mongooseim@localhost)3> base64:encode(scram:server_key(scram:salted_password(<<"1234">>, <<"salt">>, 4096))).
<<"eVwl7wTir232HDy7Tzq3SXZHn+4=">>
==SCRAM==,bXKEekOUoWNAx0f21H/fIZ4dj6Y=,eVwl7wTir232HDy7Tzq3SXZHn+4=,c2FsdA==,4096
我目前正在尝试使用 MongooseIM 并希望将 HTTP 身份验证与 scram 一起使用。我正在使用 python passlib 创建 scram 哈希:
import sys
from passlib.hash import scram
def main():
hash = scram.encrypt(sys.argv[1], rounds=4096, salt_size=16)
print hash
if __name__ == "__main__":
main()
然后我得到这样的结果:
$scram96$BmAsRcgZA4AwRijl3FtLyQ$sha-1=AXh5FzYzEnf6PaVQNR79AZhkwz8,sha-256=YZceXCVhfCBrr8sM9k3eS.5bztHugerGzjO97emvn20,sha-512=2NyVspiE7MP6xBAEycAV5Z/nIbBlki3sHfWvVUPPnEkMt5b4VbZfDZ0s8lvE/ns0scPGWmfKhUobmZbjfFH6RA
很遗憾,MongooseIM 的 HTTP 验证不接受这种格式。我查看了代码并试图找出 scram 哈希密码的序列化形式在此处的样子:https://github.com/esl/MongooseIM/blob/master/apps/ejabberd/src/scram.erl
deserialize(<<?SCRAM_SERIAL_PREFIX, Serialized/binary>>) ->
case catch binary:split(Serialized, <<",">>, [global]) of
[StoredKey, ServerKey,Salt,IterationCount] ->
{ok, #scram{storedkey = StoredKey,
serverkey = ServerKey,
salt = Salt,
iterationcount = binary_to_integer(IterationCount)}};
_ ->
?WARNING_MSG("Incorrect serialized SCRAM: ~p, ~p", [Serialized]),
{error, incorrect_scram}
end;
据我所知,从 passlib 中我得到了加盐(散列)密码的加盐、迭代计数和实际摘要(sha-1、sha-256、sha-512),但是 StoredKey 呢和Erlang代码中的ServerKey? host/get_password 返回的正确的序列化 HTTP 正文会是什么样子?
提前致谢, 马格努斯
这是一个很好的问题,实际上让我意识到我们没有记录它。我们会修复它。
目前预期的格式如下所示(您可以使用 MongooseIM 的调试 shell 来生成它)。
scram:serialize(scram:password_to_scram(<<"ala_ma_kota">>, 4096)).
<<"==SCRAM==,xB2++RvZklv0rV5I1iuCpoxLqL0=,sKXBkOFrtyGxKqYo/dlzeKfYszU=,oplvMJ5VDxQ7rJZuIj0ZfA==,4096">>
换句话说,MongooseIM 期望格式为:
==SCRAM==,StoredKey,ServerKey,Salt,IterationCount
==SCRAM==前缀不变,其他部分取决于密码。
希望对您有所帮助。
所以我想通了并写了一个小 python 脚本来生成预期的格式。
import base64
import hashlib
import hmac
import sys
from passlib.hash import scram
# password_to_scram(Password, IterationCount) ->
# Salt = crypto:rand_bytes(?SALT_LENGTH),
# SaltedPassword = salted_password(Password, Salt, IterationCount),
# StoredKey = stored_key(scram:client_key(SaltedPassword)),
# ServerKey = server_key(SaltedPassword),
# #scram{storedkey = base64:encode(StoredKey),
# serverkey = base64:encode(ServerKey),
# salt = base64:encode(Salt),
# iterationcount = IterationCount}.
def main():
rounds = 4096
hash = scram.encrypt(sys.argv[1], rounds=rounds, salt_size=16)
hash = scram.encrypt('1234', rounds=rounds, salt='salt')
salt, iterations, salted_password = scram.extract_digest_info(hash, "sha-1")
# server_key(SaltedPassword) ->
# crypto:hmac(sha, SaltedPassword, <<"Server Key">>).
server_key = hmac.new(key=salted_password, msg='Server Key', digestmod=hashlib.sha1).digest()
# client_key(SaltedPassword) ->
# crypto:hmac(sha, SaltedPassword, <<"Client Key">>).
client_key = hmac.new(key=salted_password, msg='Client Key', digestmod=hashlib.sha1).digest()
# StoredKey = stored_key(scram:client_key(SaltedPassword)),
stored_key = hashlib.sha1(client_key).digest()
result = '==SCRAM==,%s,%s,%s,%d' % \
(base64.b64encode(stored_key), base64.b64encode(server_key), base64.b64encode(salt), rounds)
print result
if __name__ == '__main__':
main()
验证:
(mongooseim@localhost)2> base64:encode(scram:salted_password(<<"1234">>, <<"salt">>, 4096)).
<<"vbpf4gmRPxs/+ru4TZJO3toJdw0=">>
(mongooseim@localhost)4> base64:encode(scram:stored_key(scram:client_key(scram:salted_password(<<"1234">>, <<"salt">>, 4096)))).
<<"bXKEekOUoWNAx0f21H/fIZ4dj6Y=">>
(mongooseim@localhost)3> base64:encode(scram:server_key(scram:salted_password(<<"1234">>, <<"salt">>, 4096))).
<<"eVwl7wTir232HDy7Tzq3SXZHn+4=">>
==SCRAM==,bXKEekOUoWNAx0f21H/fIZ4dj6Y=,eVwl7wTir232HDy7Tzq3SXZHn+4=,c2FsdA==,4096