srp-rb 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/srp-rb.rb +76 -40
- data/lib/srp-rb/version.rb +1 -1
- metadata +2 -2
data/lib/srp-rb.rb
CHANGED
@@ -43,13 +43,20 @@ require "srp-rb/version"
|
|
43
43
|
|
44
44
|
module SRP
|
45
45
|
class << self
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
|
47
|
+
attr_accessor :hash
|
48
|
+
|
49
|
+
def sha1_hex(h, hash)
|
50
|
+
h = '0' + h if h.size % 2 != 0
|
51
|
+
klass = hash == 'sha-256' ?
|
52
|
+
Digest::SHA256 : Digest::SHA1
|
53
|
+
klass.hexdigest([h].pack('H*'))
|
49
54
|
end
|
50
55
|
|
51
|
-
def sha1_str(s)
|
52
|
-
|
56
|
+
def sha1_str(s, hash)
|
57
|
+
klass = hash == 'sha-256' ?
|
58
|
+
Digest::SHA256 : Digest::SHA1
|
59
|
+
klass.hexdigest(s)
|
53
60
|
end
|
54
61
|
|
55
62
|
def bigrand(bytes)
|
@@ -70,6 +77,7 @@ module SRP
|
|
70
77
|
# SHA1 hashing function with padding.
|
71
78
|
# Input is prefixed with 0 to meet N hex width.
|
72
79
|
def H(n, *a)
|
80
|
+
hash = a.pop
|
73
81
|
nlen = 2 * ((('%x' % [n]).length * 4 + 7) >> 3)
|
74
82
|
hashin = a.map {|s|
|
75
83
|
next unless s
|
@@ -79,41 +87,56 @@ module SRP
|
|
79
87
|
end
|
80
88
|
"0" * (nlen - shex.length) + shex
|
81
89
|
}.join('')
|
82
|
-
|
90
|
+
# warn "HASH: #{hashin}"
|
91
|
+
sha1_hex(hashin, hash).hex % n
|
83
92
|
end
|
84
93
|
|
85
94
|
# Multiplier parameter
|
86
95
|
# k = H(N, g) (in SRP-6a)
|
87
|
-
def calc_k(n, g)
|
88
|
-
H(n, n, g)
|
96
|
+
def calc_k(n, g, hash)
|
97
|
+
k1 = H(n, n, g, hash)
|
98
|
+
# warn "n: #{n.to_s(16)}"
|
99
|
+
# warn "g: #{g.to_s}"
|
100
|
+
# warn "k: #{k1.to_s(16)}"
|
101
|
+
H(n, n, g, hash)
|
89
102
|
end
|
90
103
|
|
91
104
|
# Private key (derived from username, raw password and salt)
|
92
105
|
# x = H(salt || H(username || ':' || password))
|
93
|
-
def calc_x(username, password, salt)
|
106
|
+
def calc_x(username, password, salt, hash)
|
94
107
|
spad = if salt.length.odd? then '0' else '' end
|
95
|
-
sha1_hex(spad + salt + sha1_str([username, password].join(':'))).hex
|
108
|
+
x1 = sha1_hex(spad + salt + sha1_str([username, password].join(':')), hash).hex
|
109
|
+
# warn "x: #{x1.to_s(16)}"
|
110
|
+
sha1_hex(spad + salt + sha1_str([username, password].join(':'), hash), hash).hex
|
96
111
|
end
|
97
112
|
|
98
113
|
# Random scrambling parameter
|
99
114
|
# u = H(A, B)
|
100
|
-
def calc_u(xaa, xbb, n)
|
101
|
-
H(n, xaa, xbb)
|
115
|
+
def calc_u(xaa, xbb, n, hash)
|
116
|
+
u1 = H(n, xaa, xbb, hash)
|
117
|
+
# warn "u: #{u1.to_s(16)}"
|
118
|
+
H(n, xaa, xbb, hash)
|
102
119
|
end
|
103
120
|
|
104
121
|
# Password verifier
|
105
122
|
# v = g^x (mod N)
|
106
123
|
def calc_v(x, n, g)
|
124
|
+
v1 = modpow(g,x,n)
|
125
|
+
# warn "v: #{v1.to_s(16)}"
|
107
126
|
modpow(g, x, n)
|
108
127
|
end
|
109
128
|
|
110
129
|
# A = g^a (mod N)
|
111
130
|
def calc_A(a, n, g)
|
131
|
+
a1 = modpow(g,a,n)
|
132
|
+
# warn "A: #{a1.to_s(16)}"
|
112
133
|
modpow(g, a, n)
|
113
134
|
end
|
114
135
|
|
115
136
|
# B = g^b + k v (mod N)
|
116
137
|
def calc_B(b, k, v, n, g)
|
138
|
+
b1 = (modpow(g, b, n) + k * v) % n
|
139
|
+
# warn "B: #{b1.to_s(16)}"
|
117
140
|
(modpow(g, b, n) + k * v) % n
|
118
141
|
end
|
119
142
|
|
@@ -126,21 +149,23 @@ module SRP
|
|
126
149
|
# Server secret
|
127
150
|
# S = (A * v^u) ^ b % N
|
128
151
|
def calc_server_S(aa, b, v, u, n)
|
152
|
+
s1 = modpow((modpow(v, u, n) * aa), b, n)
|
153
|
+
# warn "S: #{s1.to_s(16)}"
|
129
154
|
modpow((modpow(v, u, n) * aa), b, n)
|
130
155
|
end
|
131
156
|
|
132
157
|
# M = H(H(N) xor H(g), H(I), s, A, B, K)
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
hi = sha1_str(username)
|
138
|
-
return H(n, hxor, hi, xsalt, xaa, xbb, xkk)
|
158
|
+
def calc_M1(xaa, xbb, xkk, n, hash)
|
159
|
+
m1 = H(n, xaa, xbb, xkk, hash)
|
160
|
+
# warn "M1: #{m1.to_s(16)}"
|
161
|
+
return H(n, xaa, xbb, xkk, hash)
|
139
162
|
end
|
140
163
|
|
141
164
|
# H(A, M, K)
|
142
|
-
def
|
143
|
-
H(n, xaa, xmm, xkk)
|
165
|
+
def calc_M2(xaa, xmm, xkk, n, hash)
|
166
|
+
m2 = H(n, xaa, xmm, xkk, hash)
|
167
|
+
# warn "M2: #{m2.to_s(16)}"
|
168
|
+
H(n, xaa, xmm, xkk, hash)
|
144
169
|
end
|
145
170
|
|
146
171
|
def Ng(group)
|
@@ -311,10 +336,11 @@ module SRP
|
|
311
336
|
class Verifier
|
312
337
|
attr_reader :N, :g, :k, :A, :B, :b, :S, :K, :M, :H_AMK
|
313
338
|
|
314
|
-
def initialize
|
339
|
+
def initialize(group = 1024, hash = 'sha-1')
|
315
340
|
# select modulus (N) and generator (g)
|
316
|
-
@N, @g = SRP.Ng
|
317
|
-
@
|
341
|
+
@N, @g = SRP.Ng(group)
|
342
|
+
@hash = hash
|
343
|
+
@k = SRP.calc_k(@N, @g, @hash)
|
318
344
|
end
|
319
345
|
|
320
346
|
# Initial user creation for the persistance layer.
|
@@ -322,7 +348,8 @@ module SRP
|
|
322
348
|
# Returns { <username>, <password verifier>, <salt> }
|
323
349
|
def generate_userauth username, password
|
324
350
|
@salt ||= random_salt
|
325
|
-
|
351
|
+
# warn "salt: #{@salt}"
|
352
|
+
x = SRP.calc_x(username, password, @salt, @hash)
|
326
353
|
v = SRP.calc_v(x, @N, @g)
|
327
354
|
return {:username => username, :verifier => "%x" % v, :salt => @salt}
|
328
355
|
end
|
@@ -334,6 +361,7 @@ module SRP
|
|
334
361
|
# SRP-6a safety check
|
335
362
|
return false if (xaa.to_i(16) % @N) == 0
|
336
363
|
generate_B(xverifier)
|
364
|
+
# warn "A: #{xaa}"
|
337
365
|
return {
|
338
366
|
:challenge => {:B => @B, :salt => xsalt},
|
339
367
|
:proof => {:A => xaa, :B => @B, :b => "%x" % @b,
|
@@ -348,31 +376,35 @@ module SRP
|
|
348
376
|
@A = proof[:A]
|
349
377
|
@B = proof[:B]
|
350
378
|
@b = proof[:b].to_i(16)
|
379
|
+
# warn "b: #{@b}"
|
380
|
+
|
351
381
|
username = proof[:I]
|
352
382
|
xsalt = proof[:s]
|
353
383
|
v = proof[:v].to_i(16)
|
354
384
|
|
355
|
-
u = SRP.calc_u(@A, @B, @N)
|
385
|
+
u = SRP.calc_u(@A, @B, @N, @hash)
|
356
386
|
# SRP-6a safety check
|
357
387
|
return false if u == 0
|
358
388
|
|
359
389
|
# calculate session key
|
360
390
|
@S = "%x" % SRP.calc_server_S(@A.to_i(16), @b, v, u, @N)
|
361
|
-
@K = SRP.sha1_hex(@S)
|
362
391
|
|
363
|
-
|
364
|
-
|
392
|
+
@K = SRP.sha1_hex(@S, @hash)
|
393
|
+
# warn "K: #{@K}"
|
365
394
|
|
395
|
+
# calculate match
|
396
|
+
@M = "%x" % SRP.calc_M1(@A, @B, @K, @N, @hash)
|
397
|
+
|
366
398
|
if @M == client_M
|
367
399
|
# authentication succeeded
|
368
|
-
@H_AMK = "%x" % SRP.
|
400
|
+
@H_AMK = "%x" % SRP.calc_M2(@A, @M, @K, @N, @hash)
|
369
401
|
return @H_AMK
|
370
402
|
end
|
371
403
|
return false
|
372
404
|
end
|
373
405
|
|
374
406
|
def random_salt
|
375
|
-
"%x" % SRP.bigrand(
|
407
|
+
"%x" % SRP.bigrand(16).hex
|
376
408
|
end
|
377
409
|
|
378
410
|
def random_bignum
|
@@ -392,14 +424,17 @@ module SRP
|
|
392
424
|
class Client
|
393
425
|
attr_reader :N, :g, :k, :a, :A, :S, :K, :M, :H_AMK
|
394
426
|
|
395
|
-
def initialize
|
427
|
+
def initialize(group, hash)
|
396
428
|
# select modulus (N) and generator (g)
|
397
|
-
@N, @g = SRP.Ng
|
398
|
-
@
|
429
|
+
@N, @g = SRP.Ng(group)
|
430
|
+
@hash = hash
|
431
|
+
@k = SRP.calc_k(@N, @g, @hash)
|
399
432
|
end
|
400
433
|
|
401
434
|
def start_authentication
|
402
|
-
generate_A
|
435
|
+
a = generate_A
|
436
|
+
# warn "A: #{a.to_s(16)}"
|
437
|
+
a
|
403
438
|
end
|
404
439
|
|
405
440
|
# Process initiated authentication challenge.
|
@@ -410,21 +445,21 @@ module SRP
|
|
410
445
|
# SRP-6a safety check
|
411
446
|
return false if (bb % @N) == 0
|
412
447
|
|
413
|
-
x = SRP.calc_x(username, password, xsalt)
|
414
|
-
u = SRP.calc_u(@A, xbb, @N)
|
448
|
+
x = SRP.calc_x(username, password, xsalt, @hash)
|
449
|
+
u = SRP.calc_u(@A, xbb, @N, @hash)
|
415
450
|
|
416
451
|
# SRP-6a safety check
|
417
452
|
return false if u == 0
|
418
453
|
|
419
454
|
# calculate session key
|
420
455
|
@S = "%x" % SRP.calc_client_S(bb, @a, @k, x, u, @N, @g)
|
421
|
-
@K = SRP.sha1_hex(@S)
|
456
|
+
@K = SRP.sha1_hex(@S, hash)
|
422
457
|
|
423
458
|
# calculate match
|
424
|
-
@M = "%x" % SRP.
|
459
|
+
@M = "%x" % SRP.calc_M1(@A, xbb, @K, @N, @hash)
|
425
460
|
|
426
461
|
# calculate verifier
|
427
|
-
@H_AMK = "%x" % SRP.
|
462
|
+
@H_AMK = "%x" % SRP.calc_M2(@A, @M, @K, @N, @hash)
|
428
463
|
|
429
464
|
return @M
|
430
465
|
end
|
@@ -440,7 +475,8 @@ module SRP
|
|
440
475
|
|
441
476
|
def generate_A
|
442
477
|
@a ||= random_bignum
|
478
|
+
# warn "a: #{@a}"
|
443
479
|
@A = "%x" % SRP.calc_A(@a, @N, @g)
|
444
480
|
end
|
445
481
|
end # Client
|
446
|
-
end
|
482
|
+
end
|
data/lib/srp-rb/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: srp-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|