我正在尝试使用加密模块在Erlang中实现SRP6,但我无法获得匹配的会话密钥。我使用的是256位素数。当我使用1024位素数时,它们匹配。我在crypto:compute_key中遗漏了可选的scrambler参数,但没有区别。
任何人都可以帮我弄清楚我的会话密钥不匹配的原因吗?
-module(srp).
-export([test/0]).
getUsername() -> <<"alice">>.
getPassword() -> <<"password123">>.
getSalt() -> <<"mystrongsalt">>.
getGenerator() -> <<7>>.
%% srp version 6
getVersion() -> '6'.
% randomly generated 32 byte number
getClientPrivate() ->
<<16#C49F832EE8D67ECF9E7F2785EB0622D8B3FE2344C00F96E1AEF4103CA44D51F9:256>>.
% randomly generated 32 byte number
getServerPrivate() ->
<<16#6C78CCEAAEC15E69068A87795B2A20ED7B45CFC5A254EBE2F17F144A4D99DB18:256>>.
%% 32 byte prime number
%% used in mangos: https://github.com/mangoszero/server/blob/master/src/realmd/AuthSocket.cpp#L190
%% used in arcemu: http://arcemu.org/wiki/Server_Logon_Challenge
getPrime() ->
<<16#894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7:256>>.
%% v = g^x
getVerifier() ->
Generator = getGenerator(),
Prime = getPrime(),
DerivedKey = getDerivedKey(),
crypto:mod_pow(Generator, DerivedKey, Prime).
%% x = H(salt, H(username, :, password))
getDerivedKey() ->
Username = getUsername(),
Password = getPassword(),
Salt = getSalt(),
crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]).
%% client public key
getClientPublic() ->
PrivateKey = getClientPrivate(),
Generator = getGenerator(),
Prime = getPrime(),
Version = getVersion(),
{Pub, PrivateKey} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, PrivateKey),
Pub.
%% server public key
getServerPublic() ->
PrivateKey = getServerPrivate(),
Generator = getGenerator(),
Prime = getPrime(),
Version = getVersion(),
Verifier = getVerifier(),
{Pub, PrivateKey} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivateKey),
Pub.
%% client session key
computeClientKey() ->
ServerPublic = getServerPublic(),
ClientPrivate = getClientPrivate(),
ClientPublic = getClientPublic(),
Generator = getGenerator(),
Prime = getPrime(),
Version = getVersion(),
DerivedKey = getDerivedKey(),
crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, {user, [DerivedKey, Prime, Generator, Version]}).
%% server session key
computeServerKey() ->
ClientPublic = getClientPublic(),
ServerPrivate = getServerPrivate(),
ServerPublic = getServerPublic(),
Prime = getPrime(),
Version = getVersion(),
Verifier = getVerifier(),
crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, {host, [Verifier, Prime, Version]}).
test() ->
%% these session keys should match
ClientKey = computeClientKey(),
ServerKey = computeServerKey(),
io:format("client skey: ~p~n", [ClientKey]),
io:format("server skey: ~p~n", [ServerKey]),
ClientKey == ServerKey.
gist可以在https://gist.github.com/jcclinton/4cdc9f616927677737a2
找到答案 0 :(得分:1)
不幸的是,这是影响客户端密钥计算的OTP SRP实现中的一个错误。
有一个修复程序: https://github.com/erlang/otp/pull/369
或者,您可以自己计算客户端密钥,这些内容也是如此。
computeClientKey() ->
ServerPublic = getServerPublic(),
ClientPrivate = getClientPrivate(),
ClientPublic = getClientPublic(),
Generator = getGenerator(),
Prime = getPrime(),
Version = getVersion(),
DerivedKey = getDerivedKey(),
Multiplier = getMultiplier(Version, Generator, Prime),
U = crypto:hash(sha, [padded(ClientPublic, Prime), padded(ServerPublic, Prime)]),
PrimeI = bin_to_int(Prime),
BX = crypto:mod_pow(Generator, DerivedKey, Prime),
BTMPI0 = bin_to_int(ServerPublic) - bin_to_int(Multiplier) * bin_to_int(BX),
BTMPI = BTMPI0 rem PrimeI,
Base = if
BTMPI > 0 -> int_to_bin(BTMPI);
true -> int_to_bin(BTMPI + PrimeI)
end,
Exponent = int_to_bin(bin_to_int(ClientPrivate) + bin_to_int(U) * bin_to_int(DerivedKey)),
crypto:mod_pow(Base, Exponent, Prime).
padded(V, N) when byte_size(V) =:= byte_size(N) -> V;
padded(V, N) when byte_size(V) < byte_size(N) ->
NLen = byte_size(N),
PadLen = (NLen - byte_size(V)) * 8,
Pad = <<0:PadLen>>,
[Pad, V].
int_to_bin(Int) ->
Len0 = length(erlang:integer_to_list(Int, 16)),
Len1 = Len0 + (Len0 rem 2),
Bits = Len1 * 4,
<<Int:Bits>>.
bin_to_int(Bin) ->
Bits = byte_size(Bin) * 8,
<<Val:Bits>> = Bin,
Val.
getMultiplier('6a', Generator, Prime) ->
crypto:hash(sha, [Prime, padded(Generator, Prime)]);
getMultiplier('6', _Generator, _Prime) ->
<<3/integer>>;
getMultiplier('3', _Generator, _Prime) ->
<<1/integer>>.