node-firebird 2.0.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node.js.yml +20 -0
- package/BIGINT_MIGRATION.md +374 -0
- package/CI_DEBUGGING_GUIDE.md +148 -0
- package/FIREBIRD_LOG_FEATURE.md +145 -0
- package/MINIMAL_CHANGES_SUMMARY.md +136 -0
- package/PR_SUMMARY.md +88 -131
- package/README.md +142 -22
- package/ROADMAP.md +223 -0
- package/SRP_PROTOCOL.md +482 -0
- package/lib/ieee754-decimal.js +500 -0
- package/lib/index.d.ts +10 -6
- package/lib/srp.js +65 -50
- package/lib/wire/connection.js +257 -56
- package/lib/wire/const.js +29 -0
- package/lib/wire/database.js +78 -9
- package/lib/wire/eventConnection.js +6 -3
- package/lib/wire/fbEventManager.js +234 -41
- package/lib/wire/serialize.js +39 -0
- package/lib/wire/service.js +102 -94
- package/lib/wire/statement.js +4 -4
- package/lib/wire/transaction.js +27 -9
- package/lib/wire/xsqlvar.js +176 -0
- package/package.json +5 -5
- package/vitest.config.js +12 -1
- package/Roadmap.md +0 -80
package/lib/srp.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
var
|
|
2
|
-
crypto = require('crypto');
|
|
1
|
+
var crypto = require('crypto');
|
|
3
2
|
|
|
4
3
|
const SRP_KEY_SIZE = 128,
|
|
5
4
|
SRP_KEY_MAX = BigInt('340282366920938463463374607431768211456'), // 1 << SRP_KEY_SIZE
|
|
6
5
|
SRP_SALT_SIZE = 32;
|
|
7
6
|
|
|
8
7
|
const DEBUG = false;
|
|
9
|
-
const DEBUG_PRIVATE_KEY = BigInt('
|
|
8
|
+
const DEBUG_PRIVATE_KEY = BigInt('0x84316857F47914F838918D5C12CE3A3E7A9B2D7C9486346809E9EEFCE8DE7CD4259D8BE4FD0BCC2D259553769E078FA61EE2977025E4DA42F7FD97914D8A33723DFAFBC00770B7DA0C2E3778A05790F0C0F33C32A19ED88A12928567749021B3FD45DCD1CE259C45325067E3DDC972F87867349BA82C303CCCAA9B207218007B');
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Prime values.
|
|
13
12
|
*
|
|
14
|
-
* @type {{g:
|
|
13
|
+
* @type {{g: BigInt, k: BigInt, N: BigInt}}
|
|
15
14
|
*/
|
|
16
15
|
const PRIME = {
|
|
17
|
-
N: BigInt('
|
|
16
|
+
N: BigInt('0xE67D2E994B2F900C3F41F08F5BB2627ED0D49EE1FE767A52EFCD565CD6E768812C3E1E9CE8F0A8BEA6CB13CD29DDEBF7A96D4A93B55D488DF099A15C89DCB0640738EB2CBDD9A8F7BAB561AB1B0DC1C6CDABF303264A08D1BCA932D1F1EE428B619D970F342ABA9A65793B8B2F041AE5364350C16F735F56ECBCA87BD57B29E7'),
|
|
18
17
|
g: BigInt(2),
|
|
19
18
|
k: BigInt('1277432915985975349439481660349303019122249719989')
|
|
20
19
|
};
|
|
@@ -22,11 +21,11 @@ const PRIME = {
|
|
|
22
21
|
/**
|
|
23
22
|
* Generate a client key pair.
|
|
24
23
|
*
|
|
25
|
-
* @param a
|
|
26
|
-
* @returns {{private:
|
|
24
|
+
* @param a BigInt Client private key.
|
|
25
|
+
* @returns {{private: BigInt, public: BigInt}}
|
|
27
26
|
*/
|
|
28
27
|
exports.clientSeed = function(a = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
|
|
29
|
-
var A = PRIME.g
|
|
28
|
+
var A = modPow(PRIME.g, a, PRIME.N);
|
|
30
29
|
|
|
31
30
|
dump('a', a);
|
|
32
31
|
dump('A', A);
|
|
@@ -42,15 +41,15 @@ exports.clientSeed = function(a = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
|
|
|
42
41
|
*
|
|
43
42
|
* @param user string Connection username.
|
|
44
43
|
* @param password string Connection password.
|
|
45
|
-
* @param salt
|
|
46
|
-
* @param b
|
|
47
|
-
* @returns {{private:
|
|
44
|
+
* @param salt BigInt Connection salt.
|
|
45
|
+
* @param b BigInt Server private key.
|
|
46
|
+
* @returns {{private: BigInt, public: BigInt}}
|
|
48
47
|
*/
|
|
49
48
|
exports.serverSeed = function(user, password, salt, b = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
|
|
50
49
|
var v = getVerifier(user, password, salt);
|
|
51
|
-
var gb = PRIME.g
|
|
52
|
-
var kv = PRIME.k
|
|
53
|
-
var B = kv
|
|
50
|
+
var gb = modPow(PRIME.g, b, PRIME.N);
|
|
51
|
+
var kv = (PRIME.k * v) % PRIME.N;
|
|
52
|
+
var B = (kv + gb) % PRIME.N;
|
|
54
53
|
|
|
55
54
|
dump('v', v);
|
|
56
55
|
dump('b', b);
|
|
@@ -69,24 +68,24 @@ exports.serverSeed = function(user, password, salt, b = toBigInt(crypto.randomBy
|
|
|
69
68
|
*
|
|
70
69
|
* @param user string Connection username.
|
|
71
70
|
* @param password string Connection password.
|
|
72
|
-
* @param salt
|
|
73
|
-
* @param A
|
|
74
|
-
* @param B
|
|
75
|
-
* @param b
|
|
76
|
-
* @returns {
|
|
71
|
+
* @param salt BigInt Connection salt.
|
|
72
|
+
* @param A BigInt Client public key.
|
|
73
|
+
* @param B BigInt Server public key.
|
|
74
|
+
* @param b BigInt Server private key.
|
|
75
|
+
* @returns {BigInt}
|
|
77
76
|
*/
|
|
78
77
|
exports.serverSession = function(user, password, salt, A, B, b) {
|
|
79
78
|
var u = getScramble(A, B);
|
|
80
79
|
var v = getVerifier(user, password, salt);
|
|
81
|
-
var vu =
|
|
82
|
-
var Avu = A
|
|
83
|
-
var sessionSecret =
|
|
80
|
+
var vu = modPow(v, u, PRIME.N);
|
|
81
|
+
var Avu = (A * vu) % PRIME.N;
|
|
82
|
+
var sessionSecret = modPow(Avu, b, PRIME.N);
|
|
84
83
|
var K = getHash('sha1', toBuffer(sessionSecret));
|
|
85
84
|
|
|
86
85
|
dump('server sessionSecret', sessionSecret);
|
|
87
86
|
dump('server K', K);
|
|
88
87
|
|
|
89
|
-
return BigInt(K
|
|
88
|
+
return BigInt('0x' + K);
|
|
90
89
|
};
|
|
91
90
|
|
|
92
91
|
/**
|
|
@@ -102,7 +101,7 @@ exports.clientProof = function(user, password, salt, A, B, a, hashAlgo) {
|
|
|
102
101
|
dump('n1', n1);
|
|
103
102
|
dump('n2', n2);
|
|
104
103
|
|
|
105
|
-
n1 =
|
|
104
|
+
n1 = modPow(n1, n2, PRIME.N);
|
|
106
105
|
n2 = toBigInt(getHash('sha1', user));
|
|
107
106
|
var M = toBigInt(getHash(hashAlgo, toBuffer(n1), toBuffer(n2), salt, toBuffer(A), toBuffer(B), toBuffer(K)));
|
|
108
107
|
|
|
@@ -147,12 +146,12 @@ function pad(n) {
|
|
|
147
146
|
/**
|
|
148
147
|
* Scramble keys.
|
|
149
148
|
*
|
|
150
|
-
* @param A
|
|
151
|
-
* @param B
|
|
152
|
-
* @returns {
|
|
149
|
+
* @param A BigInt Client public key.
|
|
150
|
+
* @param B BigInt Server public key.
|
|
151
|
+
* @returns {BigInt}
|
|
153
152
|
*/
|
|
154
153
|
function getScramble(A, B) {
|
|
155
|
-
return BigInt(getHash('sha1', pad(A), pad(B))
|
|
154
|
+
return BigInt('0x' + getHash('sha1', pad(A), pad(B)));
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
/**
|
|
@@ -165,28 +164,28 @@ function getScramble(A, B) {
|
|
|
165
164
|
*
|
|
166
165
|
* @param user string Connection username.
|
|
167
166
|
* @param password string Connection password.
|
|
168
|
-
* @param salt
|
|
169
|
-
* @param A
|
|
170
|
-
* @param B
|
|
171
|
-
* @param a
|
|
167
|
+
* @param salt BigInt Connection salt.
|
|
168
|
+
* @param A BigInt Client public key.
|
|
169
|
+
* @param B BigInt Server public key.
|
|
170
|
+
* @param a BigInt Client private key.
|
|
172
171
|
*/
|
|
173
172
|
function clientSession(user, password, salt, A, B, a) {
|
|
174
173
|
var u = getScramble(A, B);
|
|
175
174
|
var x = getUserHash(user, salt, password);
|
|
176
|
-
var gx = PRIME.g
|
|
177
|
-
var kgx = PRIME.k
|
|
178
|
-
var diff = B
|
|
175
|
+
var gx = modPow(PRIME.g, x, PRIME.N);
|
|
176
|
+
var kgx = (PRIME.k * gx) % PRIME.N;
|
|
177
|
+
var diff = (B - kgx) % PRIME.N;
|
|
179
178
|
|
|
180
|
-
if (diff
|
|
181
|
-
diff = diff
|
|
179
|
+
if (diff < 0n) {
|
|
180
|
+
diff = diff + PRIME.N;
|
|
182
181
|
}
|
|
183
182
|
|
|
184
183
|
// Note: While the SRP specification says exponents should not be reduced mod N,
|
|
185
184
|
// the Firebird engine implementation does reduce these exponents mod N.
|
|
186
185
|
// We must match the server's behavior for authentication to succeed.
|
|
187
|
-
var ux = u
|
|
188
|
-
var aux = a
|
|
189
|
-
var sessionSecret =
|
|
186
|
+
var ux = (u * x) % PRIME.N;
|
|
187
|
+
var aux = (a + ux) % PRIME.N;
|
|
188
|
+
var sessionSecret = modPow(diff, aux, PRIME.N);
|
|
190
189
|
var K = toBigInt(getHash('sha1', toBuffer(sessionSecret)));
|
|
191
190
|
|
|
192
191
|
dump('B', B);
|
|
@@ -207,9 +206,9 @@ function clientSession(user, password, salt, A, B, a) {
|
|
|
207
206
|
* Compute user hash.
|
|
208
207
|
*
|
|
209
208
|
* @param user string Connection username.
|
|
210
|
-
* @param salt
|
|
209
|
+
* @param salt BigInt Connection salt.
|
|
211
210
|
* @param password string Connection password.
|
|
212
|
-
* @returns {
|
|
211
|
+
* @returns {BigInt}
|
|
213
212
|
*/
|
|
214
213
|
function getUserHash(user, salt, password) {
|
|
215
214
|
var hash1 = getHash('sha1', user.toUpperCase(), ':', password);
|
|
@@ -223,11 +222,11 @@ function getUserHash(user, salt, password) {
|
|
|
223
222
|
*
|
|
224
223
|
* @param user string Connection username.
|
|
225
224
|
* @param password string Connection password.
|
|
226
|
-
* @param salt
|
|
227
|
-
* @returns {
|
|
225
|
+
* @param salt BigInt Connection salt.
|
|
226
|
+
* @returns {BigInt}
|
|
228
227
|
*/
|
|
229
228
|
function getVerifier(user, password, salt) {
|
|
230
|
-
return PRIME.g
|
|
229
|
+
return modPow(PRIME.g, getUserHash(user, salt, password), PRIME.N);
|
|
231
230
|
}
|
|
232
231
|
|
|
233
232
|
/**
|
|
@@ -254,17 +253,17 @@ function getHash(algo, ...data) {
|
|
|
254
253
|
* @returns {*}
|
|
255
254
|
*/
|
|
256
255
|
function toBuffer(bigInt) {
|
|
257
|
-
return Buffer.from(
|
|
256
|
+
return Buffer.from(typeof bigInt === 'bigint' ? hexPad(bigInt.toString(16)) : bigInt, 'hex');
|
|
258
257
|
}
|
|
259
258
|
|
|
260
259
|
/**
|
|
261
260
|
* Convert hex buffer or string to BigInt.
|
|
262
261
|
*
|
|
263
262
|
* @param hex
|
|
264
|
-
* @returns {
|
|
263
|
+
* @returns {BigInt}
|
|
265
264
|
*/
|
|
266
265
|
function toBigInt(hex) {
|
|
267
|
-
return BigInt(Buffer.isBuffer(hex) ? hex.toString('hex') : hex
|
|
266
|
+
return BigInt('0x' + (Buffer.isBuffer(hex) ? hex.toString('hex') : hex));
|
|
268
267
|
}
|
|
269
268
|
|
|
270
269
|
/**
|
|
@@ -275,10 +274,26 @@ function toBigInt(hex) {
|
|
|
275
274
|
*/
|
|
276
275
|
function dump(key, value) {
|
|
277
276
|
if (DEBUG) {
|
|
278
|
-
if (
|
|
277
|
+
if (typeof value === 'bigint') {
|
|
279
278
|
value = value.toString(16);
|
|
280
279
|
}
|
|
281
280
|
|
|
282
281
|
console.log(key + '=' + value);
|
|
283
282
|
}
|
|
284
|
-
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Calculates (base ^ exp) % mod using native BigInt.
|
|
287
|
+
*/
|
|
288
|
+
function modPow(base, exp, mod) {
|
|
289
|
+
let result = 1n;
|
|
290
|
+
base = base % mod;
|
|
291
|
+
while (exp > 0n) {
|
|
292
|
+
if (exp & 1n) {
|
|
293
|
+
result = (result * base) % mod;
|
|
294
|
+
}
|
|
295
|
+
base = (base * base) % mod;
|
|
296
|
+
exp >>= 1n;
|
|
297
|
+
}
|
|
298
|
+
return result;
|
|
299
|
+
}
|