@gqb333/based 2.7.79 → 2.7.80
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/lib/Utils/crypto.js +198 -81
- package/package.json +1 -1
package/lib/Utils/crypto.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
|
|
2
3
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
4
|
if (k2 === undefined) k2 = k;
|
|
4
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
6
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
8
|
}
|
|
8
9
|
Object.defineProperty(o, k2, desc);
|
|
9
10
|
}) : (function(o, m, k, k2) {
|
|
@@ -32,162 +33,278 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
33
|
return result;
|
|
33
34
|
};
|
|
34
35
|
})();
|
|
36
|
+
|
|
35
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
38
|
exports.signedKeyPair = exports.Curve = exports.generateSignalPubKey = void 0;
|
|
37
|
-
exports.aesEncryptGCM
|
|
38
|
-
exports.aesDecryptGCM
|
|
39
|
-
exports.aesEncryptCTR
|
|
40
|
-
exports.aesDecryptCTR
|
|
41
|
-
exports.aesDecrypt
|
|
39
|
+
exports.aesEncryptGCM = aesEncryptGCM;
|
|
40
|
+
exports.aesDecryptGCM = aesDecryptGCM;
|
|
41
|
+
exports.aesEncryptCTR = aesEncryptCTR;
|
|
42
|
+
exports.aesDecryptCTR = aesDecryptCTR;
|
|
43
|
+
exports.aesDecrypt = aesDecrypt;
|
|
42
44
|
exports.aesDecryptWithIV = aesDecryptWithIV;
|
|
43
|
-
exports.aesEncrypt
|
|
44
|
-
exports.aesEncrypWithIV
|
|
45
|
-
exports.hmacSign
|
|
46
|
-
exports.sha256
|
|
47
|
-
exports.
|
|
48
|
-
exports.
|
|
45
|
+
exports.aesEncrypt = aesEncrypt;
|
|
46
|
+
exports.aesEncrypWithIV = aesEncrypWithIV;
|
|
47
|
+
exports.hmacSign = hmacSign;
|
|
48
|
+
exports.sha256 = sha256;
|
|
49
|
+
exports.sha512 = sha512;
|
|
50
|
+
exports.md5 = md5;
|
|
51
|
+
exports.hkdf = hkdf;
|
|
49
52
|
exports.derivePairingCodeKey = derivePairingCodeKey;
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
exports.randomBytes = safeRandomBytes;
|
|
54
|
+
exports.timingSafeEqual = timingSafeEqual;
|
|
55
|
+
|
|
56
|
+
const crypto_1 = require("crypto");
|
|
57
|
+
const libsignal = __importStar(require("libsignal"));
|
|
52
58
|
const Defaults_1 = require("../Defaults");
|
|
53
|
-
|
|
59
|
+
|
|
60
|
+
// ─── Costanti ────────────────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
const GCM_TAG_LENGTH = 16; // 128 bit
|
|
63
|
+
const IV_LENGTH = 16; // 128 bit
|
|
64
|
+
const AES_KEY_LENGTH = 32; // 256 bit
|
|
65
|
+
const PBKDF2_ITER = 2 << 16; // 131.072 iterazioni
|
|
66
|
+
|
|
54
67
|
const { subtle } = globalThis.crypto;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
|
|
69
|
+
// ─── Helpers interni ─────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/** Genera bytes casuali sicuri */
|
|
72
|
+
function safeRandomBytes(size) {
|
|
73
|
+
if (!Number.isInteger(size) || size <= 0) throw new TypeError(`randomBytes: size non valida (${size})`);
|
|
74
|
+
return (0, crypto_1.randomBytes)(size);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Confronto a tempo costante per prevenire timing attacks */
|
|
78
|
+
function timingSafeEqual(a, b) {
|
|
79
|
+
if (!Buffer.isBuffer(a)) a = Buffer.from(a);
|
|
80
|
+
if (!Buffer.isBuffer(b)) b = Buffer.from(b);
|
|
81
|
+
if (a.length !== b.length) return false;
|
|
82
|
+
return (0, crypto_1.timingSafeEqual)(a, b);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Valida che una chiave AES sia della lunghezza corretta */
|
|
86
|
+
function validateAESKey(key) {
|
|
87
|
+
if (!key || key.length !== AES_KEY_LENGTH) {
|
|
88
|
+
throw new RangeError(`Chiave AES non valida: attesi ${AES_KEY_LENGTH} byte, ricevuti ${key?.length ?? 0}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Valida che un IV sia della lunghezza corretta */
|
|
93
|
+
function validateIV(iv, expected = IV_LENGTH) {
|
|
94
|
+
if (!iv || iv.length !== expected) {
|
|
95
|
+
throw new RangeError(`IV non valido: attesi ${expected} byte, ricevuti ${iv?.length ?? 0}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── Signal / Curve ──────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Aggiunge il byte di versione alla chiave pubblica Signal se mancante
|
|
103
|
+
*/
|
|
104
|
+
const generateSignalPubKey = (pubKey) => (
|
|
105
|
+
pubKey.length === 33
|
|
106
|
+
? pubKey
|
|
107
|
+
: Buffer.concat([Defaults_1.KEY_BUNDLE_TYPE, pubKey])
|
|
108
|
+
);
|
|
59
109
|
exports.generateSignalPubKey = generateSignalPubKey;
|
|
110
|
+
|
|
60
111
|
exports.Curve = {
|
|
61
112
|
generateKeyPair: () => {
|
|
62
113
|
const { pubKey, privKey } = libsignal.curve.generateKeyPair();
|
|
63
114
|
return {
|
|
64
115
|
private: Buffer.from(privKey),
|
|
65
|
-
//
|
|
66
|
-
public: Buffer.from(pubKey.slice(1))
|
|
116
|
+
public: Buffer.from(pubKey.slice(1)) // rimuove byte versione
|
|
67
117
|
};
|
|
68
118
|
},
|
|
119
|
+
|
|
69
120
|
sharedKey: (privateKey, publicKey) => {
|
|
70
|
-
const shared = libsignal.curve.calculateAgreement(
|
|
121
|
+
const shared = libsignal.curve.calculateAgreement(
|
|
122
|
+
generateSignalPubKey(publicKey),
|
|
123
|
+
privateKey
|
|
124
|
+
);
|
|
71
125
|
return Buffer.from(shared);
|
|
72
126
|
},
|
|
73
|
-
|
|
127
|
+
|
|
128
|
+
sign: (privateKey, buf) => (
|
|
129
|
+
libsignal.curve.calculateSignature(privateKey, buf)
|
|
130
|
+
),
|
|
131
|
+
|
|
74
132
|
verify: (pubKey, message, signature) => {
|
|
75
133
|
try {
|
|
76
|
-
libsignal.curve.verifySignature(
|
|
134
|
+
libsignal.curve.verifySignature(generateSignalPubKey(pubKey), message, signature);
|
|
77
135
|
return true;
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
136
|
+
} catch {
|
|
80
137
|
return false;
|
|
81
138
|
}
|
|
82
139
|
}
|
|
83
140
|
};
|
|
141
|
+
|
|
84
142
|
const signedKeyPair = (identityKeyPair, keyId) => {
|
|
85
|
-
const preKey
|
|
86
|
-
const pubKey
|
|
143
|
+
const preKey = exports.Curve.generateKeyPair();
|
|
144
|
+
const pubKey = generateSignalPubKey(preKey.public);
|
|
87
145
|
const signature = exports.Curve.sign(identityKeyPair.private, pubKey);
|
|
88
146
|
return { keyPair: preKey, signature, keyId };
|
|
89
147
|
};
|
|
90
148
|
exports.signedKeyPair = signedKeyPair;
|
|
91
|
-
|
|
149
|
+
|
|
150
|
+
// ─── AES-256-GCM ─────────────────────────────────────────────────────────────
|
|
151
|
+
|
|
92
152
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
|
|
153
|
+
* Cifra con AES-256-GCM.
|
|
154
|
+
* L'auth tag (16 byte) è suffisso al ciphertext.
|
|
155
|
+
*/
|
|
96
156
|
function aesEncryptGCM(plaintext, key, iv, additionalData) {
|
|
157
|
+
validateAESKey(key);
|
|
97
158
|
const cipher = (0, crypto_1.createCipheriv)('aes-256-gcm', key, iv);
|
|
98
|
-
cipher.setAAD(additionalData);
|
|
99
|
-
|
|
159
|
+
if (additionalData) cipher.setAAD(additionalData);
|
|
160
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
161
|
+
return Buffer.concat([encrypted, cipher.getAuthTag()]);
|
|
100
162
|
}
|
|
163
|
+
|
|
101
164
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
|
|
165
|
+
* Decifra con AES-256-GCM.
|
|
166
|
+
* L'auth tag (16 byte) è suffisso al ciphertext.
|
|
167
|
+
*/
|
|
105
168
|
function aesDecryptGCM(ciphertext, key, iv, additionalData) {
|
|
169
|
+
validateAESKey(key);
|
|
170
|
+
if (ciphertext.length < GCM_TAG_LENGTH) throw new RangeError('Ciphertext GCM troppo corto');
|
|
106
171
|
const decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', key, iv);
|
|
107
|
-
// decrypt additional adata
|
|
108
172
|
const enc = ciphertext.slice(0, ciphertext.length - GCM_TAG_LENGTH);
|
|
109
173
|
const tag = ciphertext.slice(ciphertext.length - GCM_TAG_LENGTH);
|
|
110
|
-
|
|
111
|
-
decipher.setAAD(additionalData);
|
|
174
|
+
if (additionalData) decipher.setAAD(additionalData);
|
|
112
175
|
decipher.setAuthTag(tag);
|
|
113
176
|
return Buffer.concat([decipher.update(enc), decipher.final()]);
|
|
114
177
|
}
|
|
178
|
+
|
|
179
|
+
// ─── AES-256-CTR ─────────────────────────────────────────────────────────────
|
|
180
|
+
|
|
115
181
|
function aesEncryptCTR(plaintext, key, iv) {
|
|
182
|
+
validateAESKey(key);
|
|
116
183
|
const cipher = (0, crypto_1.createCipheriv)('aes-256-ctr', key, iv);
|
|
117
184
|
return Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
118
185
|
}
|
|
186
|
+
|
|
119
187
|
function aesDecryptCTR(ciphertext, key, iv) {
|
|
188
|
+
validateAESKey(key);
|
|
120
189
|
const decipher = (0, crypto_1.createDecipheriv)('aes-256-ctr', key, iv);
|
|
121
190
|
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
122
191
|
}
|
|
123
|
-
|
|
192
|
+
|
|
193
|
+
// ─── AES-256-CBC ─────────────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Decifra AES-256-CBC dove l'IV (16 byte) è prefisso al buffer.
|
|
197
|
+
*/
|
|
124
198
|
function aesDecrypt(buffer, key) {
|
|
125
|
-
|
|
199
|
+
if (buffer.length < IV_LENGTH) throw new RangeError('Buffer CBC troppo corto per contenere IV');
|
|
200
|
+
return aesDecryptWithIV(
|
|
201
|
+
buffer.slice(IV_LENGTH),
|
|
202
|
+
key,
|
|
203
|
+
buffer.slice(0, IV_LENGTH)
|
|
204
|
+
);
|
|
126
205
|
}
|
|
127
|
-
|
|
206
|
+
|
|
207
|
+
/** Decifra AES-256-CBC con IV esplicito */
|
|
128
208
|
function aesDecryptWithIV(buffer, key, IV) {
|
|
209
|
+
validateAESKey(key);
|
|
210
|
+
validateIV(IV);
|
|
129
211
|
const aes = (0, crypto_1.createDecipheriv)('aes-256-cbc', key, IV);
|
|
130
212
|
return Buffer.concat([aes.update(buffer), aes.final()]);
|
|
131
213
|
}
|
|
132
|
-
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Cifra AES-256-CBC con IV casuale (prefissato al risultato).
|
|
217
|
+
*/
|
|
133
218
|
function aesEncrypt(buffer, key) {
|
|
134
|
-
|
|
219
|
+
validateAESKey(key);
|
|
220
|
+
const IV = safeRandomBytes(IV_LENGTH);
|
|
135
221
|
const aes = (0, crypto_1.createCipheriv)('aes-256-cbc', key, IV);
|
|
136
|
-
return Buffer.concat([IV, aes.update(buffer), aes.final()]);
|
|
222
|
+
return Buffer.concat([IV, aes.update(buffer), aes.final()]);
|
|
137
223
|
}
|
|
138
|
-
|
|
224
|
+
|
|
225
|
+
/** Cifra AES-256-CBC con IV esplicito */
|
|
139
226
|
function aesEncrypWithIV(buffer, key, IV) {
|
|
227
|
+
validateAESKey(key);
|
|
228
|
+
validateIV(IV);
|
|
140
229
|
const aes = (0, crypto_1.createCipheriv)('aes-256-cbc', key, IV);
|
|
141
|
-
return Buffer.concat([aes.update(buffer), aes.final()]);
|
|
230
|
+
return Buffer.concat([aes.update(buffer), aes.final()]);
|
|
142
231
|
}
|
|
143
|
-
|
|
232
|
+
|
|
233
|
+
// ─── Hash / HMAC ─────────────────────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
/** HMAC-SHA256 (o altra variante) */
|
|
144
236
|
function hmacSign(buffer, key, variant = 'sha256') {
|
|
145
237
|
return (0, crypto_1.createHmac)(variant, key).update(buffer).digest();
|
|
146
238
|
}
|
|
239
|
+
|
|
240
|
+
/** SHA-256 */
|
|
147
241
|
function sha256(buffer) {
|
|
148
242
|
return (0, crypto_1.createHash)('sha256').update(buffer).digest();
|
|
149
243
|
}
|
|
244
|
+
|
|
245
|
+
/** SHA-512 (aggiunto per completezza) */
|
|
246
|
+
function sha512(buffer) {
|
|
247
|
+
return (0, crypto_1.createHash)('sha512').update(buffer).digest();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** MD5 — usare solo dove strettamente necessario (non per sicurezza) */
|
|
150
251
|
function md5(buffer) {
|
|
151
252
|
return (0, crypto_1.createHash)('md5').update(buffer).digest();
|
|
152
253
|
}
|
|
153
|
-
|
|
254
|
+
|
|
255
|
+
// ─── KDF ─────────────────────────────────────────────────────────────────────
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* HKDF (RFC 5869) tramite Web Crypto API.
|
|
259
|
+
* @param {Buffer|Uint8Array} buffer - Input Key Material
|
|
260
|
+
* @param {number} expandedLength - Byte da derivare
|
|
261
|
+
* @param {{ salt?: Buffer, info?: string }} info
|
|
262
|
+
*/
|
|
154
263
|
async function hkdf(buffer, expandedLength, info) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
:
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const derivedBits = await subtle.deriveBits(
|
|
168
|
-
name: 'HKDF',
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
info: infoBytes
|
|
172
|
-
}, importedKey, expandedLength * 8 // Convert bytes to bits
|
|
264
|
+
if (expandedLength <= 0) throw new RangeError('expandedLength deve essere > 0');
|
|
265
|
+
|
|
266
|
+
const inputKeyMaterial = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
267
|
+
const salt = info.salt ? new Uint8Array(info.salt) : new Uint8Array(0);
|
|
268
|
+
const infoBytes = info.info ? new TextEncoder().encode(info.info) : new Uint8Array(0);
|
|
269
|
+
|
|
270
|
+
const importedKey = await subtle.importKey(
|
|
271
|
+
'raw', inputKeyMaterial,
|
|
272
|
+
{ name: 'HKDF' },
|
|
273
|
+
false, ['deriveBits']
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const derivedBits = await subtle.deriveBits(
|
|
277
|
+
{ name: 'HKDF', hash: 'SHA-256', salt, info: infoBytes },
|
|
278
|
+
importedKey,
|
|
279
|
+
expandedLength * 8
|
|
173
280
|
);
|
|
281
|
+
|
|
174
282
|
return Buffer.from(derivedBits);
|
|
175
283
|
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Deriva una chiave dal pairing code tramite PBKDF2.
|
|
287
|
+
* @param {string} pairingCode
|
|
288
|
+
* @param {Buffer|Uint8Array} salt
|
|
289
|
+
*/
|
|
176
290
|
async function derivePairingCodeKey(pairingCode, salt) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
291
|
+
if (!pairingCode || typeof pairingCode !== 'string') throw new TypeError('pairingCode deve essere una stringa');
|
|
292
|
+
|
|
293
|
+
const encoder = new TextEncoder();
|
|
294
|
+
const codeBuffer = encoder.encode(pairingCode);
|
|
180
295
|
const saltBuffer = salt instanceof Uint8Array ? salt : new Uint8Array(salt);
|
|
181
|
-
|
|
182
|
-
const keyMaterial = await subtle.importKey(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
hash: 'SHA-256'
|
|
190
|
-
|
|
296
|
+
|
|
297
|
+
const keyMaterial = await subtle.importKey(
|
|
298
|
+
'raw', codeBuffer,
|
|
299
|
+
{ name: 'PBKDF2' },
|
|
300
|
+
false, ['deriveBits']
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
const derivedBits = await subtle.deriveBits(
|
|
304
|
+
{ name: 'PBKDF2', salt: saltBuffer, iterations: PBKDF2_ITER, hash: 'SHA-256' },
|
|
305
|
+
keyMaterial,
|
|
306
|
+
256 // 32 byte
|
|
191
307
|
);
|
|
308
|
+
|
|
192
309
|
return Buffer.from(derivedBits);
|
|
193
310
|
}
|