summaryrefslogtreecommitdiff
path: root/lib/srp/session.rb
blob: b61058b29aff258db57769fcaf974e2cd8e2a328 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
require File.expand_path(File.dirname(__FILE__) + '/util')

module SRP
  class Session
    include Util
    attr_accessor :user, :aa, :bb

    def initialize(user, aa=nil)
      @user = user
      aa ? initialize_server(aa) : initialize_client
    end

    # client -> server: I, A = g^a
    def handshake(server)
      @bb = server.handshake(user.username, aa)
      @u = calculate_u
    end

    # client -> server: M = H(H(N) xor H(g), H(I), s, A, B, K)
    def validate(server)
      server.validate(calculate_m(client_secret))
    end

    def authenticate!(m)
      authenticate(m) || raise(SRP::WrongPassword)
    end

    def authenticate(m)
      if(m == calculate_m(server_secret))
        return m2
      end
    end

    protected

    def initialize_server(aa)
      @aa = aa
      @b = bigrand(32).hex
      # B = g^b + k v (mod N)
      @bb = (modpow(GENERATOR, @b) + multiplier * @user.verifier) % BIG_PRIME_N
      @u = calculate_u
    end

    def initialize_client
      @a = bigrand(32).hex
      @aa = modpow(GENERATOR, @a) # A = g^a (mod N)
    end

    # client: K = H( (B - kg^x) ^ (a + ux) )
    def client_secret
      base = @bb
      # base += BIG_PRIME_N * @multiplier
      base -= modpow(GENERATOR, @user.private_key) * multiplier
      base = base % BIG_PRIME_N
      modpow(base, @user.private_key * @u + @a)
    end

    # server: K = H( (Av^u) ^ b )
    # do not cache this - it's secret and someone might store the
    # session in a CookieStore
    def server_secret
      base = (modpow(@user.verifier, @u) * @aa) % BIG_PRIME_N
      modpow(base, @b)
    end

    def m1
      calculate_m(server_secret)
    end

    def m2
      sha256_int(@aa, m1, server_secret).hex
    end

    # this is outdated - SRP 6a uses
    # M = H(H(N) xor H(g), H(I), s, A, B, K)
    def calculate_m(s)
      sha256_int(@aa, @bb, s).hex
    end

    def calculate_u
      sha256_int(@aa, @bb).hex
    end
  end
end