mirror of
https://github.com/danog/fast-srp.git
synced 2024-11-26 20:04:49 +01:00
Restructured the project a bit
This commit is contained in:
parent
d8e2938064
commit
462b688de4
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
lib
|
||||
|
14
README.md
14
README.md
@ -9,7 +9,7 @@ Creating the Verifier
|
||||
---
|
||||
|
||||
```ts
|
||||
import * as srp6a from 'fast-srp-hap';
|
||||
import { SRP } from 'fast-srp-hap';
|
||||
|
||||
/**
|
||||
* Computes the verifier of a user. Only needed to add the user to the auth system.
|
||||
@ -19,12 +19,12 @@ import * as srp6a from 'fast-srp-hap';
|
||||
* @return {Promise<{salt: Buffer, verifier: Buffer}>}
|
||||
*/
|
||||
async function srp6a_create_user(I: string, P: string) {
|
||||
const salt = await srp6a.genKey(32);
|
||||
const salt = await SRP.genKey(32);
|
||||
|
||||
return {
|
||||
// The salt is required for authenticating the user later
|
||||
salt,
|
||||
verifier: srp6a.computeVerifier(srp6a.params[4096], salt, Buffer.from(I), Buffer.from(P)),
|
||||
verifier: SRP.computeVerifier(SRP.params[4096], salt, Buffer.from(I), Buffer.from(P)),
|
||||
};
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ Server
|
||||
---
|
||||
|
||||
```ts
|
||||
import {Server, genKey, params} from 'fast-srp-hap';
|
||||
import {SRP, SrpServer} from 'fast-srp-hap';
|
||||
|
||||
(async () => {
|
||||
// Get the user details from somewhere
|
||||
@ -46,7 +46,7 @@ import {Server, genKey, params} from 'fast-srp-hap';
|
||||
username: 'username', // Or a Buffer
|
||||
|
||||
// If we have the plaintext password
|
||||
salt: await genKey(32),
|
||||
salt: await SRP.genKey(32),
|
||||
password: 'password', // Or a Buffer
|
||||
|
||||
// If we have a saved verifier
|
||||
@ -55,9 +55,9 @@ import {Server, genKey, params} from 'fast-srp-hap';
|
||||
};
|
||||
|
||||
// Generate a secret key
|
||||
const secret = await genKey(32);
|
||||
const secret = await SRP.genKey(32);
|
||||
|
||||
const server = new Server(params[3076], user, secret); // For Apple SRP use params.hap
|
||||
const server = new SrpServer(SRP.params[3076], user, secret); // For Apple SRP use params.hap
|
||||
|
||||
// ...
|
||||
})();
|
||||
|
0
lib/jsbn.d.ts → jsbn/jsbn.d.ts
vendored
0
lib/jsbn.d.ts → jsbn/jsbn.d.ts
vendored
14
package-lock.json
generated
14
package-lock.json
generated
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "fast-srp-hap",
|
||||
"version": "1.1.0",
|
||||
"version": "2.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "12.12.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.3.tgz",
|
||||
"integrity": "sha512-opgSsy+cEF9N8MgaVPnWVtdJ3o4mV2aMHvDq7thkQUFt0EuOHJon4rQpJfhjmNHB+ikl0Cd6WhWIErOyQ+f7tw==",
|
||||
"version": "10.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.19.tgz",
|
||||
"integrity": "sha512-46/xThm3zvvc9t9/7M3AaLEqtOpqlYYYcCZbpYVAQHG20+oMZBkae/VMrn4BTi6AJ8cpack0mEXhGiKmDNbLrQ==",
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
@ -105,9 +105,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz",
|
||||
"integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==",
|
||||
"version": "3.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||
"dev": true
|
||||
},
|
||||
"vows": {
|
||||
|
26
package.json
26
package.json
@ -2,26 +2,34 @@
|
||||
"name": "fast-srp-hap",
|
||||
"description": "Secure Remote Password (SRP)",
|
||||
"version": "1.1.0",
|
||||
"main": "dist/index.js",
|
||||
"main": "lib/srp.js",
|
||||
"scripts": {
|
||||
"prepare": "rm -rf dist && tsc",
|
||||
"test": "vows dist/test/test_*.js --spec"
|
||||
"clean": "rm -rf lib",
|
||||
"build": "npm run clean && tsc",
|
||||
"prepublishOnly": "npm run build",
|
||||
"postpublish": "npm run clean",
|
||||
"test": "vows lib/test/test_*.js --spec"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zarmack/fast-srp"
|
||||
"url": "https://github.com/homebridge/fast-srp-hap"
|
||||
},
|
||||
"author": "Zarmack Tanen",
|
||||
"licence": "MIT",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.17.0"
|
||||
},
|
||||
"files": [
|
||||
"jsbn",
|
||||
"lib",
|
||||
"dist/index.*",
|
||||
"dist/lib"
|
||||
"!lib/test",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.12.3",
|
||||
"typescript": "^3.6.4",
|
||||
"@types/node": "^10.17.19",
|
||||
"typescript": "^3.8.3",
|
||||
"vows": "^0.8.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
export * from './lib/srp';
|
||||
|
||||
export {
|
||||
default as params,
|
||||
SrpParams,
|
||||
} from './lib/params';
|
||||
|
||||
export default module.exports;
|
@ -14,7 +14,7 @@
|
||||
// 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.
|
||||
|
||||
import BigInteger = require('../../lib/jsbn');
|
||||
import BigInteger = require('../jsbn/jsbn');
|
||||
|
||||
export function hex(s: string) {
|
||||
return new BigInteger(s.split(/\s|\n/).join(''), 16);
|
||||
@ -27,9 +27,7 @@ export interface SrpParams {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
const params: {
|
||||
[n: string]: SrpParams;
|
||||
} = {
|
||||
export const params = {
|
||||
1024: {
|
||||
N_length_bits: 1024,
|
||||
N: hex(`
|
@ -1,10 +1,11 @@
|
||||
import * as crypto from 'crypto';
|
||||
import * as assert from 'assert';
|
||||
import BigInteger = require('../../lib/jsbn');
|
||||
import crypto from 'crypto';
|
||||
import assert from 'assert';
|
||||
import BigInteger = require('../jsbn/jsbn');
|
||||
import {SrpParams, params as srpParams} from './params';
|
||||
|
||||
import {SrpParams} from './params';
|
||||
export { SrpParams } from './params';
|
||||
|
||||
var zero = new BigInteger(0, 10);
|
||||
const zero = new BigInteger(0, 10);
|
||||
|
||||
function assert_(val: any, msg: string) {
|
||||
if (!val)
|
||||
@ -34,7 +35,7 @@ function padTo(n: Buffer, len: number) {
|
||||
|
||||
function padToN(number: BigInteger, params: SrpParams) {
|
||||
assertIsBigInteger(number);
|
||||
var 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);
|
||||
}
|
||||
|
||||
@ -66,35 +67,68 @@ function getx(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer) {
|
||||
const hashIP = crypto.createHash(params.hash)
|
||||
.update(Buffer.concat([I, Buffer.from(':'), P]))
|
||||
.digest();
|
||||
const hashX = crypto.createHash(params.hash)
|
||||
const hashX: Buffer = crypto.createHash(params.hash)
|
||||
.update(salt)
|
||||
.update(hashIP)
|
||||
.digest();
|
||||
return new BigInteger(hashX);
|
||||
}
|
||||
|
||||
/**
|
||||
* The verifier is calculated as described in Section 3 of [SRP-RFC].
|
||||
* We give the algorithm here for convenience.
|
||||
*
|
||||
* The verifier (v) is computed based on the salt (s), user name (I),
|
||||
* password (P), and group parameters (N, g).
|
||||
*
|
||||
* x = H(s | H(I | ":" | P))
|
||||
* v = g^x % N
|
||||
*
|
||||
* @param {object} params Group parameters, with .N, .g, .hash
|
||||
* @param {Buffer} salt
|
||||
* @param {Buffer} I User identity
|
||||
* @param {Buffer} P User password
|
||||
* @return {Buffer}
|
||||
*/
|
||||
export function computeVerifier(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer) {
|
||||
assertIsBuffer(salt, 'salt (salt)');
|
||||
assertIsBuffer(I, 'identity (I)');
|
||||
assertIsBuffer(P, 'password (P)');
|
||||
var v_num = params.g.modPow(getx(params, salt, I, P), params.N);
|
||||
return v_num.toBuffer(params.N_length_bits / 8);
|
||||
export type GenKeyCallback = (err: Error | null, data: Buffer | null) => void;
|
||||
|
||||
export class SRP {
|
||||
|
||||
public static readonly params = srpParams;
|
||||
|
||||
/**
|
||||
* The verifier is calculated as described in Section 3 of [SRP-RFC].
|
||||
* We give the algorithm here for convenience.
|
||||
*
|
||||
* The verifier (v) is computed based on the salt (s), user name (I),
|
||||
* password (P), and group parameters (N, g).
|
||||
*
|
||||
* x = H(s | H(I | ":" | P))
|
||||
* v = g^x % N
|
||||
*
|
||||
* @param {object} params Group parameters, with .N, .g, .hash
|
||||
* @param {Buffer} salt
|
||||
* @param {Buffer} I User identity
|
||||
* @param {Buffer} P User password
|
||||
* @return {Buffer}
|
||||
*/
|
||||
public static computeVerifier(params: SrpParams, salt: Buffer, I: Buffer, P: Buffer): Buffer {
|
||||
assertIsBuffer(salt, 'salt (salt)');
|
||||
assertIsBuffer(I, 'identity (I)');
|
||||
assertIsBuffer(P, 'password (P)');
|
||||
const v_num = params.g.modPow(getx(params, salt, I, P), params.N);
|
||||
return v_num.toBuffer(params.N_length_bits / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random key.
|
||||
*
|
||||
* @param {number} [bytes=32] Length of key
|
||||
* @param {function} [callback] If not provided a Promise is returned
|
||||
* @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 {
|
||||
// bytes is optional
|
||||
if (typeof bytes !== 'number') {
|
||||
callback = bytes as unknown as GenKeyCallback;
|
||||
bytes = 32;
|
||||
}
|
||||
|
||||
if (!callback) return new Promise((rs, rj) => SRP.genKey(bytes as number, (err, data) => err ? rj(err) : rs(data!)));
|
||||
|
||||
crypto.randomBytes(bytes, (err, buf) => {
|
||||
if (err) return callback!(err, null);
|
||||
return callback!(null, buf);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,32 +147,6 @@ function getk(params: SrpParams) {
|
||||
return new BigInteger(k_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random key.
|
||||
*
|
||||
* @param {number} [bytes=32] Length of key
|
||||
* @param {function} [callback] If not provided a Promise is returned
|
||||
* @return {Promise|void}
|
||||
*/
|
||||
type GenKeyCallback = (err: Error | null, data: Buffer | null) => void;
|
||||
export function genKey(callback: GenKeyCallback): void
|
||||
export function genKey(bytes: number, callback: GenKeyCallback): void
|
||||
export function genKey(bytes?: number): Promise<Buffer>
|
||||
export function genKey(bytes: number | GenKeyCallback = 32, callback?: GenKeyCallback): Promise<Buffer> | void {
|
||||
// bytes is optional
|
||||
if (typeof bytes !== 'number') {
|
||||
callback = bytes as unknown as GenKeyCallback;
|
||||
bytes = 32;
|
||||
}
|
||||
|
||||
if (!callback) return new Promise((rs, rj) => genKey(bytes as number, (err, data) => err ? rj(err) : rs(data!)));
|
||||
|
||||
crypto.randomBytes(bytes, (err, buf) => {
|
||||
if (err) return callback!(err, null);
|
||||
return callback!(null, buf);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The server key exchange message also contains the server's public
|
||||
* value (B). The server calculates this value as B = k*v + g^b % N,
|
||||
@ -147,7 +155,8 @@ export function genKey(bytes: number | GenKeyCallback = 32, callback?: GenKeyCal
|
||||
*
|
||||
* Note: as the tests imply, the entire expression is mod N.
|
||||
*
|
||||
* @param {object} params Group parameters, with .N, .g, .hash
|
||||
* @param {SrpParams} params Group parameters, with .N, .g, .hash
|
||||
* @param {BigInteger} k
|
||||
* @param {BigInteger} v Verifier (stored)
|
||||
* @param {BigInteger} b Server secret exponent
|
||||
* @return {Buffer} B - The server public message
|
||||
@ -168,7 +177,7 @@ function getB(params: SrpParams, k: BigInteger, v: BigInteger, b: BigInteger) {
|
||||
* Note: for this implementation, we take that to mean 256/8 bytes.
|
||||
*
|
||||
* @param {object} params Group parameters, with .N, .g, .hash
|
||||
* @param {BigInteger} a Client secret exponent
|
||||
* @param {BigInteger} a_num Client secret exponent
|
||||
* @return {BigInteger} A - The client public message
|
||||
*/
|
||||
function getA(params: SrpParams, a_num: BigInteger) {
|
||||
@ -231,10 +240,10 @@ function client_getS(params: SrpParams, k_num: BigInteger, x_num: BigInteger, a_
|
||||
* The TLS premastersecret as calculated by the server
|
||||
*
|
||||
* @param {BigInteger} params Group parameters, with .N, .g, .hash
|
||||
* @param {BigInteger} v Verifier (stored on server)
|
||||
* @param {BigInteger} A Ephemeral client public key (read from client)
|
||||
* @param {BigInteger} b Server ephemeral private key (generated for session)
|
||||
* @param {BigInteger} u {@see getu}
|
||||
* @param {BigInteger} v_num Verifier (stored on server)
|
||||
* @param {BigInteger} A_num Ephemeral client public key (read from client)
|
||||
* @param {BigInteger} b_num Server ephemeral private key (generated for session)
|
||||
* @param {BigInteger} u_num {@see getu}
|
||||
* @return {Buffer}
|
||||
*/
|
||||
function server_getS(params: SrpParams, v_num: BigInteger, A_num: BigInteger, b_num: BigInteger, u_num: BigInteger) {
|
||||
@ -255,7 +264,7 @@ function server_getS(params: SrpParams, v_num: BigInteger, A_num: BigInteger, b_
|
||||
* Compute the shared session key K from S
|
||||
*
|
||||
* @param {object} params Group parameters, with .N, .g, .hash
|
||||
* @param {Buffer} S Session key
|
||||
* @param {Buffer} S_buf Session key
|
||||
* @return {Buffer}
|
||||
*/
|
||||
function getK(params: SrpParams, S_buf: Buffer) {
|
||||
@ -273,7 +282,7 @@ function getK(params: SrpParams, S_buf: Buffer) {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param params SRP params
|
||||
* @param u_buf User identity
|
||||
* @param s_buf User salt
|
||||
@ -291,13 +300,13 @@ function getM1(params: SrpParams, u_buf: Buffer, s_buf: Buffer, A_buf: Buffer, B
|
||||
assertIsBuffer(B_buf!, 'server public key (B)');
|
||||
assertIsBuffer(K_buf!, 'session key (K)');
|
||||
|
||||
var hN = crypto.createHash(params.hash).update(params.N.toBuffer(true)).digest();
|
||||
var hG = crypto.createHash(params.hash).update(params.g.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();
|
||||
|
||||
for (var i = 0; i < hN.length; i++)
|
||||
for (let i = 0; i < hN.length; i++)
|
||||
hN[i] ^= hG[i];
|
||||
|
||||
var hU = crypto.createHash(params.hash).update(u_buf).digest();
|
||||
const hU = crypto.createHash(params.hash).update(u_buf).digest();
|
||||
|
||||
return crypto.createHash(params.hash)
|
||||
.update(hN).update(hU).update(s_buf)
|
||||
@ -332,19 +341,19 @@ function equal(buf1: Buffer, buf2: Buffer) {
|
||||
return buf1.toString('hex') === buf2.toString('hex');
|
||||
}
|
||||
|
||||
export class Client {
|
||||
private _params: SrpParams;
|
||||
private _k: BigInteger;
|
||||
private _x: BigInteger;
|
||||
export class SrpClient {
|
||||
private readonly _params: SrpParams;
|
||||
private readonly _k: BigInteger;
|
||||
private readonly _x: BigInteger;
|
||||
/** Client private key */
|
||||
private _a: BigInteger;
|
||||
private readonly _a: BigInteger;
|
||||
/** Client public key */
|
||||
private _A: Buffer;
|
||||
private readonly _A: Buffer;
|
||||
|
||||
/** User identity */
|
||||
private _I?: Buffer;
|
||||
private readonly _I?: Buffer;
|
||||
/** User salt */
|
||||
private _s?: Buffer;
|
||||
private readonly _s?: Buffer;
|
||||
|
||||
/** Session key */
|
||||
private _K?: Buffer;
|
||||
@ -386,7 +395,7 @@ export class Client {
|
||||
|
||||
this._A = getA(params, this._a);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the client's public key (A).
|
||||
*
|
||||
@ -395,7 +404,7 @@ export class Client {
|
||||
computeA() {
|
||||
return this._A;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the server's public key (B).
|
||||
*
|
||||
@ -462,21 +471,21 @@ export type VerifierIdentity = BaseIdentity & {verifier: Buffer};
|
||||
|
||||
export type Identity = PasswordIdentity | VerifierIdentity;
|
||||
|
||||
export class Server {
|
||||
private _params: SrpParams;
|
||||
export class SrpServer {
|
||||
private readonly _params: SrpParams;
|
||||
/** Multiplier parameter (H(N, g)) */
|
||||
private _k: BigInteger;
|
||||
private readonly _k: BigInteger;
|
||||
/** Server private key */
|
||||
private _b: BigInteger;
|
||||
private readonly _b: BigInteger;
|
||||
/** Server public key */
|
||||
private _B: Buffer;
|
||||
private readonly _B: Buffer;
|
||||
/** Verifier */
|
||||
private _v: BigInteger;
|
||||
private readonly _v: BigInteger;
|
||||
|
||||
/** User identity */
|
||||
private _I?: Buffer;
|
||||
private readonly _I?: Buffer;
|
||||
/** User salt */
|
||||
private _s?: Buffer;
|
||||
private readonly _s?: Buffer;
|
||||
|
||||
/** Session key */
|
||||
_K?: Buffer;
|
||||
@ -500,7 +509,7 @@ export class Server {
|
||||
* @param {Buffer} salt_buf User salt (from server)
|
||||
* @param {Buffer} identity_buf Identity/username
|
||||
* @param {Buffer} password_buf Password
|
||||
* @param {Buffer} secret1_buf Client private key {@see genKey}
|
||||
* @param {Buffer} secret2_buf Client private key {@see genKey}
|
||||
*/
|
||||
constructor(params: SrpParams, salt_buf: Buffer, identity_buf: Buffer, password_buf: Buffer, secret2_buf: Buffer)
|
||||
constructor(params: SrpParams, verifier_buf: Buffer, secret2_buf: Buffer)
|
||||
@ -516,7 +525,7 @@ export class Server {
|
||||
assertIsBuffer(secret2_buf!, 'secret2');
|
||||
|
||||
this._b = new BigInteger(secret2_buf!);
|
||||
this._v = new BigInteger(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!));
|
||||
|
||||
this._I = identity_buf;
|
||||
this._s = salt_buf as Buffer;
|
||||
@ -533,6 +542,7 @@ export class Server {
|
||||
const identity = salt_buf as Identity;
|
||||
[secret2_buf, salt_buf, identity_buf, password_buf] = [identity_buf, undefined, undefined, undefined];
|
||||
|
||||
// noinspection SuspiciousTypeOfGuard
|
||||
assert(identity.username instanceof Buffer || typeof identity.username === 'string', 'identity.username (I) must be a string or Buffer');
|
||||
assertIsBuffer(identity.salt, 'identity.salt (s)');
|
||||
assert('password' in identity || 'verifier' in identity, 'identity requires a password or verifier');
|
||||
@ -546,7 +556,7 @@ export class Server {
|
||||
if ('verifier' in identity) {
|
||||
this._v = new BigInteger(identity.verifier);
|
||||
} else {
|
||||
this._v = new BigInteger(computeVerifier(
|
||||
this._v = new BigInteger(SRP.computeVerifier(
|
||||
params, identity.salt, username,
|
||||
typeof identity.password === 'string' ? Buffer.from(identity.password) : identity.password
|
||||
));
|
@ -1,5 +1,4 @@
|
||||
import {hex} from '../lib/params';
|
||||
import BigInteger = require('../../lib/jsbn');
|
||||
import {hex} from '../params';
|
||||
|
||||
// Modulus (N), as specified by the 3072-bit group of RFC 5054
|
||||
export const N = hex(`
|
||||
|
@ -1,10 +1,8 @@
|
||||
// @ts-ignore
|
||||
import * as vows from 'vows';
|
||||
import * as assert from 'assert';
|
||||
import * as srp from '..';
|
||||
import BigInteger = require('../../lib/jsbn');
|
||||
|
||||
delete exports.__esModule;
|
||||
import vows from 'vows';
|
||||
import assert from 'assert';
|
||||
import {SRP, SrpClient, SrpParams, SrpServer} from "../srp";
|
||||
import BigInteger = require('../../jsbn/jsbn');
|
||||
|
||||
interface Input {
|
||||
/** Identity */
|
||||
@ -36,7 +34,7 @@ interface ExpectedOutput {
|
||||
|
||||
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 = {
|
||||
I: Buffer.from(I, 'ascii'),
|
||||
@ -77,14 +75,14 @@ function numequal(a: BigInteger, b: BigInteger, msg?: string) {
|
||||
assert(a.compareTo(b) === 0, msg);
|
||||
}
|
||||
|
||||
function checkVectors(params: srp.SrpParams, inputs: Input, expected: ExpectedOutput, useVerifier = true) {
|
||||
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput, useVerifier = true) {
|
||||
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 srp.Client(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 ?
|
||||
new srp.Server(params, {username: inputs.I, salt: inputs.salt, verifier: expected.v}, inputs.b) :
|
||||
new srp.Server(params, inputs.salt, inputs.I, inputs.P, inputs.b);
|
||||
new SrpServer(params, {username: inputs.I, salt: inputs.salt, verifier: expected.v}, inputs.b) :
|
||||
new SrpServer(params, inputs.salt, inputs.I, inputs.P, inputs.b);
|
||||
|
||||
// @ts-ignore
|
||||
numequal(client._k, new BigInteger(expected.k.toString('hex'), 16), 'k');
|
||||
|
@ -1,10 +1,8 @@
|
||||
// @ts-ignore
|
||||
import * as vows from 'vows';
|
||||
import * as assert from 'assert';
|
||||
import * as srp from '..';
|
||||
import BigInteger = require('../../lib/jsbn');
|
||||
|
||||
delete exports.__esModule;
|
||||
import vows from 'vows';
|
||||
import assert from 'assert';
|
||||
import {SRP, SrpClient, SrpParams, SrpServer} from '../srp';
|
||||
import BigInteger = require('../../jsbn/jsbn');
|
||||
|
||||
/*
|
||||
* Vectors from https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol
|
||||
@ -19,7 +17,7 @@ function hex(s: string) {
|
||||
return Buffer.from(s.split(/\s/).join(''), 'hex');
|
||||
}
|
||||
|
||||
const params = srp.params[2048];
|
||||
const params = SRP.params[2048];
|
||||
|
||||
interface Input {
|
||||
/** Identity */
|
||||
@ -318,12 +316,12 @@ function numequal(a: BigInteger, b: BigInteger, msg?: string) {
|
||||
assert(a.compareTo(b) === 0, msg);
|
||||
}
|
||||
|
||||
function checkVectors(params: srp.SrpParams, inputs: Input, expected: ExpectedOutput) {
|
||||
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput) {
|
||||
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 srp.Client(params, inputs.salt, inputs.I, inputs.P, inputs.a, false);
|
||||
const server = new srp.Server(params, expected.v, inputs.b);
|
||||
const client = new SrpClient(params, inputs.salt, inputs.I, inputs.P, inputs.a, false);
|
||||
const server = new SrpServer(params, expected.v, inputs.b);
|
||||
|
||||
// @ts-ignore
|
||||
numequal(client._k, new BigInteger(expected.k.toString('hex'), 16), 'k');
|
||||
|
@ -1,12 +1,10 @@
|
||||
// @ts-ignore
|
||||
import * as vows from 'vows';
|
||||
import * as assert from 'assert';
|
||||
import * as srp from '..';
|
||||
import BigInteger = require('../../lib/jsbn');
|
||||
import vows from 'vows';
|
||||
import assert from 'assert';
|
||||
import {SRP, SrpClient, SrpServer} from '../srp';
|
||||
import BigInteger = require('../../jsbn/jsbn');
|
||||
|
||||
delete exports.__esModule;
|
||||
|
||||
const params = srp.params[1024];
|
||||
const params = SRP.params[1024];
|
||||
|
||||
/*
|
||||
* http://tools.ietf.org/html/rfc5054#appendix-B
|
||||
@ -60,11 +58,11 @@ function asHex(num: number | BigInteger) {
|
||||
vows.describe('RFC 5054').addBatch({
|
||||
'Test vectors': {
|
||||
topic() {
|
||||
return srp.computeVerifier(params, s, I, P);
|
||||
return SRP.computeVerifier(params, s, I, P);
|
||||
},
|
||||
|
||||
'x'() {
|
||||
const client = new srp.Client(params, s, I, P, a, false);
|
||||
const client = new SrpClient(params, s, I, P, a, false);
|
||||
// @ts-ignore
|
||||
assert.equal(asHex(client._x), x_expected);
|
||||
},
|
||||
@ -74,37 +72,37 @@ vows.describe('RFC 5054').addBatch({
|
||||
},
|
||||
|
||||
'k'() {
|
||||
const client = new srp.Client(params, s, I, P, a, false);
|
||||
const client = new SrpClient(params, s, I, P, a, false);
|
||||
// @ts-ignore
|
||||
assert.equal(asHex(client._k), k_expected);
|
||||
},
|
||||
|
||||
'A'() {
|
||||
const client = new srp.Client(params, s, I, P, a, false);
|
||||
const client = new SrpClient(params, s, I, P, a, false);
|
||||
assert.equal(client.computeA().toString('hex'), A_expected);
|
||||
},
|
||||
|
||||
'B'(v: Buffer) {
|
||||
const server = new srp.Server(params, v, b);
|
||||
const server = new SrpServer(params, v, b);
|
||||
assert.equal(server.computeB().toString('hex'), B_expected);
|
||||
},
|
||||
|
||||
'u'() {
|
||||
const client = new srp.Client(params, s, I, P, a, false);
|
||||
const client = new SrpClient(params, s, I, P, a, false);
|
||||
client.setB(Buffer.from(B_expected, 'hex'));
|
||||
// @ts-ignore
|
||||
assert.equal(asHex(client._u), u_expected);
|
||||
},
|
||||
|
||||
'S client'() {
|
||||
const client = new srp.Client(params, s, I, P, a, false);
|
||||
const client = new SrpClient(params, s, I, P, a, false);
|
||||
client.setB(Buffer.from(B_expected, 'hex'));
|
||||
// @ts-ignore
|
||||
assert.equal(client._S.toString('hex'), S_expected);
|
||||
},
|
||||
|
||||
'S server'(v: Buffer) {
|
||||
const server = new srp.Server(params, v, b);
|
||||
const server = new SrpServer(params, v, b);
|
||||
server.setA(Buffer.from(A_expected, 'hex'));
|
||||
// @ts-ignore
|
||||
assert.equal(server._S.toString('hex'), S_expected);
|
||||
|
@ -1,11 +1,9 @@
|
||||
// @ts-ignore
|
||||
import * as vows from 'vows';
|
||||
import * as assert from 'assert';
|
||||
import * as srp from '..';
|
||||
import vows from 'vows';
|
||||
import assert from 'assert';
|
||||
import {SRP, SrpClient, SrpServer} from '../srp';
|
||||
|
||||
delete exports.__esModule;
|
||||
|
||||
const params = srp.params[4096];
|
||||
const params = SRP.params[4096];
|
||||
|
||||
const salt = Buffer.from('salty');
|
||||
const identity = Buffer.from('alice');
|
||||
@ -13,7 +11,7 @@ const password = Buffer.from('password123');
|
||||
|
||||
assert(params, 'missing parameters');
|
||||
|
||||
let client: srp.Client, server: srp.Server;
|
||||
let client: SrpClient, server: SrpServer;
|
||||
let a: Buffer, A: Buffer;
|
||||
let b: Buffer, B: Buffer;
|
||||
let verifier: Buffer;
|
||||
@ -21,25 +19,25 @@ let verifier: Buffer;
|
||||
|
||||
vows.describe('srp.js').addBatch({
|
||||
'create Verifier'() {
|
||||
verifier = srp.computeVerifier(params, salt, identity, password);
|
||||
verifier = SRP.computeVerifier(params, salt, identity, password);
|
||||
assert.equal(verifier.toString('hex'), 'f0e47f50f5dead8db8d93a279e3b62d6ff50854b31fbd3474a886bef916261717e84dd4fb8b4d27feaa5146db7b1cbbc274fdf96a132b5029c2cd72527427a9b9809d5a4d018252928b4fc343bc17ce63c1859d5806f5466014fc361002d8890aeb4d6316ff37331fc2761be0144c91cdd8e00ed0138c0ce51534d1b9a9ba629d7be34d2742dd4097daabc9ecb7aaad89e53c342b038f1d2adae1f2410b7884a3e9a124c357e421bccd4524467e1922660e0a4460c5f7c38c0877b65f6e32f28296282a93fc11bbabb7bb69bf1b3f9391991d8a86dd05e15000b7e38ba38a536bb0bf59c808ec25e791b8944719488b8087df8bfd7ff20822997a53f6c86f3d45d004476d6303301376bb25a9f94b552cce5ed40de5dd7da8027d754fa5f66738c7e3fc4ef3e20d625df62cbe6e7adfc21e47880d8a6ada37e60370fd4d8fc82672a90c29f2e72f35652649d68348de6f36d0e435c8bd42dd00155d35d501becc0661b43e04cdb2da84ce92b8bf49935d73d75efcbd1176d7bbccc3cc4d4b5fefcc02d478614ee1681d2ff3c711a61a7686eb852ae06fb8227be21fb8802719b1271ba1c02b13bbf0a2c2e459d9bedcc8d1269f6a785cb4563aa791b38fb038269f63f58f47e9051499549789269cc7b8ec7026fc34ba73289c4af829d5a532e723967ce9b6c023ef0fd0cfe37f51f10f19463b6534159a09ddd2f51f3b30033');
|
||||
},
|
||||
|
||||
'create a and b': {
|
||||
topic(this: any) {(async () => {
|
||||
a = await srp.genKey(64);
|
||||
b = await srp.genKey(32);
|
||||
a = await SRP.genKey(64);
|
||||
b = await SRP.genKey(32);
|
||||
this.callback();
|
||||
})()},
|
||||
|
||||
'use a and b'() {
|
||||
client = new srp.Client(params, salt, identity, password, a, false);
|
||||
client = new SrpClient(params, salt, identity, password, a, false);
|
||||
|
||||
// client produces A
|
||||
A = client.computeA();
|
||||
|
||||
// create server
|
||||
server = new srp.Server(params, verifier, b);
|
||||
server = new SrpServer(params, verifier, b);
|
||||
|
||||
// server produces B
|
||||
B = server.computeB();
|
||||
@ -70,8 +68,8 @@ vows.describe('srp.js').addBatch({
|
||||
},
|
||||
|
||||
'server rejects wrong M1'() {
|
||||
const bad_client = new srp.Client(params, salt, identity, Buffer.from('bad'), a, false);
|
||||
const server2 = new srp.Server(params, verifier, b);
|
||||
const bad_client = new SrpClient(params, salt, identity, Buffer.from('bad'), a, false);
|
||||
const server2 = new SrpServer(params, verifier, b);
|
||||
bad_client.setB(server2.computeB());
|
||||
assert.throws(() => server.checkM1(bad_client.computeM1()), /client did not use the same password/);
|
||||
},
|
||||
@ -81,7 +79,7 @@ vows.describe('srp.js').addBatch({
|
||||
// reject 2*N too, but our Buffer-length checks reject it before the
|
||||
// number itself is examined.
|
||||
|
||||
var server2 = new srp.Server(params, verifier, b);
|
||||
var server2 = new SrpServer(params, verifier, b);
|
||||
var Azero = Buffer.alloc(params.N_length_bits / 8);
|
||||
Azero.fill(0);
|
||||
//! var AN = params.N.toBuffer();
|
||||
@ -95,7 +93,7 @@ vows.describe('srp.js').addBatch({
|
||||
|
||||
'client rejects bad B'() {
|
||||
// server's "B" must be 1..N-1 . Reject 0 and N and N+1
|
||||
var client2 = new srp.Client(params, salt, identity, password, a, false);
|
||||
var client2 = new SrpClient(params, salt, identity, password, a, false);
|
||||
var Bzero = Buffer.alloc(params.N_length_bits / 8);
|
||||
Bzero.fill(0, 0, params.N_length_bits / 8);
|
||||
//! var BN = params.N.toBuffer();
|
||||
@ -108,13 +106,13 @@ vows.describe('srp.js').addBatch({
|
||||
},
|
||||
|
||||
'client rejects bad M2'() {
|
||||
client = new srp.Client(params, salt, identity, password, a, false);
|
||||
client = new SrpClient(params, salt, identity, password, a, false);
|
||||
|
||||
// client produces A
|
||||
A = client.computeA();
|
||||
|
||||
// create server
|
||||
server = new srp.Server(params, verifier, b);
|
||||
server = new SrpServer(params, verifier, b);
|
||||
|
||||
// server produces B
|
||||
B = server.computeB();
|
||||
|
@ -1,12 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "ES2018",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es2015",
|
||||
"es2016",
|
||||
"es2017",
|
||||
"es2018"
|
||||
],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
"strict": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user