2014-05-13 2 views
1

암호화 모듈을 사용하여 Erlang에서 SRP6을 구현하려고하지만 세션 키를 일치시킬 수 없습니다. 256 비트 소수를 사용하고 있습니다. 1024 비트 소수를 사용할 때 그들은 일치합니다. 암호화에서 선택적 스크램블러 매개 변수를 생략했습니다 : compute_key,하지만 차이는 없습니다.SRP6의 다른 세션 키

누군가 내 세션 키가 일치하지 않는 이유를 알아낼 수 있습니까?

-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. 

요점은 https://gist.github.com/jcclinton/4cdc9f616927677737a2

답변

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>>.