forked from LinusU/secure-remote-password
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
80 lines (63 loc) · 2.2 KB
/
server.js
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
'use strict'
const params = require('./lib/params')
const SRPInteger = require('./lib/srp-integer')
exports.generateEphemeral = function (verifier) {
// N A large safe prime (N = 2q+1, where q is prime)
// g A generator modulo N
// k Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)
const { N, g, k } = params
// v Password verifier
const v = SRPInteger.fromHex(verifier)
// B = kv + g^b (b = random number)
const b = SRPInteger.randomInteger(params.hashOutputBytes)
const B = k.multiply(v).add(g.modPow(b, N)).mod(N)
return {
secret: b.toHex(),
public: B.toHex()
}
}
exports.deriveSession = function (serverSecretEphemeral, clientPublicEphemeral, salt, username, verifier, clientSessionProof) {
// N A large safe prime (N = 2q+1, where q is prime)
// g A generator modulo N
// k Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)
// H() One-way hash function
const { N, g, k, H } = params
// b Secret ephemeral values
// A Public ephemeral values
// s User's salt
// p Cleartext Password
// I Username
// v Password verifier
const b = SRPInteger.fromHex(serverSecretEphemeral)
const A = SRPInteger.fromHex(clientPublicEphemeral)
const s = SRPInteger.fromHex(salt)
const I = String(username)
const v = SRPInteger.fromHex(verifier)
// B = kv + g^b (b = random number)
const B = k.multiply(v).add(g.modPow(b, N)).mod(N)
// A % N > 0
if (A.mod(N).equals(SRPInteger.ZERO)) {
// fixme: .code, .statusCode, etc.
throw new Error('The client sent an invalid public ephemeral')
}
// u = H(A, B)
const u = H(A, B)
// S = (Av^u) ^ b (computes session key)
const S = A.multiply(v.modPow(u, N)).modPow(b, N)
// K = H(S)
const K = H(S)
// M = H(H(N) xor H(g), H(I), s, A, B, K)
const M = H(H(N).xor(H(g)), H(I), s, A, B, K)
const expected = M
const actual = SRPInteger.fromHex(clientSessionProof)
if (!actual.equals(expected)) {
// fixme: .code, .statusCode, etc.
throw new Error('Client provided session proof is invalid')
}
// P = H(A, M, K)
const P = H(A, M, K)
return {
key: K.toHex(),
proof: P.toHex()
}
}