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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
srp.Session = function(account, calculate) {
// default for injected dependency
account = account || new srp.Account();
calculate = calculate || new srp.Calculate();
var a = calculate.randomEphemeral();
var A = calculate.A(a);
var S = null;
var K = null;
var M = null;
var M2 = null;
var authenticated = false;
// *** Accessor methods ***
// allows setting the random number A for testing
this.calculateAndSetA = function(_a) {
a = _a;
A = calculate.A(_a);
return A;
};
this.signup = function() {
var salt = calculate.randomSalt();
var x = calculate.X(account.login(), account.password(), salt);
return {
login: account.login(),
password_salt: salt,
password_verifier: calculate.V(x)
};
};
this.handshake = function() {
return {
login: account.login(),
A: this.getA()
};
};
this.getA = function() {
return A;
}
// Delegate login & id so they can be used when talking to the remote
this.login = account.login;
this.id = account.id;
// Calculate S, M, and M2
// This is the client side of the SRP specification
this.calculations = function(salt, ephemeral)
{
//S -> C: s | B
var B = ephemeral;
var x = calculate.X(account.login(), account.password(), salt);
S = calculate.S(a, A, B, x);
K = calculate.K(S);
// M = H(H(N) xor H(g), H(I), s, A, B, K)
var xor = calculate.nXorG();
var hash_i = calculate.hash(account.login())
M = calculate.hashHex(xor + hash_i + salt + A + B + K);
//M2 = H(A, M, K)
M2 = calculate.hashHex(A + M + K);
};
this.getS = function() {
return S;
}
this.getM = function() {
return M;
}
this.validate = function(serverM2) {
authenticated = (serverM2 && serverM2 == M2)
return authenticated;
}
// If someone wants to use the session key for encrypting traffic, they can
// access the key with this function.
this.key = function()
{
if(K) {
return K;
} else {
this.onError("User has not been authenticated.");
}
};
// Encrypt plaintext using slowAES
this.encrypt = function(plaintext)
{
var key = cryptoHelpers.toNumbers(session.key());
var byteMessage = cryptoHelpers.convertStringToByteArray(plaintext);
var iv = new Array(16);
rng.nextBytes(iv);
var paddedByteMessage = slowAES.getPaddedBlock(byteMessage, 0, byteMessage.length, slowAES.modeOfOperation.CFB);
var ciphertext = slowAES.encrypt(paddedByteMessage, slowAES.modeOfOperation.CFB, key, key.length, iv).cipher;
var retstring = cryptoHelpers.base64.encode(iv.concat(ciphertext));
while(retstring.indexOf("+",0) > -1)
retstring = retstring.replace("+", "_");
return retstring;
};
};
|