srp-rb 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|