summaryrefslogtreecommitdiff
path: root/src/srp_session.js
blob: babb96adaadcb4e7a1d7005375c5dd0473dfd224 (plain)
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
109
110
111
112
113
114
115
srp.Session = function(login, password, constants) {
  

  var constants = constants || new srp.Constants();
  var a = constants.randomEphemeral();
  var A = constants.calcA(a);
  var S = null;
  var K = null;
  var M = null;
  var M2 = null;
  var authenticated = false;
  var I = login;
  var pass = password;

  // *** Accessor methods ***

  // allows setting the random number A for testing

  this.calculateAndSetA = function(_a) {
    a = _a;
    A = constants.calcA(_a);
    return A;
  };

  this.signup = function() {
    var salt = constants.randomSalt();
    var x = constants.calcX(this.getI(), this.getPass(), salt);
    return {
      login: this.getI(),
      password_salt: salt,
      password_verifier: constants.calcV(x)
    };
  };

  this.handshake = function() {
    return { 
      login: this.getI(), 
      A: this.getA()
    };
  };

  this.getA = function() {
    return A;
  }

  // Returns the user's identity
  this.getI = function() {
    I = login || document.getElementById("srp_username").value;
    return I;
  };

  // Returns the password currently typed in
  this.getPass = function() {
    pass = password || document.getElementById("srp_password").value;
    return pass;
  };

  // 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 = constants.calcX(this.getI(), this.getPass(), salt);
    S = constants.calcS(a, A, B, x);
    K = constants.calcK(S);
    
    // M = H(H(N) xor H(g), H(I), s, A, B, K)
    var xor = constants.nXorG();
    M = constants.hash(xor + SHA256(I) + salt + A + B + K);
    //M2 = H(A, M, K)
    M2 = constants.hash(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;
  };
};