forked from zarmack/fast-srp
-
Notifications
You must be signed in to change notification settings - Fork 4
/
test_hap_vectors.ts
124 lines (108 loc) · 4.25 KB
/
test_hap_vectors.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* eslint-disable @typescript-eslint/ban-ts-ignore */
// @ts-ignore
import vows from "vows";
import assert from "assert";
import { SRP, SrpClient, SrpParams, SrpServer } from "../srp";
import BigInteger = require("../../jsbn/jsbn");
interface Input {
/** Identity */
I: Buffer;
/** Password */
P: Buffer;
/** Salt */
salt: Buffer;
/** Client private key */
a: Buffer;
/** Server private key */
b: Buffer;
}
interface ExpectedOutput {
k: Buffer;
x: Buffer;
/** Verifier */
v: Buffer;
/** Server public key */
B: Buffer;
/** Client public key */
A: Buffer;
u: Buffer;
S: Buffer;
K: Buffer;
M1: Buffer;
}
// 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 inputs: Input = {
I: Buffer.from(I, "ascii"),
P: Buffer.from(p, "ascii"),
salt: s.toBuffer(true),
// a and b are usually random. For testing, we force them to specific values.
a: a.toBuffer(true),
b: b.toBuffer(true),
};
const expected: ExpectedOutput = {
// 'k' encodes the group (N and g), used in SRP-6a
k: Buffer.from("a9c2e2559bf0ebb53f0cbbf62282906bede7f2182f00678211fbd5bde5b285033a4993503b87397f9be5ec02080fedbc0835587ad039060879b8621e8c3659e0", "hex"),
// 'x' is derived from the salt and password
x: Buffer.from("b149ecb0946b0b206d77e73d95deb7c41bd12e86a5e2eea3893d5416591a002ff94bfea384dc0e1c550f7ed4d5a9d2ad1f1526f01c56b5c10577730cc4a4d709", "hex"),
// 'v' is the SRP verifier
v: v.toBuffer(true),
// 'B' is the server's public message
B: B.toBuffer(true),
// 'A' is the client's public message
A: A.toBuffer(true),
// 'u' combines the two public messages
u: u.toBuffer(true),
// 'S' is the shared secret
S: S.toBuffer(true),
// 'K' is the shared derived key
K: K.toBuffer(true),
// 'M1' is the client's proof that it knows the shared key
M1: Buffer.from("5f7c14ab57ed0e94fd1d78c6b4dd09ed7e340b7e05d419a9fd760f6b35e523d1310777a1ae1d2826f596f3a85116cc457c7c964d4f44ded5559da818c88b617f", "hex"),
};
function hexequal(a: Buffer, b: Buffer, msg?: string): void {
assert.strictEqual(a.length, b.length, msg);
assert.strictEqual(a.toString("hex"), b.toString("hex"), msg);
}
function numequal(a: BigInteger, b: BigInteger, msg?: string): void {
assert(a.compareTo(b) === 0, msg);
}
function checkVectors(params: SrpParams, inputs: Input, expected: ExpectedOutput, useVerifier = true): void {
hexequal(inputs.I, Buffer.from("616c696365", "hex"), "I");
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 server = useVerifier ?
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");
// @ts-ignore
numequal(client._x, new BigInteger(expected.x.toString("hex"), 16), "x");
hexequal(client.computeA(), expected.A);
hexequal(server.computeB(), expected.B);
assert.throws(() => client.computeM1(), /incomplete protocol/);
assert.throws(() => client.computeK(), /incomplete protocol/);
assert.throws(() => server.checkM1(expected.M1), /incomplete protocol/);
assert.throws(() => server.computeK(), /incomplete protocol/);
assert.throws(() => server.computeM2(), /incomplete protocol/);
client.setB(expected.B);
// @ts-ignore
numequal(client._u, new BigInteger(expected.u.toString("hex"), 16));
// @ts-ignore
hexequal(client._S, expected.S);
hexequal(client.computeM1(), expected.M1);
hexequal(client.computeK(), expected.K);
server.setA(expected.A);
// @ts-ignore
numequal(server._u, new BigInteger(expected.u.toString("hex"), 16));
// @ts-ignore
hexequal(server._S, expected.S);
assert.throws(() => server.checkM1(Buffer.from("notM1")), /client did not use the same password/);
server.checkM1(expected.M1); // happy, not throwy
hexequal(server.computeK(), expected.K);
}
vows.describe("HomeKit vectors").addBatch({
"with verifier": () => checkVectors(params, inputs, expected),
"with password": () => checkVectors(params, inputs, expected, false),
}).export(module);