Class: SIRP::Client

Inherits:
Object
  • Object
show all
Includes:
SIRP
Defined in:
lib/sirp/client.rb

Constant Summary

Constants included from SIRP

VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SIRP

#H, #Ng, #calc_A, #calc_B, #calc_H_AMK, #calc_M, #calc_client_S, #calc_k, #calc_server_S, #calc_u, #calc_v, #calc_x, #hex_to_bytes, #mod_exp, #num_to_hex, #secure_compare, #sha_hex, #sha_str

Constructor Details

#initialize(group = 2048) ⇒ Client

Select modulus (N), generator (g), and one-way hash function (SHA1 or SHA256)

Parameters:

  • group (Integer) (defaults to: 2048)

    the group size in bits

Raises:

  • (ArgumentError)

9
10
11
12
13
14
15
# File 'lib/sirp/client.rb', line 9

def initialize(group = 2048)
  raise ArgumentError, 'must be an Integer' unless group.is_a?(Integer)
  raise ArgumentError, 'must be a known group size' unless [1024, 1536, 2048, 3072, 4096, 6144, 8192].include?(group)

  @N, @g, @hash = Ng(group)
  @k = calc_k(@N, @g, hash)
end

Instance Attribute Details

#AObject (readonly)

Returns the value of attribute A


4
5
6
# File 'lib/sirp/client.rb', line 4

def A
  @A
end

#aObject (readonly)

Returns the value of attribute a


4
5
6
# File 'lib/sirp/client.rb', line 4

def a
  @a
end

#gObject (readonly)

Returns the value of attribute g


4
5
6
# File 'lib/sirp/client.rb', line 4

def g
  @g
end

#H_AMKObject (readonly)

Returns the value of attribute H_AMK


4
5
6
# File 'lib/sirp/client.rb', line 4

def H_AMK
  @H_AMK
end

#hashObject (readonly)

Returns the value of attribute hash


4
5
6
# File 'lib/sirp/client.rb', line 4

def hash
  @hash
end

#kObject (readonly)

Returns the value of attribute k


4
5
6
# File 'lib/sirp/client.rb', line 4

def k
  @k
end

#KObject (readonly)

Returns the value of attribute K


4
5
6
# File 'lib/sirp/client.rb', line 4

def K
  @K
end

#MObject (readonly)

Returns the value of attribute M


4
5
6
# File 'lib/sirp/client.rb', line 4

def M
  @M
end

#NObject (readonly)

Returns the value of attribute N


4
5
6
# File 'lib/sirp/client.rb', line 4

def N
  @N
end

#SObject (readonly)

Returns the value of attribute S


4
5
6
# File 'lib/sirp/client.rb', line 4

def S
  @S
end

Instance Method Details

#process_challenge(username, password, xsalt, xbb) ⇒ String

Phase 2 : Step 1 : Process the salt and B values provided by the server.

Parameters:

  • username (String)

    the client provided authentication username

  • password (String)

    the client provided authentication password

  • xsalt (String)

    the server provided salt for the username in hex

  • xbb (String)

    the server verifier 'B' value in hex

Returns:

  • (String)

    the client 'M' value in hex

Raises:

  • (ArgumentError)

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
# File 'lib/sirp/client.rb', line 39

def process_challenge(username, password, xsalt, xbb)
  raise ArgumentError, 'username must be a string' unless username.is_a?(String) && !username.empty?
  raise ArgumentError, 'password must be a string' unless password.is_a?(String) && !password.empty?
  raise ArgumentError, 'xsalt must be a string' unless xsalt.is_a?(String)
  raise ArgumentError, 'xsalt must be a hex string' unless xsalt =~ /^[a-fA-F0-9]+$/
  raise ArgumentError, 'xbb must be a string' unless xbb.is_a?(String)
  raise ArgumentError, 'xbb must be a hex string' unless xbb =~ /^[a-fA-F0-9]+$/

  # Convert the 'B' hex value to an Integer
  bb = xbb.to_i(16)

  # SRP-6a safety check
  return false if (bb % @N).zero?

  x = calc_x(username, password, xsalt, hash)
  u = calc_u(@A, xbb, @N, hash)

  # SRP-6a safety check
  return false if u.zero?

  # Calculate session key 'S' and secret key 'K'
  @S = num_to_hex(calc_client_S(bb, @a, @k, x, u, @N, @g))
  @K = sha_hex(@S, hash)

  # Calculate the 'M' matcher
  @M = calc_M(@A, xbb, @K, hash)

  # Calculate the H(A,M,K) verifier
  @H_AMK = num_to_hex(calc_H_AMK(@A, @M, @K, hash))

  # Return the 'M' matcher to be sent to the server
  @M
end

#start_authenticationString

Phase 1 : Step 1 : Start the authentication process by generating the client 'a' and 'A' values. Public 'A' should later be sent along with the username, to the server verifier to continue the auth process. The internal secret 'a' value should remain private.

Returns:

  • (String)

    the value of 'A' in hex


23
24
25
26
# File 'lib/sirp/client.rb', line 23

def start_authentication
  @a ||= SecureRandom.hex(32).hex
  @A = num_to_hex(calc_A(@a, @N, @g))
end

#verify(server_HAMK) ⇒ true, false

Phase 2 : Step 3 : Verify that the server provided H(A,M,K) value matches the client generated version. This is the last step of mutual authentication and confirms that the client and server have completed the auth process. The comparison of local and server H_AMK values is done using a secure constant-time comparison method so as not to leak information.

Parameters:

  • server_HAMK (String)

    the server provided H_AMK in hex

Returns:

  • (true, false)

    returns true if the server and client agree on the H_AMK value, false if not


86
87
88
89
90
91
92
93
94
# File 'lib/sirp/client.rb', line 86

def verify(server_HAMK)
  return false unless @H_AMK && server_HAMK
  return false unless server_HAMK.is_a?(String)
  return false unless server_HAMK =~ /^[a-fA-F0-9]+$/

  # Hash the comparison params to ensure that both strings
  # being compared are equal length 32 Byte strings.
  secure_compare(Digest::SHA256.hexdigest(@H_AMK), Digest::SHA256.hexdigest(server_HAMK))
end