mirror of
https://github.com/danog/fast-srp.git
synced 2024-11-26 20:04:49 +01:00
Setting up ESLint
This commit is contained in:
parent
462b688de4
commit
b91cb6fe8a
32
.eslintrc
Normal file
32
.eslintrc
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended" // uses the recommended rules from the @typescript-eslint/eslint-plugin
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2018,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"ignorePatterns": [
|
||||||
|
"bin/",
|
||||||
|
"lib/",
|
||||||
|
"jsbn"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||||
|
"linebreak-style": ["error", "unix"],
|
||||||
|
"semi": ["error", "always"],
|
||||||
|
|
||||||
|
"comma-dangle": ["error", "always-multiline"],
|
||||||
|
"dot-notation": "error",
|
||||||
|
"eqeqeq": "error",
|
||||||
|
"curly": ["error", "all"],
|
||||||
|
"brace-style": ["error"],
|
||||||
|
|
||||||
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
|
"@typescript-eslint/camelcase": "off"
|
||||||
|
}
|
||||||
|
}
|
19
.github/workflows/nodejs.yml
vendored
19
.github/workflows/nodejs.yml
vendored
@ -23,11 +23,20 @@ jobs:
|
|||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- name: npm install, build and test
|
- name: Run npm ci
|
||||||
run: |
|
run: npm ci
|
||||||
npm ci
|
env:
|
||||||
npm run build --if-present
|
CI: true
|
||||||
npm test
|
- name: Run npm build
|
||||||
|
run: npm build
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
- name: Run npm lint
|
||||||
|
run: npm lint
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
- name: Run npm test
|
||||||
|
run: npm test
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
fast-srp
|
fast-srp-hap
|
||||||
===
|
===
|
||||||
|
|
||||||
Is a pure [NodeJS](https://nodejs.org/) implementation of the [SRP6a protocol](http://srp.stanford.edu/).
|
Is a pure [NodeJS](https://nodejs.org/) implementation of the [SRP6a protocol](http://srp.stanford.edu/).
|
||||||
|
32
jsbn/jsbn.d.ts
vendored
32
jsbn/jsbn.d.ts
vendored
@ -1,23 +1,23 @@
|
|||||||
declare class BigInteger {
|
declare class BigInteger {
|
||||||
constructor(number: number | string, base?: number);
|
constructor(number: number | string, base?: number);
|
||||||
constructor(number: Buffer);
|
constructor(number: Buffer);
|
||||||
constructor(number: unknown);
|
constructor(number: unknown);
|
||||||
|
|
||||||
toString(base?: number): string;
|
toString(base?: number): string;
|
||||||
toBuffer(trimOrSize?: true | number): Buffer;
|
toBuffer(trimOrSize?: true | number): Buffer;
|
||||||
|
|
||||||
/** @return {number} 1 if this > a, -1 if this < a, 0 if equal */
|
/** @return {number} 1 if this > a, -1 if this < a, 0 if equal */
|
||||||
compareTo(a: BigInteger): -1 | 0 | 1;
|
compareTo(a: BigInteger): -1 | 0 | 1;
|
||||||
|
|
||||||
multiply(b: BigInteger): BigInteger;
|
|
||||||
|
|
||||||
add(b: BigInteger | number): BigInteger;
|
|
||||||
subtract(b: BigInteger): BigInteger;
|
|
||||||
|
|
||||||
modPow(b: BigInteger, N: BigInteger): BigInteger;
|
|
||||||
mod(b: BigInteger): BigInteger;
|
|
||||||
|
|
||||||
bitLength(): number;
|
multiply(b: BigInteger): BigInteger;
|
||||||
|
|
||||||
|
add(b: BigInteger | number): BigInteger;
|
||||||
|
subtract(b: BigInteger): BigInteger;
|
||||||
|
|
||||||
|
modPow(b: BigInteger, N: BigInteger): BigInteger;
|
||||||
|
mod(b: BigInteger): BigInteger;
|
||||||
|
|
||||||
|
bitLength(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export = BigInteger;
|
export = BigInteger;
|
||||||
|
1113
package-lock.json
generated
1113
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -5,10 +5,11 @@
|
|||||||
"main": "lib/srp.js",
|
"main": "lib/srp.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -rf lib",
|
"clean": "rm -rf lib",
|
||||||
|
"lint": "eslint 'src/**/*.{js,ts,json}'",
|
||||||
"build": "npm run clean && tsc",
|
"build": "npm run clean && tsc",
|
||||||
|
"test": "vows lib/test/test_*.js --spec",
|
||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build",
|
||||||
"postpublish": "npm run clean",
|
"postpublish": "npm run clean"
|
||||||
"test": "vows lib/test/test_*.js --spec"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -30,6 +31,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^10.17.19",
|
"@types/node": "^10.17.19",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
"vows": "^0.8.3"
|
"vows": "^0.8.3",
|
||||||
|
"eslint": "^6.8.0",
|
||||||
|
"@typescript-eslint/parser": "^2.27.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.27.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
// since these are meant to be used internally, all values are numbers. If
|
// since these are meant to be used internally, all values are numbers. If
|
||||||
// you want to add parameter sets, you'll need to convert them to bignums.
|
// you want to add parameter sets, you'll need to convert them to bignums.
|
||||||
|
|
||||||
import BigInteger = require('../jsbn/jsbn');
|
import BigInteger = require("../jsbn/jsbn");
|
||||||
|
|
||||||
export function hex(s: string) {
|
export function hex(s: string): BigInteger {
|
||||||
return new BigInteger(s.split(/\s|\n/).join(''), 16);
|
return new BigInteger(s.split(/\s|\n/).join(""), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SrpParams {
|
export interface SrpParams {
|
||||||
@ -37,8 +37,8 @@ export const params = {
|
|||||||
7BCF1885 C529F566 660E57EC 68EDBC3C 05726CC0 2FD4CBF4 976EAA9A
|
7BCF1885 C529F566 660E57EC 68EDBC3C 05726CC0 2FD4CBF4 976EAA9A
|
||||||
FD5138FE 8376435B 9FC61D2F C0EB06E3
|
FD5138FE 8376435B 9FC61D2F C0EB06E3
|
||||||
`),
|
`),
|
||||||
g: hex('02'),
|
g: hex("02"),
|
||||||
hash: 'sha1',
|
hash: "sha1",
|
||||||
},
|
},
|
||||||
|
|
||||||
1536: {
|
1536: {
|
||||||
@ -52,8 +52,8 @@ export const params = {
|
|||||||
F7CCB7AE 837C264A E3A9BEB8 7F8A2FE9 B8B5292E 5A021FFF 5E91479E
|
F7CCB7AE 837C264A E3A9BEB8 7F8A2FE9 B8B5292E 5A021FFF 5E91479E
|
||||||
8CE7A28C 2442C6F3 15180F93 499A234D CF76E3FE D135F9BB
|
8CE7A28C 2442C6F3 15180F93 499A234D CF76E3FE D135F9BB
|
||||||
`),
|
`),
|
||||||
g: hex('02'),
|
g: hex("02"),
|
||||||
hash: 'sha1',
|
hash: "sha1",
|
||||||
},
|
},
|
||||||
|
|
||||||
2048: {
|
2048: {
|
||||||
@ -70,8 +70,8 @@ export const params = {
|
|||||||
94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F
|
94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F
|
||||||
9E4AFF73
|
9E4AFF73
|
||||||
`),
|
`),
|
||||||
g: hex('02'),
|
g: hex("02"),
|
||||||
hash: 'sha256',
|
hash: "sha256",
|
||||||
},
|
},
|
||||||
|
|
||||||
3072: {
|
3072: {
|
||||||
@ -92,8 +92,8 @@ export const params = {
|
|||||||
BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
|
BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
|
||||||
E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
|
E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
|
||||||
`),
|
`),
|
||||||
g: hex('05'),
|
g: hex("05"),
|
||||||
hash: 'sha256',
|
hash: "sha256",
|
||||||
},
|
},
|
||||||
|
|
||||||
hap: {
|
hap: {
|
||||||
@ -114,8 +114,8 @@ export const params = {
|
|||||||
BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
|
BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
|
||||||
E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
|
E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
|
||||||
`),
|
`),
|
||||||
g: hex('05'),
|
g: hex("05"),
|
||||||
hash: 'sha512',
|
hash: "sha512",
|
||||||
},
|
},
|
||||||
|
|
||||||
4096: {
|
4096: {
|
||||||
@ -141,8 +141,8 @@ export const params = {
|
|||||||
D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199
|
D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199
|
||||||
FFFFFFFF FFFFFFFF
|
FFFFFFFF FFFFFFFF
|
||||||
`),
|
`),
|
||||||
g: hex('05'),
|
g: hex("05"),
|
||||||
hash: 'sha256',
|
hash: "sha256",
|
||||||
},
|
},
|
||||||
|
|
||||||
6244: {
|
6244: {
|
||||||
@ -177,8 +177,8 @@ export const params = {
|
|||||||
387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E
|
387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E
|
||||||
6DCC4024 FFFFFFFF FFFFFFFF
|
6DCC4024 FFFFFFFF FFFFFFFF
|
||||||
`),
|
`),
|
||||||
g: hex('05'),
|
g: hex("05"),
|
||||||
hash: 'sha256',
|
hash: "sha256",
|
||||||
},
|
},
|
||||||
|
|
||||||
8192: {
|
8192: {
|
||||||
@ -222,8 +222,8 @@ export const params = {
|
|||||||
FC026E47 9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71
|
FC026E47 9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71
|
||||||
60C980DD 98EDD3DF FFFFFFFF FFFFFFFF
|
60C980DD 98EDD3DF FFFFFFFF FFFFFFFF
|
||||||
`),
|
`),
|
||||||
g: hex('13'),
|
g: hex("13"),
|
||||||
hash: 'sha256',
|
hash: "sha256",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
266
src/srp.ts
266
src/srp.ts
@ -1,15 +1,24 @@
|
|||||||
import crypto from 'crypto';
|
import crypto from "crypto";
|
||||||
import assert from 'assert';
|
import assert from "assert";
|
||||||
import BigInteger = require('../jsbn/jsbn');
|
import BigInteger = require("../jsbn/jsbn");
|
||||||
import {SrpParams, params as srpParams} from './params';
|
import { SrpParams, params as srpParams } from "./params";
|
||||||
|
|
||||||
export { SrpParams } from './params';
|
export { SrpParams } from "./params";
|
||||||
|
|
||||||
const zero = new BigInteger(0, 10);
|
const zero = new BigInteger(0, 10);
|
||||||
|
|
||||||
function assert_(val: any, msg: string) {
|
function assert_<V>(val: V, msg: string): void{
|
||||||
if (!val)
|
if (!val) {
|
||||||
throw new Error(msg || 'assertion');
|
throw new Error(msg || "assertion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertIsBuffer(arg: Buffer, argname = "arg"): void {
|
||||||
|
assert_(Buffer.isBuffer(arg), `Type error: ${argname} must be a buffer`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertIsBigInteger(arg: BigInteger, argname?: string): void {
|
||||||
|
assert_(arg.constructor.name === "BigInteger", `Type error: ${argname} must be a BigInteger`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,30 +31,21 @@ function assert_(val: any, msg: string) {
|
|||||||
* @param {number} len Length of the resulting Buffer
|
* @param {number} len Length of the resulting Buffer
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
function padTo(n: Buffer, len: number) {
|
function padTo(n: Buffer, len: number): Buffer {
|
||||||
assertIsBuffer(n, 'n');
|
assertIsBuffer(n, "n");
|
||||||
const padding = len - n.length;
|
const padding = len - n.length;
|
||||||
assert_(padding > -1, 'Negative padding. Very uncomfortable.');
|
assert_(padding > -1, "Negative padding. Very uncomfortable.");
|
||||||
const result = Buffer.alloc(len);
|
const result = Buffer.alloc(len);
|
||||||
result.fill(0, 0, padding);
|
result.fill(0, 0, padding);
|
||||||
n.copy(result, padding);
|
n.copy(result, padding);
|
||||||
assert.equal(result.length, len);
|
assert.strictEqual(result.length, len);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function padToN(number: BigInteger, params: SrpParams) {
|
function padToN(number: BigInteger, params: SrpParams): Buffer {
|
||||||
assertIsBigInteger(number);
|
assertIsBigInteger(number);
|
||||||
const n = number.toString(16).length % 2 != 0 ? '0' + number.toString(16) : number.toString(16);
|
const n = number.toString(16).length % 2 !== 0 ? "0" + number.toString(16) : number.toString(16);
|
||||||
return padTo(Buffer.from(n, 'hex'), params.N_length_bits / 8);
|
return padTo(Buffer.from(n, "hex"), params.N_length_bits / 8);
|
||||||
}
|
|
||||||
|
|
||||||
function assertIsBuffer(arg: Buffer, argname: string, ___?: any) {
|
|
||||||
argname = argname || 'arg';
|
|
||||||
assert_(Buffer.isBuffer(arg), `Type error: ${argname} must be a buffer`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertIsBigInteger(arg: BigInteger, argname?: string) {
|
|
||||||
assert_(arg.constructor.name === 'BigInteger', `Type error: ${argname} must be a BigInteger`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,12 +60,12 @@ function assertIsBigInteger(arg: BigInteger, argname?: string) {
|
|||||||
* @param {Buffer} P User password
|
* @param {Buffer} P User password
|
||||||
* @return {BigInteger} User secret
|
* @return {BigInteger} User secret
|
||||||
*/
|
*/
|
||||||
function getx(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer) {
|
function getx(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer): BigInteger {
|
||||||
assertIsBuffer(salt, 'salt (salt)');
|
assertIsBuffer(salt, "salt (salt)");
|
||||||
assertIsBuffer(I, 'identity (I)');
|
assertIsBuffer(I, "identity (I)");
|
||||||
assertIsBuffer(P, 'password (P)');
|
assertIsBuffer(P, "password (P)");
|
||||||
const hashIP = crypto.createHash(params.hash)
|
const hashIP = crypto.createHash(params.hash)
|
||||||
.update(Buffer.concat([I, Buffer.from(':'), P]))
|
.update(Buffer.concat([I, Buffer.from(":"), P]))
|
||||||
.digest();
|
.digest();
|
||||||
const hashX: Buffer = crypto.createHash(params.hash)
|
const hashX: Buffer = crypto.createHash(params.hash)
|
||||||
.update(salt)
|
.update(salt)
|
||||||
@ -97,13 +97,18 @@ export class SRP {
|
|||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
public static computeVerifier(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer): Buffer {
|
public static computeVerifier(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer): Buffer {
|
||||||
assertIsBuffer(salt, 'salt (salt)');
|
assertIsBuffer(salt, "salt (salt)");
|
||||||
assertIsBuffer(I, 'identity (I)');
|
assertIsBuffer(I, "identity (I)");
|
||||||
assertIsBuffer(P, 'password (P)');
|
assertIsBuffer(P, "password (P)");
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
const v_num = params.g.modPow(getx(params, salt, I, P), params.N);
|
const v_num = params.g.modPow(getx(params, salt, I, P), params.N);
|
||||||
return v_num.toBuffer(params.N_length_bits / 8);
|
return v_num.toBuffer(params.N_length_bits / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static genKey(callback: GenKeyCallback): void;
|
||||||
|
public static genKey(bytes: number, callback: GenKeyCallback): void;
|
||||||
|
public static genKey(bytes?: number): Promise<Buffer>;
|
||||||
/**
|
/**
|
||||||
* Generate a random key.
|
* Generate a random key.
|
||||||
*
|
*
|
||||||
@ -111,20 +116,21 @@ export class SRP {
|
|||||||
* @param {function} [callback] If not provided a Promise is returned
|
* @param {function} [callback] If not provided a Promise is returned
|
||||||
* @return {Promise|void}
|
* @return {Promise|void}
|
||||||
*/
|
*/
|
||||||
public static genKey(callback: GenKeyCallback): void;
|
|
||||||
public static genKey(bytes: number, callback: GenKeyCallback): void;
|
|
||||||
public static genKey(bytes?: number): Promise<Buffer>;
|
|
||||||
public static genKey(bytes: number | GenKeyCallback = 32, callback?: GenKeyCallback): Promise<Buffer> | void {
|
public static genKey(bytes: number | GenKeyCallback = 32, callback?: GenKeyCallback): Promise<Buffer> | void {
|
||||||
// bytes is optional
|
// bytes is optional
|
||||||
if (typeof bytes !== 'number') {
|
if (typeof bytes !== "number") {
|
||||||
callback = bytes as unknown as GenKeyCallback;
|
callback = bytes as unknown as GenKeyCallback;
|
||||||
bytes = 32;
|
bytes = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callback) return new Promise((rs, rj) => SRP.genKey(bytes as number, (err, data) => err ? rj(err) : rs(data!)));
|
if (!callback) {
|
||||||
|
return new Promise((rs, rj) => SRP.genKey(bytes as number, (err, data) => err ? rj(err) : rs(data!)));
|
||||||
|
}
|
||||||
|
|
||||||
crypto.randomBytes(bytes, (err, buf) => {
|
crypto.randomBytes(bytes, (err, buf) => {
|
||||||
if (err) return callback!(err, null);
|
if (err) {
|
||||||
|
return callback!(err, null);
|
||||||
|
}
|
||||||
return callback!(null, buf);
|
return callback!(null, buf);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -137,7 +143,7 @@ export class SRP {
|
|||||||
* @param {object} params Group parameters, with .N, .g, .hash
|
* @param {object} params Group parameters, with .N, .g, .hash
|
||||||
* @return {BigInteger}
|
* @return {BigInteger}
|
||||||
*/
|
*/
|
||||||
function getk(params: SrpParams) {
|
function getk(params: SrpParams): BigInteger {
|
||||||
const k_buf = crypto
|
const k_buf = crypto
|
||||||
.createHash(params.hash)
|
.createHash(params.hash)
|
||||||
.update(padToN(params.N, params))
|
.update(padToN(params.N, params))
|
||||||
@ -161,7 +167,7 @@ function getk(params: SrpParams) {
|
|||||||
* @param {BigInteger} b Server secret exponent
|
* @param {BigInteger} b Server secret exponent
|
||||||
* @return {Buffer} B - The server public message
|
* @return {Buffer} B - The server public message
|
||||||
*/
|
*/
|
||||||
function getB(params: SrpParams, k: BigInteger, v: BigInteger, b: BigInteger) {
|
function getB(params: SrpParams, k: BigInteger, v: BigInteger, b: BigInteger): Buffer {
|
||||||
assertIsBigInteger(v);
|
assertIsBigInteger(v);
|
||||||
assertIsBigInteger(k);
|
assertIsBigInteger(k);
|
||||||
assertIsBigInteger(b);
|
assertIsBigInteger(b);
|
||||||
@ -178,12 +184,12 @@ function getB(params: SrpParams, k: BigInteger, v: BigInteger, b: BigInteger) {
|
|||||||
*
|
*
|
||||||
* @param {object} params Group parameters, with .N, .g, .hash
|
* @param {object} params Group parameters, with .N, .g, .hash
|
||||||
* @param {BigInteger} a_num Client secret exponent
|
* @param {BigInteger} a_num Client secret exponent
|
||||||
* @return {BigInteger} A - The client public message
|
* @return {Buffer} A - The client public message
|
||||||
*/
|
*/
|
||||||
function getA(params: SrpParams, a_num: BigInteger) {
|
function getA(params: SrpParams, a_num: BigInteger): Buffer {
|
||||||
assertIsBigInteger(a_num);
|
assertIsBigInteger(a_num);
|
||||||
if (Math.ceil(a_num.toString(16).length / 2) < 32) {
|
if (Math.ceil(a_num.toString(16).length / 2) < 32) {
|
||||||
console.warn('getA: client key length %d is less than the recommended 256 bits', a_num.bitLength());
|
console.warn("getA: client key length %d is less than the recommended 256 bits", a_num.bitLength());
|
||||||
}
|
}
|
||||||
return params.g.modPow(a_num, params.N).toBuffer(params.N_length_bits / 8);
|
return params.g.modPow(a_num, params.N).toBuffer(params.N_length_bits / 8);
|
||||||
}
|
}
|
||||||
@ -200,9 +206,9 @@ function getA(params: SrpParams, a_num: BigInteger) {
|
|||||||
* @param {Buffer} B Server ephemeral public key
|
* @param {Buffer} B Server ephemeral public key
|
||||||
* @return {BigInteger} u - Shared scrambling parameter
|
* @return {BigInteger} u - Shared scrambling parameter
|
||||||
*/
|
*/
|
||||||
function getu(params: SrpParams, A: Buffer, B: Buffer) {
|
function getu(params: SrpParams, A: Buffer, B: Buffer): BigInteger {
|
||||||
assertIsBuffer(A, 'A');
|
assertIsBuffer(A, "A");
|
||||||
assertIsBuffer(B, 'B');
|
assertIsBuffer(B, "B");
|
||||||
const u_buf = crypto.createHash(params.hash)
|
const u_buf = crypto.createHash(params.hash)
|
||||||
.update(padTo(A, params.N_length_bits / 8))
|
.update(padTo(A, params.N_length_bits / 8))
|
||||||
.update(padTo(B, params.N_length_bits / 8))
|
.update(padTo(B, params.N_length_bits / 8))
|
||||||
@ -213,22 +219,23 @@ function getu(params: SrpParams, A: Buffer, B: Buffer) {
|
|||||||
/**
|
/**
|
||||||
* The TLS premaster secret as calculated by the client
|
* The TLS premaster secret as calculated by the client
|
||||||
*
|
*
|
||||||
* @param {object} params Group parameters, with .N, .g, .hash
|
* @param {SrpParams} params Group parameters, with .N, .g, .hash
|
||||||
* @param {Buffer} salt Salt (read from server)
|
* @param {BigInteger} k_num
|
||||||
* @param {Buffer} I User identity (read from user)
|
* @param {BigInteger} x_num
|
||||||
* @param {Buffer} P User password (read from user)
|
* @param {BigInteger} a_num
|
||||||
* @param {BigInteger} a Ephemeral private key (generated for session)
|
* @param {BigInteger} B_num
|
||||||
* @param {BigInteger} B Server ephemeral public key (read from server)
|
* @param {BigInteger} u_num
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
function client_getS(params: SrpParams, k_num: BigInteger, x_num: BigInteger, a_num: BigInteger, B_num: BigInteger, u_num: BigInteger) {
|
function client_getS(params: SrpParams, k_num: BigInteger, x_num: BigInteger, a_num: BigInteger, B_num: BigInteger, u_num: BigInteger): Buffer {
|
||||||
assertIsBigInteger(k_num);
|
assertIsBigInteger(k_num);
|
||||||
assertIsBigInteger(x_num);
|
assertIsBigInteger(x_num);
|
||||||
assertIsBigInteger(a_num);
|
assertIsBigInteger(a_num);
|
||||||
assertIsBigInteger(B_num);
|
assertIsBigInteger(B_num);
|
||||||
assertIsBigInteger(u_num);
|
assertIsBigInteger(u_num);
|
||||||
if ((zero.compareTo(B_num) >= 0) || (params.N.compareTo(B_num) <= 0))
|
if ((zero.compareTo(B_num) >= 0) || (params.N.compareTo(B_num) <= 0)) {
|
||||||
throw new Error('invalid server-supplied "B", must be 1..N-1');
|
throw new Error("invalid server-supplied \"B\", must be 1..N-1");
|
||||||
|
}
|
||||||
|
|
||||||
const S_num = B_num.subtract(k_num.multiply(params.g.modPow(x_num, params.N)))
|
const S_num = B_num.subtract(k_num.multiply(params.g.modPow(x_num, params.N)))
|
||||||
.modPow(a_num.add(u_num.multiply(x_num)), params.N)
|
.modPow(a_num.add(u_num.multiply(x_num)), params.N)
|
||||||
@ -246,13 +253,14 @@ function client_getS(params: SrpParams, k_num: BigInteger, x_num: BigInteger, a_
|
|||||||
* @param {BigInteger} u_num {@see getu}
|
* @param {BigInteger} u_num {@see getu}
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
function server_getS(params: SrpParams, v_num: BigInteger, A_num: BigInteger, b_num: BigInteger, u_num: BigInteger) {
|
function server_getS(params: SrpParams, v_num: BigInteger, A_num: BigInteger, b_num: BigInteger, u_num: BigInteger): Buffer {
|
||||||
assertIsBigInteger(v_num);
|
assertIsBigInteger(v_num);
|
||||||
assertIsBigInteger(A_num);
|
assertIsBigInteger(A_num);
|
||||||
assertIsBigInteger(b_num);
|
assertIsBigInteger(b_num);
|
||||||
assertIsBigInteger(u_num);
|
assertIsBigInteger(u_num);
|
||||||
if ((zero.compareTo(A_num) >= 0) || (params.N.compareTo(A_num) <= 0))
|
if ((zero.compareTo(A_num) >= 0) || (params.N.compareTo(A_num) <= 0)) {
|
||||||
throw new Error('invalid client-supplied "A", must be 1..N-1');
|
throw new Error("invalid client-supplied \"A\", must be 1..N-1");
|
||||||
|
}
|
||||||
|
|
||||||
const S_num = A_num.multiply(v_num.modPow(u_num, params.N))
|
const S_num = A_num.multiply(v_num.modPow(u_num, params.N))
|
||||||
.modPow(b_num, params.N)
|
.modPow(b_num, params.N)
|
||||||
@ -267,13 +275,13 @@ function server_getS(params: SrpParams, v_num: BigInteger, A_num: BigInteger, b_
|
|||||||
* @param {Buffer} S_buf Session key
|
* @param {Buffer} S_buf Session key
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
function getK(params: SrpParams, S_buf: Buffer) {
|
function getK(params: SrpParams, S_buf: Buffer): Buffer {
|
||||||
assertIsBuffer(S_buf, 'S');
|
assertIsBuffer(S_buf, "S");
|
||||||
if (params.hash === 'sha1') {
|
if (params.hash === "sha1") {
|
||||||
// use t_mgf1 interleave for short sha1 hashes
|
// use t_mgf1 interleave for short sha1 hashes
|
||||||
return Buffer.concat([
|
return Buffer.concat([
|
||||||
crypto.createHash(params.hash).update(S_buf).update(Buffer.from([0,0,0,0])).digest(),
|
crypto.createHash(params.hash).update(S_buf).update(Buffer.from([0,0,0,0])).digest(),
|
||||||
crypto.createHash(params.hash).update(S_buf).update(Buffer.from([0,0,0,1])).digest()
|
crypto.createHash(params.hash).update(S_buf).update(Buffer.from([0,0,0,1])).digest(),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// use hash as-is otherwise
|
// use hash as-is otherwise
|
||||||
@ -292,19 +300,20 @@ function getK(params: SrpParams, S_buf: Buffer) {
|
|||||||
*/
|
*/
|
||||||
function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B_buf: Buffer, K_buf: Buffer): Buffer
|
function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B_buf: Buffer, K_buf: Buffer): Buffer
|
||||||
function getM1(params: SrpParams, A_buf: Buffer, B_buf: Buffer, K_buf: Buffer): Buffer
|
function getM1(params: SrpParams, A_buf: Buffer, B_buf: Buffer, K_buf: Buffer): Buffer
|
||||||
function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B_buf?: Buffer, K_buf?: Buffer) {
|
function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B_buf?: Buffer, K_buf?: Buffer): Buffer {
|
||||||
if (arguments.length > 4) {
|
if (arguments.length > 4) {
|
||||||
assertIsBuffer(u_buf, 'identity (I)');
|
assertIsBuffer(u_buf, "identity (I)");
|
||||||
assertIsBuffer(s_buf, 'salt (s)')
|
assertIsBuffer(s_buf, "salt (s)");
|
||||||
assertIsBuffer(A_buf, 'client public key (A)');
|
assertIsBuffer(A_buf, "client public key (A)");
|
||||||
assertIsBuffer(B_buf!, 'server public key (B)');
|
assertIsBuffer(B_buf!, "server public key (B)");
|
||||||
assertIsBuffer(K_buf!, 'session key (K)');
|
assertIsBuffer(K_buf!, "session key (K)");
|
||||||
|
|
||||||
const hN = crypto.createHash(params.hash).update(params.N.toBuffer(true)).digest();
|
const hN = crypto.createHash(params.hash).update(params.N.toBuffer(true)).digest();
|
||||||
const hG = crypto.createHash(params.hash).update(params.g.toBuffer(true)).digest();
|
const hG = crypto.createHash(params.hash).update(params.g.toBuffer(true)).digest();
|
||||||
|
|
||||||
for (let i = 0; i < hN.length; i++)
|
for (let i = 0; i < hN.length; i++) {
|
||||||
hN[i] ^= hG[i];
|
hN[i] ^= hG[i];
|
||||||
|
}
|
||||||
|
|
||||||
const hU = crypto.createHash(params.hash).update(u_buf).digest();
|
const hU = crypto.createHash(params.hash).update(u_buf).digest();
|
||||||
|
|
||||||
@ -315,9 +324,9 @@ function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B
|
|||||||
} else {
|
} else {
|
||||||
[A_buf, B_buf, s_buf] = [u_buf, s_buf, A_buf];
|
[A_buf, B_buf, s_buf] = [u_buf, s_buf, A_buf];
|
||||||
|
|
||||||
assertIsBuffer(A_buf, 'A');
|
assertIsBuffer(A_buf, "A");
|
||||||
assertIsBuffer(B_buf, 'B');
|
assertIsBuffer(B_buf, "B");
|
||||||
assertIsBuffer(s_buf, 'S');
|
assertIsBuffer(s_buf, "S");
|
||||||
|
|
||||||
return crypto.createHash(params.hash)
|
return crypto.createHash(params.hash)
|
||||||
.update(A_buf).update(B_buf).update(s_buf)
|
.update(A_buf).update(B_buf).update(s_buf)
|
||||||
@ -325,20 +334,20 @@ function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getM2(params: SrpParams, A_buf: Buffer, M1_buf: Buffer, K_buf: Buffer) {
|
function getM2(params: SrpParams, A_buf: Buffer, M1_buf: Buffer, K_buf: Buffer): Buffer {
|
||||||
assertIsBuffer(A_buf, 'A');
|
assertIsBuffer(A_buf, "A");
|
||||||
assertIsBuffer(M1_buf, 'M1');
|
assertIsBuffer(M1_buf, "M1");
|
||||||
assertIsBuffer(K_buf, 'K');
|
assertIsBuffer(K_buf, "K");
|
||||||
|
|
||||||
return crypto.createHash(params.hash)
|
return crypto.createHash(params.hash)
|
||||||
.update(A_buf).update(M1_buf).update(K_buf)
|
.update(A_buf).update(M1_buf).update(K_buf)
|
||||||
.digest();
|
.digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
function equal(buf1: Buffer, buf2: Buffer) {
|
function equal(buf1: Buffer, buf2: Buffer): boolean {
|
||||||
// constant-time comparison. A drop in the ocean compared to our
|
// constant-time comparison. A drop in the ocean compared to our
|
||||||
// non-constant-time modexp operations, but still good practice.
|
// non-constant-time modexp operations, but still good practice.
|
||||||
return buf1.toString('hex') === buf2.toString('hex');
|
return buf1.toString("hex") === buf2.toString("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SrpClient {
|
export class SrpClient {
|
||||||
@ -376,12 +385,13 @@ export class SrpClient {
|
|||||||
* @param {Buffer} identity_buf Identity/username
|
* @param {Buffer} identity_buf Identity/username
|
||||||
* @param {Buffer} password_buf Password
|
* @param {Buffer} password_buf Password
|
||||||
* @param {Buffer} secret1_buf Client private key {@see genKey}
|
* @param {Buffer} secret1_buf Client private key {@see genKey}
|
||||||
|
* @param {boolean} hap
|
||||||
*/
|
*/
|
||||||
constructor(params: SrpParams, salt_buf: Buffer, identity_buf: Buffer, password_buf: Buffer, secret1_buf: Buffer, hap = true) {
|
constructor(params: SrpParams, salt_buf: Buffer, identity_buf: Buffer, password_buf: Buffer, secret1_buf: Buffer, hap = true) {
|
||||||
assertIsBuffer(salt_buf, 'salt (s)');
|
assertIsBuffer(salt_buf, "salt (s)");
|
||||||
assertIsBuffer(identity_buf, 'identity (I)');
|
assertIsBuffer(identity_buf, "identity (I)");
|
||||||
assertIsBuffer(password_buf, 'password (P)');
|
assertIsBuffer(password_buf, "password (P)");
|
||||||
assertIsBuffer(secret1_buf, 'secret1');
|
assertIsBuffer(secret1_buf, "secret1");
|
||||||
|
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._k = getk(params);
|
this._k = getk(params);
|
||||||
@ -401,7 +411,7 @@ export class SrpClient {
|
|||||||
*
|
*
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
computeA() {
|
computeA(): Buffer {
|
||||||
return this._A;
|
return this._A;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +420,7 @@ export class SrpClient {
|
|||||||
*
|
*
|
||||||
* @param {Buffer} B_buf The server's public key
|
* @param {Buffer} B_buf The server's public key
|
||||||
*/
|
*/
|
||||||
setB(B_buf: Buffer) {
|
setB(B_buf: Buffer): void {
|
||||||
const u_num = getu(this._params, this._A, B_buf);
|
const u_num = getu(this._params, this._A, B_buf);
|
||||||
const S_buf_x = client_getS(this._params, this._k, this._x, this._a, new BigInteger(B_buf), u_num);
|
const S_buf_x = client_getS(this._params, this._k, this._x, this._a, new BigInteger(B_buf), u_num);
|
||||||
|
|
||||||
@ -432,9 +442,10 @@ export class SrpClient {
|
|||||||
*
|
*
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
computeM1() {
|
computeM1(): Buffer {
|
||||||
if (this._M1 === undefined)
|
if (this._M1 === undefined) {
|
||||||
throw new Error('incomplete protocol');
|
throw new Error("incomplete protocol");
|
||||||
|
}
|
||||||
return this._M1;
|
return this._M1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,9 +455,10 @@ export class SrpClient {
|
|||||||
*
|
*
|
||||||
* @param M2 The server's M2 value
|
* @param M2 The server's M2 value
|
||||||
*/
|
*/
|
||||||
checkM2(M2: Buffer) {
|
checkM2(M2: Buffer): void {
|
||||||
if (!equal(this._M2!, M2))
|
if (!equal(this._M2!, M2)) {
|
||||||
throw new Error('server is not authentic');
|
throw new Error("server is not authentic");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -454,9 +466,10 @@ export class SrpClient {
|
|||||||
*
|
*
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
computeK() {
|
computeK(): Buffer {
|
||||||
if (this._K === undefined)
|
if (this._K === undefined) {
|
||||||
throw new Error('incomplete protocol');
|
throw new Error("incomplete protocol");
|
||||||
|
}
|
||||||
return this._K;
|
return this._K;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -519,10 +532,10 @@ export class SrpServer {
|
|||||||
this._k = getk(params);
|
this._k = getk(params);
|
||||||
|
|
||||||
if (arguments.length > 3) {
|
if (arguments.length > 3) {
|
||||||
assertIsBuffer(salt_buf as Buffer, 'salt (salt)');
|
assertIsBuffer(salt_buf as Buffer, "salt (salt)");
|
||||||
assertIsBuffer(identity_buf!, 'identity (I)');
|
assertIsBuffer(identity_buf!, "identity (I)");
|
||||||
assertIsBuffer(password_buf!, 'password (P)');
|
assertIsBuffer(password_buf!, "password (P)");
|
||||||
assertIsBuffer(secret2_buf!, 'secret2');
|
assertIsBuffer(secret2_buf!, "secret2");
|
||||||
|
|
||||||
this._b = new BigInteger(secret2_buf!);
|
this._b = new BigInteger(secret2_buf!);
|
||||||
this._v = new BigInteger(SRP.computeVerifier(params, salt_buf as Buffer, identity_buf!, password_buf!));
|
this._v = new BigInteger(SRP.computeVerifier(params, salt_buf as Buffer, identity_buf!, password_buf!));
|
||||||
@ -531,34 +544,40 @@ export class SrpServer {
|
|||||||
this._s = salt_buf as Buffer;
|
this._s = salt_buf as Buffer;
|
||||||
} else if (salt_buf instanceof Buffer) {
|
} else if (salt_buf instanceof Buffer) {
|
||||||
const verifier_buf = salt_buf;
|
const verifier_buf = salt_buf;
|
||||||
|
// noinspection JSUnusedAssignment
|
||||||
[secret2_buf, salt_buf, identity_buf, password_buf] = [identity_buf, undefined, undefined, undefined];
|
[secret2_buf, salt_buf, identity_buf, password_buf] = [identity_buf, undefined, undefined, undefined];
|
||||||
|
|
||||||
assertIsBuffer(verifier_buf, 'verifier (v)');
|
assertIsBuffer(verifier_buf, "verifier (v)");
|
||||||
assertIsBuffer(secret2_buf!, 'secret2');
|
assertIsBuffer(secret2_buf!, "secret2");
|
||||||
|
|
||||||
this._b = new BigInteger(secret2_buf!);
|
this._b = new BigInteger(secret2_buf!);
|
||||||
this._v = new BigInteger(verifier_buf);
|
this._v = new BigInteger(verifier_buf);
|
||||||
} else {
|
} else {
|
||||||
const identity = salt_buf as Identity;
|
const identity = salt_buf as Identity;
|
||||||
|
// noinspection JSUnusedAssignment
|
||||||
[secret2_buf, salt_buf, identity_buf, password_buf] = [identity_buf, undefined, undefined, undefined];
|
[secret2_buf, salt_buf, identity_buf, password_buf] = [identity_buf, undefined, undefined, undefined];
|
||||||
|
|
||||||
// noinspection SuspiciousTypeOfGuard
|
// noinspection SuspiciousTypeOfGuard
|
||||||
assert(identity.username instanceof Buffer || typeof identity.username === 'string', 'identity.username (I) must be a string or Buffer');
|
assert(identity.username instanceof Buffer || typeof identity.username === "string", "identity.username (I) must be a string or Buffer");
|
||||||
assertIsBuffer(identity.salt, 'identity.salt (s)');
|
assertIsBuffer(identity.salt, "identity.salt (s)");
|
||||||
assert('password' in identity || 'verifier' in identity, 'identity requires a password or verifier');
|
assert("password" in identity || "verifier" in identity, "identity requires a password or verifier");
|
||||||
if ('verifier' in identity) assertIsBuffer(identity.verifier, 'identity.verifier (v)');
|
if ("verifier" in identity) {
|
||||||
else assert(identity.password instanceof Buffer || typeof identity.password === 'string', 'identity.password (p) must be a string or Buffer');
|
assertIsBuffer(identity.verifier, "identity.verifier (v)");
|
||||||
assertIsBuffer(secret2_buf!, 'secret2');
|
} else {
|
||||||
|
// noinspection SuspiciousTypeOfGuard
|
||||||
|
assert(identity.password instanceof Buffer || typeof identity.password === "string", "identity.password (p) must be a string or Buffer");
|
||||||
|
}
|
||||||
|
assertIsBuffer(secret2_buf!, "secret2");
|
||||||
|
|
||||||
const username = typeof identity.username === 'string' ? Buffer.from(identity.username) : identity.username;
|
const username = typeof identity.username === "string" ? Buffer.from(identity.username) : identity.username;
|
||||||
|
|
||||||
this._b = new BigInteger(secret2_buf!);
|
this._b = new BigInteger(secret2_buf!);
|
||||||
if ('verifier' in identity) {
|
if ("verifier" in identity) {
|
||||||
this._v = new BigInteger(identity.verifier);
|
this._v = new BigInteger(identity.verifier);
|
||||||
} else {
|
} else {
|
||||||
this._v = new BigInteger(SRP.computeVerifier(
|
this._v = new BigInteger(SRP.computeVerifier(
|
||||||
params, identity.salt, username,
|
params, identity.salt, username,
|
||||||
typeof identity.password === 'string' ? Buffer.from(identity.password) : identity.password
|
typeof identity.password === "string" ? Buffer.from(identity.password) : identity.password,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,7 +593,7 @@ export class SrpServer {
|
|||||||
*
|
*
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
computeB() {
|
computeB(): Buffer {
|
||||||
return this._B;
|
return this._B;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,7 +602,7 @@ export class SrpServer {
|
|||||||
*
|
*
|
||||||
* @param {Buffer} A The client's public key
|
* @param {Buffer} A The client's public key
|
||||||
*/
|
*/
|
||||||
setA(A: Buffer) {
|
setA(A: Buffer): void {
|
||||||
const u_num = getu(this._params, A, this._B);
|
const u_num = getu(this._params, A, this._B);
|
||||||
const S_buf = server_getS(this._params, this._v, new BigInteger(A), this._b, u_num);
|
const S_buf = server_getS(this._params, this._v, new BigInteger(A), this._b, u_num);
|
||||||
|
|
||||||
@ -604,11 +623,13 @@ export class SrpServer {
|
|||||||
*
|
*
|
||||||
* @param {Buffer} M1 The client's M1 value
|
* @param {Buffer} M1 The client's M1 value
|
||||||
*/
|
*/
|
||||||
checkM1(M1: Buffer) {
|
checkM1(M1: Buffer): void {
|
||||||
if (this._M1 === undefined)
|
if (this._M1 === undefined) {
|
||||||
throw new Error('incomplete protocol');
|
throw new Error("incomplete protocol");
|
||||||
if (!equal(this._M1, M1))
|
}
|
||||||
throw new Error('client did not use the same password');
|
if (!equal(this._M1, M1)) {
|
||||||
|
throw new Error("client did not use the same password");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -616,9 +637,10 @@ export class SrpServer {
|
|||||||
*
|
*
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
computeK() {
|
computeK(): Buffer {
|
||||||
if (this._K === undefined)
|
if (this._K === undefined) {
|
||||||
throw new Error('incomplete protocol');
|
throw new Error("incomplete protocol");
|
||||||
|
}
|
||||||
return this._K;
|
return this._K;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,9 +650,11 @@ export class SrpServer {
|
|||||||
*
|
*
|
||||||
* @return {Buffer}
|
* @return {Buffer}
|
||||||
*/
|
*/
|
||||||
computeM2() {
|
computeM2(): Buffer {
|
||||||
if (this._M2 === undefined)
|
if (this._M2 === undefined) {
|
||||||
throw new Error('incomplete protocol');
|
throw new Error("incomplete protocol");
|
||||||
|
}
|
||||||
return this._M2;
|
return this._M2;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {hex} from '../params';
|
import { hex } from "../params";
|
||||||
|
|
||||||
// Modulus (N), as specified by the 3072-bit group of RFC 5054
|
// Modulus (N), as specified by the 3072-bit group of RFC 5054
|
||||||
export const N = hex(`
|
export const N = hex(`
|
||||||
@ -17,13 +17,13 @@ export const N = hex(`
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
// Generator (g), as specified by the 3072-bit group of RFC 5054
|
// Generator (g), as specified by the 3072-bit group of RFC 5054
|
||||||
export const g = hex('05');
|
export const g = hex("05");
|
||||||
|
|
||||||
// Username (I), as an ASCII string without quotes
|
// Username (I), as an ASCII string without quotes
|
||||||
export const I = 'alice';
|
export const I = "alice";
|
||||||
|
|
||||||
// Password (p), as an ASCII string without quotes
|
// Password (p), as an ASCII string without quotes
|
||||||
export const p = 'password123';
|
export const p = "password123";
|
||||||
|
|
||||||
// A private (a)
|
// A private (a)
|
||||||
export const a = hex(`
|
export const a = hex(`
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-ignore */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import vows from 'vows';
|
import vows from "vows";
|
||||||
import assert from 'assert';
|
import assert from "assert";
|
||||||
import {SRP, SrpClient, SrpParams, SrpServer} from "../srp";
|
import { SRP, SrpClient, SrpParams, SrpServer } from "../srp";
|
||||||
import BigInteger = require('../../jsbn/jsbn');
|
import BigInteger = require("../../jsbn/jsbn");
|
||||||
|
|
||||||
interface Input {
|
interface Input {
|
||||||
/** Identity */
|
/** Identity */
|
||||||
@ -32,13 +33,14 @@ interface ExpectedOutput {
|
|||||||
M1: Buffer;
|
M1: Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
import {N, g, I, p, a, A, b, B, s, v, u, S, K} from './hap_test_data';
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import {N, g, I, p, a, A, b, B, s, v, u, S, K} from "./hap_test_data";
|
||||||
|
|
||||||
const params = SRP.params.hap;
|
const params = SRP.params.hap;
|
||||||
|
|
||||||
const inputs: Input = {
|
const inputs: Input = {
|
||||||
I: Buffer.from(I, 'ascii'),
|
I: Buffer.from(I, "ascii"),
|
||||||
P: Buffer.from(p, 'ascii'),
|
P: Buffer.from(p, "ascii"),
|
||||||
salt: s.toBuffer(true),
|
salt: s.toBuffer(true),
|
||||||
// a and b are usually random. For testing, we force them to specific values.
|
// a and b are usually random. For testing, we force them to specific values.
|
||||||
a: a.toBuffer(true),
|
a: a.toBuffer(true),
|
||||||
@ -47,9 +49,9 @@ const inputs: Input = {
|
|||||||
|
|
||||||
const expected: ExpectedOutput = {
|
const expected: ExpectedOutput = {
|
||||||
// 'k' encodes the group (N and g), used in SRP-6a
|
// 'k' encodes the group (N and g), used in SRP-6a
|
||||||
k: Buffer.from('a9c2e2559bf0ebb53f0cbbf62282906bede7f2182f00678211fbd5bde5b285033a4993503b87397f9be5ec02080fedbc0835587ad039060879b8621e8c3659e0', 'hex'),
|
k: Buffer.from("a9c2e2559bf0ebb53f0cbbf62282906bede7f2182f00678211fbd5bde5b285033a4993503b87397f9be5ec02080fedbc0835587ad039060879b8621e8c3659e0", "hex"),
|
||||||
// 'x' is derived from the salt and password
|
// 'x' is derived from the salt and password
|
||||||
x: Buffer.from('b149ecb0946b0b206d77e73d95deb7c41bd12e86a5e2eea3893d5416591a002ff94bfea384dc0e1c550f7ed4d5a9d2ad1f1526f01c56b5c10577730cc4a4d709', 'hex'),
|
x: Buffer.from("b149ecb0946b0b206d77e73d95deb7c41bd12e86a5e2eea3893d5416591a002ff94bfea384dc0e1c550f7ed4d5a9d2ad1f1526f01c56b5c10577730cc4a4d709", "hex"),
|
||||||
// 'v' is the SRP verifier
|
// 'v' is the SRP verifier
|
||||||
v: v.toBuffer(true),
|
v: v.toBuffer(true),
|
||||||
// 'B' is the server's public message
|
// 'B' is the server's public message
|
||||||
@ -63,21 +65,21 @@ const expected: ExpectedOutput = {
|
|||||||
// 'K' is the shared derived key
|
// 'K' is the shared derived key
|
||||||
K: K.toBuffer(true),
|
K: K.toBuffer(true),
|
||||||
// 'M1' is the client's proof that it knows the shared key
|
// 'M1' is the client's proof that it knows the shared key
|
||||||
M1: Buffer.from('5f7c14ab57ed0e94fd1d78c6b4dd09ed7e340b7e05d419a9fd760f6b35e523d1310777a1ae1d2826f596f3a85116cc457c7c964d4f44ded5559da818c88b617f', 'hex'),
|
M1: Buffer.from("5f7c14ab57ed0e94fd1d78c6b4dd09ed7e340b7e05d419a9fd760f6b35e523d1310777a1ae1d2826f596f3a85116cc457c7c964d4f44ded5559da818c88b617f", "hex"),
|
||||||
};
|
};
|
||||||
|
|
||||||
function hexequal(a: Buffer, b: Buffer, msg?: string) {
|
function hexequal(a: Buffer, b: Buffer, msg?: string): void {
|
||||||
assert.equal(a.length, b.length, msg);
|
assert.strictEqual(a.length, b.length, msg);
|
||||||
assert.equal(a.toString('hex'), b.toString('hex'), msg);
|
assert.strictEqual(a.toString("hex"), b.toString("hex"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function numequal(a: BigInteger, b: BigInteger, msg?: string) {
|
function numequal(a: BigInteger, b: BigInteger, msg?: string): void {
|
||||||
assert(a.compareTo(b) === 0, msg);
|
assert(a.compareTo(b) === 0, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput, useVerifier = true) {
|
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput, useVerifier = true): void {
|
||||||
hexequal(inputs.I, Buffer.from('616c696365', 'hex'), 'I');
|
hexequal(inputs.I, Buffer.from("616c696365", "hex"), "I");
|
||||||
hexequal(SRP.computeVerifier(params, inputs.salt, inputs.I, inputs.P), expected.v, 'v');
|
hexequal(SRP.computeVerifier(params, inputs.salt, inputs.I, inputs.P), expected.v, "v");
|
||||||
|
|
||||||
const client = new SrpClient(params, inputs.salt, inputs.I, inputs.P, inputs.a, true);
|
const client = new SrpClient(params, inputs.salt, inputs.I, inputs.P, inputs.a, true);
|
||||||
const server = useVerifier ?
|
const server = useVerifier ?
|
||||||
@ -85,9 +87,9 @@ function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput
|
|||||||
new SrpServer(params, inputs.salt, inputs.I, inputs.P, inputs.b);
|
new SrpServer(params, inputs.salt, inputs.I, inputs.P, inputs.b);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(client._k, new BigInteger(expected.k.toString('hex'), 16), 'k');
|
numequal(client._k, new BigInteger(expected.k.toString("hex"), 16), "k");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(client._x, new BigInteger(expected.x.toString('hex'), 16), 'x');
|
numequal(client._x, new BigInteger(expected.x.toString("hex"), 16), "x");
|
||||||
hexequal(client.computeA(), expected.A);
|
hexequal(client.computeA(), expected.A);
|
||||||
hexequal(server.computeB(), expected.B);
|
hexequal(server.computeB(), expected.B);
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput
|
|||||||
client.setB(expected.B);
|
client.setB(expected.B);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(client._u, new BigInteger(expected.u.toString('hex'), 16));
|
numequal(client._u, new BigInteger(expected.u.toString("hex"), 16));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
hexequal(client._S, expected.S);
|
hexequal(client._S, expected.S);
|
||||||
hexequal(client.computeM1(), expected.M1);
|
hexequal(client.computeM1(), expected.M1);
|
||||||
@ -107,15 +109,15 @@ function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput
|
|||||||
|
|
||||||
server.setA(expected.A);
|
server.setA(expected.A);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(server._u, new BigInteger(expected.u.toString('hex'), 16));
|
numequal(server._u, new BigInteger(expected.u.toString("hex"), 16));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
hexequal(server._S, expected.S);
|
hexequal(server._S, expected.S);
|
||||||
assert.throws(() => server.checkM1(Buffer.from('notM1')), /client did not use the same password/);
|
assert.throws(() => server.checkM1(Buffer.from("notM1")), /client did not use the same password/);
|
||||||
server.checkM1(expected.M1); // happy, not throwy
|
server.checkM1(expected.M1); // happy, not throwy
|
||||||
hexequal(server.computeK(), expected.K);
|
hexequal(server.computeK(), expected.K);
|
||||||
}
|
}
|
||||||
|
|
||||||
vows.describe('HomeKit vectors').addBatch({
|
vows.describe("HomeKit vectors").addBatch({
|
||||||
'with verifier': () => checkVectors(params, inputs, expected),
|
"with verifier": () => checkVectors(params, inputs, expected),
|
||||||
'with password': () => checkVectors(params, inputs, expected, false),
|
"with password": () => checkVectors(params, inputs, expected, false),
|
||||||
}).export(module);
|
}).export(module);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-ignore */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import vows from 'vows';
|
import vows from "vows";
|
||||||
import assert from 'assert';
|
import assert from "assert";
|
||||||
import {SRP, SrpClient, SrpParams, SrpServer} from '../srp';
|
import { SRP, SrpClient, SrpParams, SrpServer } from "../srp";
|
||||||
import BigInteger = require('../../jsbn/jsbn');
|
import BigInteger = require("../../jsbn/jsbn");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vectors from https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol
|
* Vectors from https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol
|
||||||
@ -13,8 +14,8 @@ import BigInteger = require('../../jsbn/jsbn');
|
|||||||
* Note that P is the HKDF-stretched key, computed elsewhere.
|
* Note that P is the HKDF-stretched key, computed elsewhere.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function hex(s: string) {
|
function hex(s: string): Buffer {
|
||||||
return Buffer.from(s.split(/\s/).join(''), 'hex');
|
return Buffer.from(s.split(/\s/).join(""), "hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = SRP.params[2048];
|
const params = SRP.params[2048];
|
||||||
@ -53,9 +54,9 @@ interface ExpectedOutput {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const inputs_1: Input = {
|
const inputs_1: Input = {
|
||||||
I: Buffer.from('andré@example.org', 'utf8'),
|
I: Buffer.from("andré@example.org", "utf8"),
|
||||||
P: hex('00f9b71800ab5337 d51177d8fbc682a3 653fa6dae5b87628 eeec43a18af59a9d'),
|
P: hex("00f9b71800ab5337 d51177d8fbc682a3 653fa6dae5b87628 eeec43a18af59a9d"),
|
||||||
salt: hex('00f1000000000000000000000000000000000000000000000000000000000179'),
|
salt: hex("00f1000000000000000000000000000000000000000000000000000000000179"),
|
||||||
// a and b are usually random. For testing, we force them to specific values.
|
// a and b are usually random. For testing, we force them to specific values.
|
||||||
a: hex(`
|
a: hex(`
|
||||||
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
@ -81,10 +82,10 @@ const inputs_1: Input = {
|
|||||||
|
|
||||||
const expected_1: ExpectedOutput = {
|
const expected_1: ExpectedOutput = {
|
||||||
// 'k' encodes the group (N and g), used in SRP-6a
|
// 'k' encodes the group (N and g), used in SRP-6a
|
||||||
k: hex('05b9e8ef059c6b32 ea59fc1d322d37f0 4aa30bae5aa9003b 8321e21ddb04e300'),
|
k: hex("05b9e8ef059c6b32 ea59fc1d322d37f0 4aa30bae5aa9003b 8321e21ddb04e300"),
|
||||||
// 'x' is derived from the salt and password
|
// 'x' is derived from the salt and password
|
||||||
// 'v' is the SRP verifier
|
// 'v' is the SRP verifier
|
||||||
x: hex('b5200337cc3f3f92 6cdddae0b2d31029 c069936a844aff58 779a545be89d0abe'),
|
x: hex("b5200337cc3f3f92 6cdddae0b2d31029 c069936a844aff58 779a545be89d0abe"),
|
||||||
v: hex(`
|
v: hex(`
|
||||||
00173ffa0263e63c cfd6791b8ee2a40f 048ec94cd95aa8a3 125726f9805e0c82
|
00173ffa0263e63c cfd6791b8ee2a40f 048ec94cd95aa8a3 125726f9805e0c82
|
||||||
83c658dc0b607fbb 25db68e68e93f265 8483049c68af7e82 14c49fde2712a775
|
83c658dc0b607fbb 25db68e68e93f265 8483049c68af7e82 14c49fde2712a775
|
||||||
@ -118,7 +119,7 @@ const expected_1: ExpectedOutput = {
|
|||||||
7374d73e79be2c39 75632de562c59647 0bb27bad79c3e2fc ddf194e1666cb9fc
|
7374d73e79be2c39 75632de562c59647 0bb27bad79c3e2fc ddf194e1666cb9fc
|
||||||
`),
|
`),
|
||||||
// 'u' combines the two public messages
|
// 'u' combines the two public messages
|
||||||
u: hex('b284aa1064e87751 50da6b5e2147b47c a7df505bed94a6f4 bb2ad873332ad732'),
|
u: hex("b284aa1064e87751 50da6b5e2147b47c a7df505bed94a6f4 bb2ad873332ad732"),
|
||||||
// 'S' is the shared secret
|
// 'S' is the shared secret
|
||||||
S: hex(`
|
S: hex(`
|
||||||
0092aaf0f527906a a5e8601f5d707907 a03137e1b601e04b 5a1deb02a981f4be
|
0092aaf0f527906a a5e8601f5d707907 a03137e1b601e04b 5a1deb02a981f4be
|
||||||
@ -131,15 +132,15 @@ const expected_1: ExpectedOutput = {
|
|||||||
6001497c27f362ed bafb25e0f045bfdf 9fb02db9c908f103 40a639fe84c31b27
|
6001497c27f362ed bafb25e0f045bfdf 9fb02db9c908f103 40a639fe84c31b27
|
||||||
`),
|
`),
|
||||||
// 'K' is the shared derived key
|
// 'K' is the shared derived key
|
||||||
K: hex('e68fd0112bfa31dc ffc8e9c96a1cbadb 4c3145978ff35c73 e5bf8d30bbc7499a'),
|
K: hex("e68fd0112bfa31dc ffc8e9c96a1cbadb 4c3145978ff35c73 e5bf8d30bbc7499a"),
|
||||||
// 'M1' is the client's proof that it knows the shared key
|
// 'M1' is the client's proof that it knows the shared key
|
||||||
M1: hex('27949ec1e0f16256 33436865edb037e2 3eb6bf5cb91873f2 a2729373c2039008')
|
M1: hex("27949ec1e0f16256 33436865edb037e2 3eb6bf5cb91873f2 a2729373c2039008"),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* inputs_2/expected_2 have leading 0x00 bytes in 'x' and 'u' */
|
/* inputs_2/expected_2 have leading 0x00 bytes in 'x' and 'u' */
|
||||||
const inputs_2: Input = {
|
const inputs_2: Input = {
|
||||||
I: inputs_1.I, P: inputs_1.P,
|
I: inputs_1.I, P: inputs_1.P,
|
||||||
salt: hex('00f1000000000000000000000000000000000000000000000000000000000021'),
|
salt: hex("00f1000000000000000000000000000000000000000000000000000000000021"),
|
||||||
a: hex(`
|
a: hex(`
|
||||||
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
@ -159,11 +160,11 @@ const inputs_2: Input = {
|
|||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000001
|
0000000000000000 0000000000000000 0000000000000000 0000000000000001
|
||||||
`)
|
`),
|
||||||
};
|
};
|
||||||
const expected_2: ExpectedOutput = {
|
const expected_2: ExpectedOutput = {
|
||||||
k: expected_1.k,
|
k: expected_1.k,
|
||||||
x: hex('009b2740fb49284d 69cab7c916d449ee d7dcabf41332b8b8 d6928f529bd1a94e'),
|
x: hex("009b2740fb49284d 69cab7c916d449ee d7dcabf41332b8b8 d6928f529bd1a94e"),
|
||||||
v: hex(`
|
v: hex(`
|
||||||
1cd8b856685672ee 7a5895d897121234 6c17c3472f2696e4 8cdeec5533c06693
|
1cd8b856685672ee 7a5895d897121234 6c17c3472f2696e4 8cdeec5533c06693
|
||||||
179bc24802b762bc c1e1f8fc8abe607a f2f44aac9172e7dd 0c0110e45cf3b700
|
179bc24802b762bc c1e1f8fc8abe607a f2f44aac9172e7dd 0c0110e45cf3b700
|
||||||
@ -197,7 +198,7 @@ const expected_2: ExpectedOutput = {
|
|||||||
cdcb555a6b16e844 5b03e09776eba841 7576dac458afbbd5 2902dfb0282bed79
|
cdcb555a6b16e844 5b03e09776eba841 7576dac458afbbd5 2902dfb0282bed79
|
||||||
`),
|
`),
|
||||||
// 'u' combines the two public messages
|
// 'u' combines the two public messages
|
||||||
u: hex('000e4039be3989ad 088dc17d8ade899a 6409e7e57b3e8518 cee1cbc77e1de243'),
|
u: hex("000e4039be3989ad 088dc17d8ade899a 6409e7e57b3e8518 cee1cbc77e1de243"),
|
||||||
// 'S' is the shared secret
|
// 'S' is the shared secret
|
||||||
S: hex(`
|
S: hex(`
|
||||||
5c7f591d134d19f9 fcedc2b4e3eecd3d 5deadfe7dd42bd59 b1c960516c65ab61
|
5c7f591d134d19f9 fcedc2b4e3eecd3d 5deadfe7dd42bd59 b1c960516c65ab61
|
||||||
@ -210,15 +211,15 @@ const expected_2: ExpectedOutput = {
|
|||||||
e75f0058f718ec14 f9bbeb29ff966e00 ddfdd2d38a1c7a68 ac455a57b972d528
|
e75f0058f718ec14 f9bbeb29ff966e00 ddfdd2d38a1c7a68 ac455a57b972d528
|
||||||
`),
|
`),
|
||||||
// 'K' is the shared derived key
|
// 'K' is the shared derived key
|
||||||
K: hex('b637ede0b7a31c46 b2567e855eb8a7f7 a994937deee76479 62afbe35d6929709'),
|
K: hex("b637ede0b7a31c46 b2567e855eb8a7f7 a994937deee76479 62afbe35d6929709"),
|
||||||
// 'M1' is the client's proof that it knows the shared key
|
// 'M1' is the client's proof that it knows the shared key
|
||||||
M1: hex('67c83797eb1a3987 e2d48d287e3bd772 d25db2b3cd86ea22 c8cf3ae932a1e45b')
|
M1: hex("67c83797eb1a3987 e2d48d287e3bd772 d25db2b3cd86ea22 c8cf3ae932a1e45b"),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* inputs_3/expected_3 have leading 0x00 bytes in 'x' and 'K' */
|
/* inputs_3/expected_3 have leading 0x00 bytes in 'x' and 'K' */
|
||||||
const inputs_3: Input = {
|
const inputs_3: Input = {
|
||||||
I: inputs_2.I, P: inputs_2.P,
|
I: inputs_2.I, P: inputs_2.P,
|
||||||
salt: hex('00f1000000000000000000000000000000000000000000000000000000000021'),
|
salt: hex("00f1000000000000000000000000000000000000000000000000000000000021"),
|
||||||
a: hex(`
|
a: hex(`
|
||||||
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
@ -229,7 +230,7 @@ const inputs_3: Input = {
|
|||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 00000000000001a0
|
0000000000000000 0000000000000000 0000000000000000 00000000000001a0
|
||||||
`),
|
`),
|
||||||
b: inputs_2.b
|
b: inputs_2.b,
|
||||||
};
|
};
|
||||||
const expected_3: ExpectedOutput = {
|
const expected_3: ExpectedOutput = {
|
||||||
k: expected_2.k,
|
k: expected_2.k,
|
||||||
@ -246,7 +247,7 @@ const expected_3: ExpectedOutput = {
|
|||||||
6c7011f3c979eaab 469f06465a5b7239 afaee535aedc5bd2 1a220546e0e6b70b
|
6c7011f3c979eaab 469f06465a5b7239 afaee535aedc5bd2 1a220546e0e6b70b
|
||||||
5b6f54db3fea46d5 7ebc7fe46156d793 c59e6290d3cf9bc2 4316528da34f4640
|
5b6f54db3fea46d5 7ebc7fe46156d793 c59e6290d3cf9bc2 4316528da34f4640
|
||||||
`),
|
`),
|
||||||
u: hex('865d0efca6cf17d6 f489e129231f1a48 b20c83ec6581d11f 3a2fa48ea93cd305'),
|
u: hex("865d0efca6cf17d6 f489e129231f1a48 b20c83ec6581d11f 3a2fa48ea93cd305"),
|
||||||
S: hex(`
|
S: hex(`
|
||||||
0ae26456e1a0dec1 ce162fb2e5bc7300 3c285e17c0b44f03 7ebbc57f8020ceae
|
0ae26456e1a0dec1 ce162fb2e5bc7300 3c285e17c0b44f03 7ebbc57f8020ceae
|
||||||
5d10a9e6e44eab2a 6915b582ab5f6e7d 16002ce05e524015 e9bc7c56d5131da4
|
5d10a9e6e44eab2a 6915b582ab5f6e7d 16002ce05e524015 e9bc7c56d5131da4
|
||||||
@ -257,14 +258,14 @@ const expected_3: ExpectedOutput = {
|
|||||||
249f7734081aa42d 58dd54f8f725b245 175cf7d102e1086c eba4cfe7e49a2d27
|
249f7734081aa42d 58dd54f8f725b245 175cf7d102e1086c eba4cfe7e49a2d27
|
||||||
ffd6aef7549d402f bfcea78b4f3398ac 9ab1ee199f70acb6 4d2a17e159ff500d
|
ffd6aef7549d402f bfcea78b4f3398ac 9ab1ee199f70acb6 4d2a17e159ff500d
|
||||||
`),
|
`),
|
||||||
K: hex('00217598a4008956 4b17196bd43422d6 03a0a88a545b61b3 98c42c9cbcc1d1b3'),
|
K: hex("00217598a4008956 4b17196bd43422d6 03a0a88a545b61b3 98c42c9cbcc1d1b3"),
|
||||||
M1: hex('96d815ecece1dff4 254cd77517b37b97 65e741c1a57169ab af538e867444ec7f')
|
M1: hex("96d815ecece1dff4 254cd77517b37b97 65e741c1a57169ab af538e867444ec7f"),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* inputs_4/expected_4 have leading 0x00 bytes in 'x' and 'M1' */
|
/* inputs_4/expected_4 have leading 0x00 bytes in 'x' and 'M1' */
|
||||||
const inputs_4: Input = {
|
const inputs_4: Input = {
|
||||||
I: inputs_2.I, P: inputs_2.P,
|
I: inputs_2.I, P: inputs_2.P,
|
||||||
salt: hex('00f1000000000000000000000000000000000000000000000000000000000021'),
|
salt: hex("00f1000000000000000000000000000000000000000000000000000000000021"),
|
||||||
a: hex(`
|
a: hex(`
|
||||||
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
00f2000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
@ -275,7 +276,7 @@ const inputs_4: Input = {
|
|||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
0000000000000000 0000000000000000 0000000000000000 0000000000000000
|
||||||
0000000000000000 0000000000000000 0000000000000000 0000000000000190
|
0000000000000000 0000000000000000 0000000000000000 0000000000000190
|
||||||
`),
|
`),
|
||||||
b: inputs_2.b
|
b: inputs_2.b,
|
||||||
};
|
};
|
||||||
const expected_4: ExpectedOutput = {
|
const expected_4: ExpectedOutput = {
|
||||||
k: expected_2.k,
|
k: expected_2.k,
|
||||||
@ -292,7 +293,7 @@ const expected_4: ExpectedOutput = {
|
|||||||
c690f9478d5b331d c00eef68670edbf3 629fd1a6c85267d2 cbb90f1670e7ba09
|
c690f9478d5b331d c00eef68670edbf3 629fd1a6c85267d2 cbb90f1670e7ba09
|
||||||
cf2b5a9b00be8e11 f33e47a1c1f04eca f35bccb61af1116e 4d0f9d475017bad2
|
cf2b5a9b00be8e11 f33e47a1c1f04eca f35bccb61af1116e 4d0f9d475017bad2
|
||||||
`),
|
`),
|
||||||
u: hex('d0913eb75b61e15a 87756ffa04d4f967 e492bd0b330a2b11 fe8976aada2bb1ee'),
|
u: hex("d0913eb75b61e15a 87756ffa04d4f967 e492bd0b330a2b11 fe8976aada2bb1ee"),
|
||||||
S: hex(`
|
S: hex(`
|
||||||
7ba3ce4a3d236b95 3c2d0fee42195c85 081664a44f55b82d a3abf66ac68bdbd7
|
7ba3ce4a3d236b95 3c2d0fee42195c85 081664a44f55b82d a3abf66ac68bdbd7
|
||||||
ad82d5ad95090782 5241fb706de8fc58 0a29e4579fbbedf3 0bec0138b3f76e06
|
ad82d5ad95090782 5241fb706de8fc58 0a29e4579fbbedf3 0bec0138b3f76e06
|
||||||
@ -303,30 +304,30 @@ const expected_4: ExpectedOutput = {
|
|||||||
d4a9bf0242bfe703 26fc19b68c90e83b 59b5cc21886ab602 f8bfa16fb50c3147
|
d4a9bf0242bfe703 26fc19b68c90e83b 59b5cc21886ab602 f8bfa16fb50c3147
|
||||||
9aad5e31698abf67 863b7ca6b6ac25a7 09a24d8f94c80bbf 691e38c81beb3c72
|
9aad5e31698abf67 863b7ca6b6ac25a7 09a24d8f94c80bbf 691e38c81beb3c72
|
||||||
`),
|
`),
|
||||||
K: hex('bd2a167a93b8496e 68c7e24b37956924 672eb8249d25c281 13984912d5cf27a6'),
|
K: hex("bd2a167a93b8496e 68c7e24b37956924 672eb8249d25c281 13984912d5cf27a6"),
|
||||||
M1: hex('00cef66a047d506c bf941c236218e583 5343534ae08cf0cd 0fb7980bed242e05')
|
M1: hex("00cef66a047d506c bf941c236218e583 5343534ae08cf0cd 0fb7980bed242e05"),
|
||||||
};
|
};
|
||||||
|
|
||||||
function hexequal(a: Buffer, b: Buffer, msg?: string) {
|
function hexequal(a: Buffer, b: Buffer, msg?: string): void {
|
||||||
assert.equal(a.length, b.length, msg);
|
assert.strictEqual(a.length, b.length, msg);
|
||||||
assert.equal(a.toString('hex'), b.toString('hex'), msg);
|
assert.strictEqual(a.toString("hex"), b.toString("hex"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function numequal(a: BigInteger, b: BigInteger, msg?: string) {
|
function numequal(a: BigInteger, b: BigInteger, msg?: string): void {
|
||||||
assert(a.compareTo(b) === 0, msg);
|
assert(a.compareTo(b) === 0, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput) {
|
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput): void {
|
||||||
hexequal(inputs.I, Buffer.from('616e6472c3a9406578616d706c652e6f7267', 'hex'), 'I');
|
hexequal(inputs.I, Buffer.from("616e6472c3a9406578616d706c652e6f7267", "hex"), "I");
|
||||||
hexequal(SRP.computeVerifier(params, inputs.salt, inputs.I, inputs.P), expected.v, 'v');
|
hexequal(SRP.computeVerifier(params, inputs.salt, inputs.I, inputs.P), expected.v, "v");
|
||||||
|
|
||||||
const client = new SrpClient(params, inputs.salt, inputs.I, inputs.P, inputs.a, false);
|
const client = new SrpClient(params, inputs.salt, inputs.I, inputs.P, inputs.a, false);
|
||||||
const server = new SrpServer(params, expected.v, inputs.b);
|
const server = new SrpServer(params, expected.v, inputs.b);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(client._k, new BigInteger(expected.k.toString('hex'), 16), 'k');
|
numequal(client._k, new BigInteger(expected.k.toString("hex"), 16), "k");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(client._x, new BigInteger(expected.x.toString('hex'), 16), 'x');
|
numequal(client._x, new BigInteger(expected.x.toString("hex"), 16), "x");
|
||||||
hexequal(client.computeA(), expected.A);
|
hexequal(client.computeA(), expected.A);
|
||||||
hexequal(server.computeB(), expected.B);
|
hexequal(server.computeB(), expected.B);
|
||||||
|
|
||||||
@ -338,7 +339,7 @@ function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput
|
|||||||
client.setB(expected.B);
|
client.setB(expected.B);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(client._u, new BigInteger(expected.u.toString('hex'), 16));
|
numequal(client._u, new BigInteger(expected.u.toString("hex"), 16));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
hexequal(client._S, expected.S);
|
hexequal(client._S, expected.S);
|
||||||
hexequal(client.computeM1(), expected.M1);
|
hexequal(client.computeM1(), expected.M1);
|
||||||
@ -346,17 +347,17 @@ function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput
|
|||||||
|
|
||||||
server.setA(expected.A);
|
server.setA(expected.A);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
numequal(server._u, new BigInteger(expected.u.toString('hex'), 16));
|
numequal(server._u, new BigInteger(expected.u.toString("hex"), 16));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
hexequal(server._S, expected.S);
|
hexequal(server._S, expected.S);
|
||||||
assert.throws(() => server.checkM1(Buffer.from('notM1')), /client did not use the same password/);
|
assert.throws(() => server.checkM1(Buffer.from("notM1")), /client did not use the same password/);
|
||||||
server.checkM1(expected.M1); // happy, not throwy
|
server.checkM1(expected.M1); // happy, not throwy
|
||||||
hexequal(server.computeK(), expected.K);
|
hexequal(server.computeK(), expected.K);
|
||||||
}
|
}
|
||||||
|
|
||||||
vows.describe('picl vectors').addBatch({
|
vows.describe("picl vectors").addBatch({
|
||||||
'vectors 1': () => checkVectors(params, inputs_1, expected_1),
|
"vectors 1": () => checkVectors(params, inputs_1, expected_1),
|
||||||
'vectors 2': () => checkVectors(params, inputs_2, expected_2),
|
"vectors 2": () => checkVectors(params, inputs_2, expected_2),
|
||||||
'vectors 3': () => checkVectors(params, inputs_3, expected_3),
|
"vectors 3": () => checkVectors(params, inputs_3, expected_3),
|
||||||
'vectors 4': () => checkVectors(params, inputs_4, expected_4),
|
"vectors 4": () => checkVectors(params, inputs_4, expected_4),
|
||||||
}).export(module);
|
}).export(module);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-ignore */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import vows from 'vows';
|
import vows from "vows";
|
||||||
import assert from 'assert';
|
import assert from "assert";
|
||||||
import {SRP, SrpClient, SrpServer} from '../srp';
|
import { SRP, SrpClient, SrpServer } from "../srp";
|
||||||
import BigInteger = require('../../jsbn/jsbn');
|
import BigInteger = require("../../jsbn/jsbn");
|
||||||
|
|
||||||
const params = SRP.params[1024];
|
const params = SRP.params[1024];
|
||||||
|
|
||||||
@ -10,15 +11,15 @@ const params = SRP.params[1024];
|
|||||||
* http://tools.ietf.org/html/rfc5054#appendix-B
|
* http://tools.ietf.org/html/rfc5054#appendix-B
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function hex(h: string) {
|
function hex(h: string): string {
|
||||||
return h.split(/\s/).join('');
|
return h.split(/\s/).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
const I = Buffer.from('alice');
|
const I = Buffer.from("alice");
|
||||||
const P = Buffer.from('password123');
|
const P = Buffer.from("password123");
|
||||||
const s = Buffer.from('beb25379d1a8581eb5a727673a2441ee', 'hex');
|
const s = Buffer.from("beb25379d1a8581eb5a727673a2441ee", "hex");
|
||||||
const k_expected = '7556aa045aef2cdd07abaf0f665c3e818913186f';
|
const k_expected = "7556aa045aef2cdd07abaf0f665c3e818913186f";
|
||||||
const x_expected = '94b7555aabe9127cc58ccf4993db6cf84d16c124';
|
const x_expected = "94b7555aabe9127cc58ccf4993db6cf84d16c124";
|
||||||
const v_expected = hex(`
|
const v_expected = hex(`
|
||||||
7e273de8 696ffc4f 4e337d05 b4b375be b0dde156 9e8fa00a 9886d812
|
7e273de8 696ffc4f 4e337d05 b4b375be b0dde156 9e8fa00a 9886d812
|
||||||
9bada1f1 822223ca 1a605b53 0e379ba4 729fdc59 f105b478 7e5186f5
|
9bada1f1 822223ca 1a605b53 0e379ba4 729fdc59 f105b478 7e5186f5
|
||||||
@ -26,8 +27,8 @@ const v_expected = hex(`
|
|||||||
ea53d15c 1aff87b2 b9da6e04 e058ad51 cc72bfc9 033b564e 26480d78
|
ea53d15c 1aff87b2 b9da6e04 e058ad51 cc72bfc9 033b564e 26480d78
|
||||||
e955a5e2 9e7ab245 db2be315 e2099afb
|
e955a5e2 9e7ab245 db2be315 e2099afb
|
||||||
`);
|
`);
|
||||||
const a = Buffer.from('60975527035cf2ad1989806f0407210bc81edc04e2762a56afd529ddda2d4393', 'hex');
|
const a = Buffer.from("60975527035cf2ad1989806f0407210bc81edc04e2762a56afd529ddda2d4393", "hex");
|
||||||
const b = Buffer.from('e487cb59d31ac550471e81f00f6928e01dda08e974a004f49e61f5d105284d20', 'hex');
|
const b = Buffer.from("e487cb59d31ac550471e81f00f6928e01dda08e974a004f49e61f5d105284d20", "hex");
|
||||||
const A_expected = hex(`
|
const A_expected = hex(`
|
||||||
61d5e490 f6f1b795 47b0704c 436f523d d0e560f0 c64115bb 72557ec4
|
61d5e490 f6f1b795 47b0704c 436f523d d0e560f0 c64115bb 72557ec4
|
||||||
4352e890 3211c046 92272d8b 2d1a5358 a2cf1b6e 0bfcf99f 921530ec
|
4352e890 3211c046 92272d8b 2d1a5358 a2cf1b6e 0bfcf99f 921530ec
|
||||||
@ -42,7 +43,7 @@ const B_expected = hex(`
|
|||||||
37089e6f 9c6059f3 88838e7a 00030b33 1eb76840 910440b1 b27aaeae
|
37089e6f 9c6059f3 88838e7a 00030b33 1eb76840 910440b1 b27aaeae
|
||||||
eb4012b7 d7665238 a8e3fb00 4b117b58
|
eb4012b7 d7665238 a8e3fb00 4b117b58
|
||||||
`);
|
`);
|
||||||
const u_expected = 'ce38b9593487da98554ed47d70a7ae5f462ef019';
|
const u_expected = "ce38b9593487da98554ed47d70a7ae5f462ef019";
|
||||||
const S_expected = hex(`
|
const S_expected = hex(`
|
||||||
b0dc82ba bcf30674 ae450c02 87745e79 90a3381f 63b387aa f271a10d
|
b0dc82ba bcf30674 ae450c02 87745e79 90a3381f 63b387aa f271a10d
|
||||||
233861e3 59b48220 f7c4693c 9ae12b0a 6f67809f 0876e2d0 13800d6c
|
233861e3 59b48220 f7c4693c 9ae12b0a 6f67809f 0876e2d0 13800d6c
|
||||||
@ -51,61 +52,61 @@ const S_expected = hex(`
|
|||||||
c346d7e4 74b29ede 8a469ffe ca686e5a
|
c346d7e4 74b29ede 8a469ffe ca686e5a
|
||||||
`);
|
`);
|
||||||
|
|
||||||
function asHex(num: number | BigInteger) {
|
function asHex(num: number | BigInteger): string {
|
||||||
return num.toString(16);
|
return num.toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
vows.describe('RFC 5054').addBatch({
|
vows.describe("RFC 5054").addBatch({
|
||||||
'Test vectors': {
|
"Test vectors": {
|
||||||
topic() {
|
topic(): Buffer {
|
||||||
return SRP.computeVerifier(params, s, I, P);
|
return SRP.computeVerifier(params, s, I, P);
|
||||||
},
|
},
|
||||||
|
|
||||||
'x'() {
|
"x"(): void {
|
||||||
const client = new SrpClient(params, s, I, P, a, false);
|
const client = new SrpClient(params, s, I, P, a, false);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
assert.equal(asHex(client._x), x_expected);
|
assert.strictEqual(asHex(client._x), x_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'V'(v: Buffer) {
|
"V"(v: Buffer): void {
|
||||||
assert.equal(v.toString('hex'), v_expected);
|
assert.strictEqual(v.toString("hex"), v_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'k'() {
|
"k"(): void {
|
||||||
const client = new SrpClient(params, s, I, P, a, false);
|
const client = new SrpClient(params, s, I, P, a, false);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
assert.equal(asHex(client._k), k_expected);
|
assert.strictEqual(asHex(client._k), k_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'A'() {
|
"A"(): void {
|
||||||
const client = new SrpClient(params, s, I, P, a, false);
|
const client = new SrpClient(params, s, I, P, a, false);
|
||||||
assert.equal(client.computeA().toString('hex'), A_expected);
|
assert.strictEqual(client.computeA().toString("hex"), A_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'B'(v: Buffer) {
|
"B"(v: Buffer): void {
|
||||||
const server = new SrpServer(params, v, b);
|
const server = new SrpServer(params, v, b);
|
||||||
assert.equal(server.computeB().toString('hex'), B_expected);
|
assert.strictEqual(server.computeB().toString("hex"), B_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'u'() {
|
"u"(): void {
|
||||||
const client = new SrpClient(params, s, I, P, a, false);
|
const client = new SrpClient(params, s, I, P, a, false);
|
||||||
client.setB(Buffer.from(B_expected, 'hex'));
|
client.setB(Buffer.from(B_expected, "hex"));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
assert.equal(asHex(client._u), u_expected);
|
assert.strictEqual(asHex(client._u), u_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'S client'() {
|
"S client"(): void {
|
||||||
const client = new SrpClient(params, s, I, P, a, false);
|
const client = new SrpClient(params, s, I, P, a, false);
|
||||||
client.setB(Buffer.from(B_expected, 'hex'));
|
client.setB(Buffer.from(B_expected, "hex"));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
assert.equal(client._S.toString('hex'), S_expected);
|
assert.strictEqual(client._S.toString("hex"), S_expected);
|
||||||
},
|
},
|
||||||
|
|
||||||
'S server'(v: Buffer) {
|
"S server"(v: Buffer): void {
|
||||||
const server = new SrpServer(params, v, b);
|
const server = new SrpServer(params, v, b);
|
||||||
server.setA(Buffer.from(A_expected, 'hex'));
|
server.setA(Buffer.from(A_expected, "hex"));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
assert.equal(server._S.toString('hex'), S_expected);
|
assert.strictEqual(server._S.toString("hex"), S_expected);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).export(module);
|
}).export(module);
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import vows from 'vows';
|
import vows from "vows";
|
||||||
import assert from 'assert';
|
import assert from "assert";
|
||||||
import {SRP, SrpClient, SrpServer} from '../srp';
|
import { SRP, SrpClient, SrpServer } from "../srp";
|
||||||
|
|
||||||
const params = SRP.params[4096];
|
const params = SRP.params[4096];
|
||||||
|
|
||||||
const salt = Buffer.from('salty');
|
const salt = Buffer.from("salty");
|
||||||
const identity = Buffer.from('alice');
|
const identity = Buffer.from("alice");
|
||||||
const password = Buffer.from('password123');
|
const password = Buffer.from("password123");
|
||||||
|
|
||||||
assert(params, 'missing parameters');
|
assert(params, "missing parameters");
|
||||||
|
|
||||||
let client: SrpClient, server: SrpServer;
|
let client: SrpClient, server: SrpServer;
|
||||||
let a: Buffer, A: Buffer;
|
let a: Buffer, A: Buffer;
|
||||||
@ -17,20 +18,23 @@ let b: Buffer, B: Buffer;
|
|||||||
let verifier: Buffer;
|
let verifier: Buffer;
|
||||||
// let S_client, S_server;
|
// let S_client, S_server;
|
||||||
|
|
||||||
vows.describe('srp.js').addBatch({
|
vows.describe("srp.js").addBatch({
|
||||||
'create Verifier'() {
|
"create Verifier"() {
|
||||||
verifier = SRP.computeVerifier(params, salt, identity, password);
|
verifier = SRP.computeVerifier(params, salt, identity, password);
|
||||||
assert.equal(verifier.toString('hex'), 'f0e47f50f5dead8db8d93a279e3b62d6ff50854b31fbd3474a886bef916261717e84dd4fb8b4d27feaa5146db7b1cbbc274fdf96a132b5029c2cd72527427a9b9809d5a4d018252928b4fc343bc17ce63c1859d5806f5466014fc361002d8890aeb4d6316ff37331fc2761be0144c91cdd8e00ed0138c0ce51534d1b9a9ba629d7be34d2742dd4097daabc9ecb7aaad89e53c342b038f1d2adae1f2410b7884a3e9a124c357e421bccd4524467e1922660e0a4460c5f7c38c0877b65f6e32f28296282a93fc11bbabb7bb69bf1b3f9391991d8a86dd05e15000b7e38ba38a536bb0bf59c808ec25e791b8944719488b8087df8bfd7ff20822997a53f6c86f3d45d004476d6303301376bb25a9f94b552cce5ed40de5dd7da8027d754fa5f66738c7e3fc4ef3e20d625df62cbe6e7adfc21e47880d8a6ada37e60370fd4d8fc82672a90c29f2e72f35652649d68348de6f36d0e435c8bd42dd00155d35d501becc0661b43e04cdb2da84ce92b8bf49935d73d75efcbd1176d7bbccc3cc4d4b5fefcc02d478614ee1681d2ff3c711a61a7686eb852ae06fb8227be21fb8802719b1271ba1c02b13bbf0a2c2e459d9bedcc8d1269f6a785cb4563aa791b38fb038269f63f58f47e9051499549789269cc7b8ec7026fc34ba73289c4af829d5a532e723967ce9b6c023ef0fd0cfe37f51f10f19463b6534159a09ddd2f51f3b30033');
|
assert.strictEqual(verifier.toString("hex"), "f0e47f50f5dead8db8d93a279e3b62d6ff50854b31fbd3474a886bef916261717e84dd4fb8b4d27feaa5146db7b1cbbc274fdf96a132b5029c2cd72527427a9b9809d5a4d018252928b4fc343bc17ce63c1859d5806f5466014fc361002d8890aeb4d6316ff37331fc2761be0144c91cdd8e00ed0138c0ce51534d1b9a9ba629d7be34d2742dd4097daabc9ecb7aaad89e53c342b038f1d2adae1f2410b7884a3e9a124c357e421bccd4524467e1922660e0a4460c5f7c38c0877b65f6e32f28296282a93fc11bbabb7bb69bf1b3f9391991d8a86dd05e15000b7e38ba38a536bb0bf59c808ec25e791b8944719488b8087df8bfd7ff20822997a53f6c86f3d45d004476d6303301376bb25a9f94b552cce5ed40de5dd7da8027d754fa5f66738c7e3fc4ef3e20d625df62cbe6e7adfc21e47880d8a6ada37e60370fd4d8fc82672a90c29f2e72f35652649d68348de6f36d0e435c8bd42dd00155d35d501becc0661b43e04cdb2da84ce92b8bf49935d73d75efcbd1176d7bbccc3cc4d4b5fefcc02d478614ee1681d2ff3c711a61a7686eb852ae06fb8227be21fb8802719b1271ba1c02b13bbf0a2c2e459d9bedcc8d1269f6a785cb4563aa791b38fb038269f63f58f47e9051499549789269cc7b8ec7026fc34ba73289c4af829d5a532e723967ce9b6c023ef0fd0cfe37f51f10f19463b6534159a09ddd2f51f3b30033");
|
||||||
},
|
},
|
||||||
|
|
||||||
'create a and b': {
|
"create a and b": {
|
||||||
topic(this: any) {(async () => {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
a = await SRP.genKey(64);
|
topic(this: any): void {
|
||||||
b = await SRP.genKey(32);
|
(async (): Promise<void> => {
|
||||||
this.callback();
|
a = await SRP.genKey(64);
|
||||||
})()},
|
b = await SRP.genKey(32);
|
||||||
|
this.callback();
|
||||||
|
})();
|
||||||
|
},
|
||||||
|
|
||||||
'use a and b'() {
|
"use a and b"(): void {
|
||||||
client = new SrpClient(params, salt, identity, password, a, false);
|
client = new SrpClient(params, salt, identity, password, a, false);
|
||||||
|
|
||||||
// client produces A
|
// client produces A
|
||||||
@ -61,51 +65,51 @@ vows.describe('srp.js').addBatch({
|
|||||||
// client and server agree on K
|
// client and server agree on K
|
||||||
const client_K = client.computeK();
|
const client_K = client.computeK();
|
||||||
const server_K = server.computeK();
|
const server_K = server.computeK();
|
||||||
assert.equal(client_K.toString('hex'), server_K.toString('hex'));
|
assert.strictEqual(client_K.toString("hex"), server_K.toString("hex"));
|
||||||
|
|
||||||
// server is authentic
|
// server is authentic
|
||||||
assert.doesNotThrow(() => client.checkM2(serverM2), 'M2 didn\'t check');
|
assert.doesNotThrow(() => client.checkM2(serverM2), "M2 didn't check");
|
||||||
},
|
},
|
||||||
|
|
||||||
'server rejects wrong M1'() {
|
"server rejects wrong M1"(): void {
|
||||||
const bad_client = new SrpClient(params, salt, identity, Buffer.from('bad'), a, false);
|
const bad_client = new SrpClient(params, salt, identity, Buffer.from("bad"), a, false);
|
||||||
const server2 = new SrpServer(params, verifier, b);
|
const server2 = new SrpServer(params, verifier, b);
|
||||||
bad_client.setB(server2.computeB());
|
bad_client.setB(server2.computeB());
|
||||||
assert.throws(() => server.checkM1(bad_client.computeM1()), /client did not use the same password/);
|
assert.throws(() => server.checkM1(bad_client.computeM1()), /client did not use the same password/);
|
||||||
},
|
},
|
||||||
|
|
||||||
'server rejects bad A'() {
|
"server rejects bad A"(): void {
|
||||||
// client's "A" must be 1..N-1 . Reject 0 and N and N+1. We should
|
// client's "A" must be 1..N-1 . Reject 0 and N and N+1. We should
|
||||||
// reject 2*N too, but our Buffer-length checks reject it before the
|
// reject 2*N too, but our Buffer-length checks reject it before the
|
||||||
// number itself is examined.
|
// number itself is examined.
|
||||||
|
|
||||||
var server2 = new SrpServer(params, verifier, b);
|
const server2 = new SrpServer(params, verifier, b);
|
||||||
var Azero = Buffer.alloc(params.N_length_bits / 8);
|
const Azero = Buffer.alloc(params.N_length_bits / 8);
|
||||||
Azero.fill(0);
|
Azero.fill(0);
|
||||||
//! var AN = params.N.toBuffer();
|
//! var AN = params.N.toBuffer();
|
||||||
//! var AN1 = params.N.add(1).toBuffer();
|
//! var AN1 = params.N.add(1).toBuffer();
|
||||||
var AN = Buffer.from(params.N.toString(16), 'hex');
|
const AN = Buffer.from(params.N.toString(16), "hex");
|
||||||
var AN1 = Buffer.from(params.N.add(1).toString(16), 'hex');
|
const AN1 = Buffer.from(params.N.add(1).toString(16), "hex");
|
||||||
assert.throws(() => server2.setA(Azero), /invalid client-supplied "A"/);
|
assert.throws(() => server2.setA(Azero), /invalid client-supplied "A"/);
|
||||||
assert.throws(() => server2.setA(AN), /invalid client-supplied "A"/);
|
assert.throws(() => server2.setA(AN), /invalid client-supplied "A"/);
|
||||||
assert.throws(() => server2.setA(AN1), /invalid client-supplied "A"/);
|
assert.throws(() => server2.setA(AN1), /invalid client-supplied "A"/);
|
||||||
},
|
},
|
||||||
|
|
||||||
'client rejects bad B'() {
|
"client rejects bad B"(): void {
|
||||||
// server's "B" must be 1..N-1 . Reject 0 and N and N+1
|
// server's "B" must be 1..N-1 . Reject 0 and N and N+1
|
||||||
var client2 = new SrpClient(params, salt, identity, password, a, false);
|
const client2 = new SrpClient(params, salt, identity, password, a, false);
|
||||||
var Bzero = Buffer.alloc(params.N_length_bits / 8);
|
const Bzero = Buffer.alloc(params.N_length_bits / 8);
|
||||||
Bzero.fill(0, 0, params.N_length_bits / 8);
|
Bzero.fill(0, 0, params.N_length_bits / 8);
|
||||||
//! var BN = params.N.toBuffer();
|
//! var BN = params.N.toBuffer();
|
||||||
//! var BN1 = params.N.add(1).toBuffer();
|
//! var BN1 = params.N.add(1).toBuffer();
|
||||||
var BN = Buffer.from(params.N.toString(16), 'hex');
|
const BN = Buffer.from(params.N.toString(16), "hex");
|
||||||
var BN1 = Buffer.from(params.N.add(1).toString(16), 'hex');
|
const BN1 = Buffer.from(params.N.add(1).toString(16), "hex");
|
||||||
assert.throws(() => client2.setB(Bzero), /invalid server-supplied "B"/);
|
assert.throws(() => client2.setB(Bzero), /invalid server-supplied "B"/);
|
||||||
assert.throws(() => client2.setB(BN), /invalid server-supplied "B"/);
|
assert.throws(() => client2.setB(BN), /invalid server-supplied "B"/);
|
||||||
assert.throws(() => client2.setB(BN1), /invalid server-supplied "B"/);
|
assert.throws(() => client2.setB(BN1), /invalid server-supplied "B"/);
|
||||||
},
|
},
|
||||||
|
|
||||||
'client rejects bad M2'() {
|
"client rejects bad M2"(): void {
|
||||||
client = new SrpClient(params, salt, identity, password, a, false);
|
client = new SrpClient(params, salt, identity, password, a, false);
|
||||||
|
|
||||||
// client produces A
|
// client produces A
|
||||||
@ -130,15 +134,15 @@ vows.describe('srp.js').addBatch({
|
|||||||
server.checkM1(client.computeM1());
|
server.checkM1(client.computeM1());
|
||||||
let serverM2 = server.computeM2();
|
let serverM2 = server.computeM2();
|
||||||
// we tamper with the server's M2
|
// we tamper with the server's M2
|
||||||
serverM2 = Buffer.from('a');
|
serverM2 = Buffer.from("a");
|
||||||
|
|
||||||
// client and server agree on K
|
// client and server agree on K
|
||||||
var client_K = client.computeK();
|
const client_K = client.computeK();
|
||||||
var server_K = server.computeK();
|
const server_K = server.computeK();
|
||||||
assert.equal(client_K.toString('hex'), server_K.toString('hex'));
|
assert.strictEqual(client_K.toString("hex"), server_K.toString("hex"));
|
||||||
|
|
||||||
// server is NOT authentic
|
// server is NOT authentic
|
||||||
assert.throws(() => client.checkM2(serverM2), 'M2 didn\'t check');
|
assert.throws(() => client.checkM2(serverM2), "M2 didn't check");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).export(module);
|
}).export(module);
|
||||||
|
Loading…
Reference in New Issue
Block a user