ruby_home-srp 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 01aa88f20f9d30e522a70b7b9b5fb46c0a88c72e17ed8497508673a49e3f4c81
4
+ data.tar.gz: be1162da69b86dbc69ac9a54f878ff10ff825691549058028e110c8f174f9e8d
5
+ SHA512:
6
+ metadata.gz: be13ad8ed43883b4c1bda4362481edcfe4ea1873afba34942157bf2a44b114672db9f783d7aa96dd6b5a0a640590b3b89b055381b2cb2e2bdcc63a53111fd4ce
7
+ data.tar.gz: ffffd98cda85809b6da6b921d39093acd974f379d9c6b877a5ab3a97b3fffebc3ade15179309ec837f82ec0203950c5793fbcc1759cea491972f1532109e4be6
@@ -0,0 +1,180 @@
1
+ require 'securerandom'
2
+ require 'srp'
3
+
4
+ module RubyHome
5
+ module SRP
6
+ class << self
7
+ ::SRP.singleton_methods.each do |m|
8
+ define_method m, ::SRP.method(m).to_proc
9
+ end
10
+ end
11
+
12
+ class << self
13
+ def sha512_hex(h)
14
+ OpenSSL::Digest::SHA512.hexdigest([h].pack('H*'))
15
+ end
16
+
17
+ def sha512_str(s)
18
+ OpenSSL::Digest::SHA512.hexdigest(s)
19
+ end
20
+
21
+ # hashing function with padding.
22
+ # Input is prefixed with 0 to meet N hex width.
23
+ def H(n, *a)
24
+ nlen = 2 * ((('%x' % [n]).length * 4 + 7) >> 3)
25
+ hashin = a.map {|s|
26
+ next unless s
27
+ shex = s.class == String ? s : '%x' % s
28
+ if shex.length > nlen
29
+ raise 'Bit width does not match - client uses different prime'
30
+ end
31
+ '0' * (nlen - shex.length) + shex
32
+ }.join('')
33
+ sha512_hex(hashin).hex % n
34
+ end
35
+
36
+ # Multiplier parameter
37
+ # k = H(N, g) (in SRP-6a)
38
+ def calc_k(n, g)
39
+ H(n, n, g)
40
+ end
41
+
42
+ # Private key (derived from username, raw password and salt)
43
+ # x = H(salt || H(username || ':' || password))
44
+ def calc_x(username, password, salt)
45
+ sha512_hex(salt + sha512_str([username, password].join(':'))).hex
46
+ end
47
+
48
+ # Random scrambling parameter
49
+ # u = H(A, B)
50
+ def calc_u(xaa, xbb, n)
51
+ H(n, xaa, xbb)
52
+ end
53
+
54
+ # M = H(H(N) xor H(g), H(I), s, A, B, K)
55
+ def calc_M(username, xsalt, xaa, xbb, xkk, n, g)
56
+ hn = sha512_hex('%x' % n).hex
57
+ hg = sha512_hex(g).hex
58
+ hxor = '%x' % (hn ^ hg)
59
+ hi = sha512_str(username)
60
+
61
+ hashin = [hxor, hi, xsalt, xaa, xbb, xkk].join
62
+ sha512_hex(hashin).hex % n
63
+ end
64
+
65
+ # H(A, M, K)
66
+ def calc_H_AMK(xaa, xmm, xkk, n, g)
67
+ hashin = [xaa, xmm, xkk].join()
68
+ sha512_hex(hashin).hex % n
69
+ end
70
+
71
+ def Ng(group)
72
+ case group
73
+ when 3072
74
+ @N = %w{
75
+ FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
76
+ 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
77
+ 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
78
+ A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
79
+ 49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
80
+ FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
81
+ 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
82
+ 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
83
+ 3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
84
+ 04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
85
+ B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
86
+ 1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
87
+ BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
88
+ E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
89
+ }.join.hex
90
+ @g = '05'
91
+ else
92
+ raise NotImplementedError
93
+ end
94
+ return [@N, @g]
95
+ end
96
+ end
97
+
98
+ class Verifier < ::SRP::Verifier
99
+ attr_reader :u
100
+ attr_writer :salt
101
+
102
+ def initialize group=3072
103
+ # select modulus (N) and generator (g)
104
+ @N, @g = SRP.Ng group
105
+ @k = SRP.calc_k(@N, @g)
106
+ end
107
+
108
+ # Initial user creation for the persistance layer.
109
+ # Not part of the authentication process.
110
+ # Returns { <username>, <password verifier>, <salt> }
111
+ def generate_userauth username, password
112
+ @salt ||= random_salt
113
+ x = SRP.calc_x(username, password, @salt)
114
+ v = SRP.calc_v(x, @N, @g.hex)
115
+ return {:username => username, :verifier => '%x' % v, :salt => @salt}
116
+ end
117
+
118
+ # Authentication phase 1 - create challenge.
119
+ # Returns Hash with challenge for client and proof to be stored on server.
120
+ # Parameters should be given in hex.
121
+ def get_challenge_and_proof username, xverifier, xsalt
122
+ generate_B(xverifier)
123
+ return {
124
+ :challenge => {:B => @B, :salt => xsalt},
125
+ :proof => {:B => @B, :b => '%x' % @b, :I => username, :s => xsalt, :v => xverifier}
126
+ }
127
+ end
128
+
129
+ # returns H_AMK on success, None on failure
130
+ # User -> Host: M = H(H(N) xor H(g), H(I), s, A, B, K)
131
+ # Host -> User: H(A, M, K)
132
+ def verify_session proof, client_M
133
+ @A = proof[:A]
134
+ @B = proof[:B]
135
+ @b = proof[:b].to_i(16)
136
+ username = proof[:I]
137
+ xsalt = proof[:s]
138
+ v = proof[:v].to_i(16)
139
+
140
+ @u = SRP.calc_u(@A, @B, @N)
141
+ # SRP-6a safety check
142
+ return false if @u == 0
143
+
144
+ # calculate session key
145
+ @S = '%x' % SRP.calc_server_S(@A.to_i(16), @b, v, @u, @N)
146
+ @K = SRP.sha512_hex(@S)
147
+
148
+ # calculate match
149
+ @M = '%x' % SRP.calc_M(username, xsalt, @A, @B, @K, @N, @g)
150
+
151
+ if @M == client_M
152
+ # authentication succeeded
153
+ @H_AMK = '%x' % SRP.calc_H_AMK(@A, @M, @K, @N, @g)
154
+ return @H_AMK
155
+ end
156
+ return false
157
+ end
158
+
159
+ def random_salt
160
+ SecureRandom.hex(16)
161
+ end
162
+
163
+ def random_bignum
164
+ SecureRandom.hex(32).hex
165
+ end
166
+
167
+ def u
168
+ '%x' % @u
169
+ end
170
+
171
+ # generates challenge
172
+ # input verifier in hex
173
+ def generate_B xverifier
174
+ v = xverifier.to_i(16)
175
+ @b ||= random_bignum
176
+ @B = '%x' % SRP.calc_B(@b, k, v, @N, @g.hex)
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,5 @@
1
+ module RubyHome
2
+ module SRP
3
+ VERSION = '1.1.1'
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ require 'bundler/setup'
2
+ require 'rspec'
3
+
4
+ RSpec.configure do |config|
5
+ # Disable RSpec exposing methods globally on `Module` and `main`
6
+ config.disable_monkey_patching!
7
+
8
+ config.expect_with :rspec do |c|
9
+ c.syntax = :expect
10
+ end
11
+
12
+ config.order = :random
13
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_home-srp
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Karl Entwistle
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: srp-rb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: 'Secure Remote Password protocol (SRP-6a) with HAP modifications
56
+
57
+ '
58
+ email:
59
+ - karl@entwistle.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - lib/ruby_home-srp.rb
65
+ - lib/ruby_home-srp/version.rb
66
+ - spec/spec_helper.rb
67
+ homepage: https://github.com/karlentwistle/ruby_home-srp
68
+ licenses: []
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.7.5
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Secure Remote Password protocol SRP-6a-HAP
90
+ test_files:
91
+ - spec/spec_helper.rb