2016-02-26 53 views
1

我目前正在玩MongooseIM一点点,并希望与scram一起使用HTTP认证。我使用Python passlib创建急停散列:MongooseIM/ejabberd:http认证使用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() 

然后我结束了这样的事情:

$scram$4096$BmAsRcgZA4AwRijl3FtLyQ$sha-1=AXh5FzYzEnf6PaVQNR79AZhkwz8,sha-256=YZceXCVhfCBrr8sM9k3eS.5bztHugerGzjO97emvn20,sha-512=2NyVspiE7MP6xBAEycAV5Z/nIbBlki3sHfWvVUPPnEkMt5b4VbZfDZ0s8lvE/ns0scPGWmfKhUobmZbjfFH6RA 

不幸的是这种格式不MongooseIM的HTTP认证所接受。我看了一下代码,并试图找出急停的serialzed形式如何散列密码,看起来像在这里: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),据我所知,但是从Erlang代码的StoredKey和ServerKey呢?如何通过host/get_password返回正确的序列化HTTP主体?

由于提前, 马格努斯

回答

1

所以我想通了,写了一个小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() 

验证:

([email protected])2> base64:encode(scram:salted_password(<<"1234">>, <<"salt">>, 4096)).  
<<"vbpf4gmRPxs/+ru4TZJO3toJdw0=">> 

([email protected])4> base64:encode(scram:stored_key(scram:client_key(scram:salted_password(<<"1234">>, <<"salt">>, 4096)))). 
<<"bXKEekOUoWNAx0f21H/fIZ4dj6Y=">> 

([email protected])3> base64:encode(scram:server_key(scram:salted_password(<<"1234">>, <<"salt">>, 4096))). 
<<"eVwl7wTir232HDy7Tzq3SXZHn+4=">> 

==SCRAM==,bXKEekOUoWNAx0f21H/fIZ4dj6Y=,eVwl7wTir232HDy7Tzq3SXZHn+4=,c2FsdA==,4096 
2

这实际上让我意识到,我们没有它证明一个很好的问题。我们会解决它。至于现在预期的格式如下所示(您可以使用MongooseIM的调试外壳来生成它)。

scram:serialize(scram:password_to_scram(<<"ala_ma_kota">>, 4096)). 
<<"==SCRAM==,xB2++RvZklv0rV5I1iuCpoxLqL0=,sKXBkOFrtyGxKqYo/dlzeKfYszU=,oplvMJ5VDxQ7rJZuIj0ZfA==,4096">> 

换句话说,MongooseIM期望的格式为:

==SCRAM==,StoredKey,ServerKey,Salt,IterationCount 

的== SCRAM ==前缀是恒定的,其它部分取决于密码。

希望有所帮助。

+0

谢谢,但究竟什么是StoredKey和ServerKey?如何使用我自己的认证服务从MongooseIM服务器中分离出相应的生成密码哈希? – Magnus

+0

您可以检查[password_to_scram](https://github.com/esl/MongooseIM/blob/master/apps/ejabberd/src/scram.erl#L139-L147)。基本上这个SCRAM认证方法是这里描述的SCRAM-SHA-1机制的实现[RFC 5802](https://tools.ietf.org/html/rfc5802) – michalwski

+0

我只注意到你已经知道了。干得好! – michalwski