jsrp
Version:
JavaScript SRP implementation
179 lines (153 loc) • 5.4 kB
JavaScript
// Generated by CoffeeScript 2.3.2
(function() {
var BigInteger, SRP, createHash, parameters, randomBytes, transform;
BigInteger = require('jsbn').BigInteger;
createHash = require('create-hash');
randomBytes = require('randombytes');
transform = require('./transform');
parameters = require('./parameters');
SRP = class SRP {
constructor(length) {
this.params = parameters.get(length);
}
// x = H(s | H(I | ":" | P))
// Returns bigInteger
x(options) {
var I, P, identifierPasswordHash, result, salt, xHash;
// Options expects I, P, and salt property, where I is the identifier
// and P is the password. All of these should be buffers.
I = options.I;
P = options.P;
salt = options.salt;
identifierPasswordHash = createHash(this.params.hash).update(I).update(Buffer.from(':')).update(P).digest();
xHash = createHash(this.params.hash).update(salt).update(identifierPasswordHash).digest();
result = transform.buffer.toBigInteger(xHash);
return result;
}
// v = g^x % N
// Returns Buffer
v(options) {
var I, P, result, salt;
// Expects salt, I, P
I = options.I;
P = options.P;
salt = options.salt;
result = this.params.g.modPow(this.x(options), this.params.N);
result = transform.pad.toN(result, this.params);
return result;
}
// Returns a random BigInteger
a(callback) {
return randomBytes(32, function(err, resultBuf) {
var result;
result = transform.buffer.toBigInteger(resultBuf);
return callback(err, result);
});
}
// Returns a random BigInteger
b(callback) {
return randomBytes(32, function(err, resultBuf) {
var result;
result = transform.buffer.toBigInteger(resultBuf);
return callback(err, result);
});
}
// A = g^a % N
A(options) {
var a, result;
// Expects a, which should be a random BigInteger
a = options.a;
// Check here to ensure that a.length is not smaller than 256
result = this.params.g.modPow(a, this.params.N);
result = transform.pad.toN(result, this.params);
return result;
}
// B = (kv + g^b) % N
B(options) {
var b, result, v;
// Expects v, which should be the client verifier BigInteger, and b,
// which should be a random BigInteger
v = options.v; // BigInteger
b = options.b; // BigInteger
// This actually ends up being (v + (g^b % N)) % N, this is the way
// everyone else is doing it, so it's the way we're gonna do it.
result = this.k().multiply(v).add(this.params.g.modPow(b, this.params.N)).mod(this.params.N);
result = transform.pad.toN(result, this.params);
return result;
}
// u = H(A | B)
// Returns BigInteger
u(options) {
var A, B, result;
// We want A and B, both in buffer format.
A = options.A; // Buffer
B = options.B; // Buffer
result = createHash(this.params.hash).update(A).update(B).digest();
result = transform.buffer.toBigInteger(result);
return result;
}
// Client S calculation, where S = (B - g^x) ^ (a + u * x) % N
// Returns Buffer
clientS(options) {
var B, a, result, u, x;
B = options.B; // BigInteger
a = options.a; // BigInteger
u = options.u; // BigInteger
x = options.x; // BigInteger
result = B.subtract(this.k().multiply(this.params.g.modPow(x, this.params.N))).modPow(a.add(u.multiply(x)), this.params.N);
result = transform.pad.toN(result, this.params);
return result;
}
// S = (A * v^u) ^ b % N
serverS(options) {
var A, b, result, u, v;
A = options.A; // BigInteger
v = options.v; // BigInteger
u = options.u; // BigInteger
b = options.b; // BigInteger
result = A.multiply(v.modPow(u, this.params.N)).modPow(b, this.params.N);
result = transform.pad.toN(result, this.params);
return result;
}
// SRP-6 multiplier
// Returns BigInteger
k() {
var result;
result = createHash(this.params.hash).update(transform.pad.toN(this.params.N, this.params)).update(transform.pad.toN(this.params.g, this.params)).digest();
result = transform.buffer.toBigInteger(result);
return result;
}
K(options) {
var S, result;
S = options.S; // Buffer
result = createHash(this.params.hash).update(S).digest();
return result;
}
M1(options) {
var A, B, K, result;
A = options.A; // Buffer
B = options.B; // Buffer
K = options.K; // Buffer
result = createHash(this.params.hash).update(A).update(B).update(K).digest();
return result;
}
M2(options) {
var A, K, M, result;
A = options.A; // Buffer
M = options.M; // Buffer
K = options.K; // Buffer
result = createHash(this.params.hash).update(A).update(M).update(K).digest();
return result;
}
generateSalt(callback) {
return randomBytes(32, function(err, resultBuf) {
return callback(err, resultBuf);
});
}
// This is used to ensure that values are not zero when mod N.
isZeroWhenModN(thisBigInt) {
return thisBigInt.mod(this.params.N).equals(BigInteger.ZERO);
}
};
module.exports = SRP;
}).call(this);