bsrp
Version:
Secure Remote Password Protocol (SRP-6a) Implementation
121 lines (120 loc) • 9.01 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var jsbn_1 = require("jsbn");
var index_1 = require("./index");
var crypto_1 = __importDefault(require("crypto"));
Object.defineProperty(global, "crypto", {
value: {
getRandomValues: function (arr) {
return new Uint8Array(crypto_1["default"].randomBytes(arr.length));
}
}
});
test("should generate distinct ephemeral A pairs on subsequent calls", function () {
var firstAPair = index_1.generateAPair();
var secondAPair = index_1.generateAPair();
expect(firstAPair.ephemeralA.equals(secondAPair.ephemeralA)).toBeFalsy();
expect(firstAPair.publicA.equals(secondAPair.publicA)).toBeFalsy();
});
describe("should process the challenge and ", function () {
var mockIdentity = "test";
var mockPassword = "#yoloswag";
var mockSalt = new jsbn_1.BigInteger("82309018978721799953398513360460893179767695404873354411100056397421052845665");
var mockPublicB = new jsbn_1.BigInteger("\n 2168633872370722745670231052464515298895652280466586654940561279418192885446\n 5569815697827449086706130654556981842259346317901572319578127690722060828257\n 3518553531735879868022446812124213772126832091842123960193172642571089048102\n 1733289687022334152421632949742565001244773176944756872042436192195957381164\n 3090658931531623031352514968292009353084810965494415056390874498442382477900\n 5882353129578106468292270918741874924193460980087907520441982126932668030685\n 0090969045828991711574270619272362170264839084534189611581461513287496008879\n 4917135704491740168013752189651036694080408335025658762869099665070041969775\n 98773447");
var mockEphemeralA = new jsbn_1.BigInteger("\n 4511537769169629456932317311882933072389518195547222946095076177846929590195\n 1371663079183837225894296915421325322153782291026063288897303615301028637536\n 4456708100501196659474191428313993281737569455237451851801736494448257151040\n 4365649028849103887131660619405196304102087967082694857865126560813264823405\n 2896370620643251731159847597082454921230612553999232050453350061287212947114\n 3468309214437185337349903617563711682323708858174186538383127890364117859261\n 0235971430683027990812743687636354509374067537368960261011404677986671649957\n 1557511465995246567919633908251275514634723736321964939491245041138953850276\n 87951603");
var mockPublicA = new jsbn_1.BigInteger("\n 7723050516275197268596595028736303071422024349483662336212921812048310033512\n 6572244050991069989463201236543019478742255154255342629510064426510389492901\n 5314632288491039186285275840080928643682068266242876368549903623900851264362\n 7570310166999141108388337926675047366656403001872884373870424306058994437632\n 6182236026078347522175520387250862728453632132151431118882482079388402701874\n 1521703855998269888412158021986972606977074552546346835095695193183456199335\n 2853623091631714197790513583278068216773290743046592802328988338075991944028\n 1512937113784396196375280239379337167801926867954676026661710324701047040250\n 3411593");
var mockM = new jsbn_1.BigInteger("47331452883524291432813240675074597019503107827225066688099958715824381672937");
var mockSessionKey = new jsbn_1.BigInteger("56698353699494108654378460060782330526832508847563378289382973830724156337149");
var mockServerHAMK = new jsbn_1.BigInteger("112019802657940577633183024678428984798515249411730363524477901544479122837941");
test("respond with the expected message M to the server", function () { return __awaiter(void 0, void 0, void 0, function () {
var processedChallenge, message, sessionKey, clientHAMK;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4, index_1.processChallenge(mockIdentity, mockPassword, mockSalt, mockEphemeralA, mockPublicA, mockPublicB)];
case 1:
processedChallenge = _a.sent();
message = processedChallenge.message, sessionKey = processedChallenge.sessionKey;
expect(message.equals(mockM)).toBeTruthy();
expect(sessionKey.equals(mockSessionKey)).toBeTruthy();
return [4, index_1.verifySession(mockPublicA, message, sessionKey, mockServerHAMK)];
case 2:
clientHAMK = _a.sent();
expect(clientHAMK.equals(mockServerHAMK)).toBeTruthy();
return [2];
}
});
}); });
test("fail (SRP6a safety check) since B % prime = 0", function () { return __awaiter(void 0, void 0, void 0, function () {
var mockZeroPublicB, processedChallenge;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
mockZeroPublicB = new jsbn_1.BigInteger("0");
return [4, index_1.processChallenge(mockIdentity, mockPassword, mockSalt, mockEphemeralA, mockPublicA, mockZeroPublicB)];
case 1:
processedChallenge = _a.sent();
expect(processedChallenge).toBeNull();
return [2];
}
});
}); });
test("fail to mutually authenticate the server", function () { return __awaiter(void 0, void 0, void 0, function () {
var mockWrongServerHAMK, processedChallenge, message, sessionKey, clientHAMK;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
mockWrongServerHAMK = new jsbn_1.BigInteger("482758924758974325893457983478954");
return [4, index_1.processChallenge(mockIdentity, mockPassword, mockSalt, mockEphemeralA, mockPublicA, mockPublicB)];
case 1:
processedChallenge = _a.sent();
message = processedChallenge.message, sessionKey = processedChallenge.sessionKey;
expect(message.equals(mockM)).toBeTruthy();
expect(sessionKey.equals(mockSessionKey)).toBeTruthy();
return [4, index_1.verifySession(mockPublicA, message, sessionKey, mockWrongServerHAMK)];
case 2:
clientHAMK = _a.sent();
expect(clientHAMK).toBeNull();
return [2];
}
});
}); });
});