@gjsify/crypto 0.3.13 → 0.3.15
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/esm/asn1.js +576 -450
- package/lib/esm/bigint-math.js +37 -28
- package/lib/esm/cipher.js +1252 -1229
- package/lib/esm/constants.js +12 -13
- package/lib/esm/crypto-utils.js +54 -36
- package/lib/esm/dh.js +408 -368
- package/lib/esm/ecdh.js +403 -321
- package/lib/esm/ecdsa.js +138 -111
- package/lib/esm/hash.js +100 -89
- package/lib/esm/hkdf.js +65 -47
- package/lib/esm/hmac.js +95 -90
- package/lib/esm/index.js +75 -148
- package/lib/esm/key-object.js +348 -307
- package/lib/esm/mgf1.js +30 -24
- package/lib/esm/pbkdf2.js +66 -59
- package/lib/esm/public-encrypt.js +203 -156
- package/lib/esm/random.js +137 -124
- package/lib/esm/rsa-oaep.js +94 -87
- package/lib/esm/rsa-pss.js +95 -88
- package/lib/esm/scrypt.js +116 -115
- package/lib/esm/sign.js +267 -237
- package/lib/esm/timing-safe-equal.js +16 -11
- package/lib/esm/x509.js +215 -206
- package/package.json +7 -7
package/lib/esm/mgf1.js
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
|
-
import { Hash } from "./hash.js";
|
|
2
1
|
import { hashSize } from "./crypto-utils.js";
|
|
2
|
+
import { Hash } from "./hash.js";
|
|
3
|
+
|
|
4
|
+
//#region src/mgf1.ts
|
|
5
|
+
/**
|
|
6
|
+
* MGF1 mask generation function.
|
|
7
|
+
* Produces a mask of `length` bytes from `seed` using `hashAlgo`.
|
|
8
|
+
*/
|
|
3
9
|
function mgf1(hashAlgo, seed, length) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
const hashLen = hashSize(hashAlgo);
|
|
11
|
+
const mask = new Uint8Array(length);
|
|
12
|
+
let offset = 0;
|
|
13
|
+
let counter = 0;
|
|
14
|
+
while (offset < length) {
|
|
15
|
+
const C = new Uint8Array(4);
|
|
16
|
+
C[0] = counter >>> 24 & 255;
|
|
17
|
+
C[1] = counter >>> 16 & 255;
|
|
18
|
+
C[2] = counter >>> 8 & 255;
|
|
19
|
+
C[3] = counter & 255;
|
|
20
|
+
const hash = new Hash(hashAlgo);
|
|
21
|
+
hash.update(seed);
|
|
22
|
+
hash.update(C);
|
|
23
|
+
const digest = new Uint8Array(hash.digest());
|
|
24
|
+
const toCopy = Math.min(digest.length, length - offset);
|
|
25
|
+
mask.set(digest.slice(0, toCopy), offset);
|
|
26
|
+
offset += toCopy;
|
|
27
|
+
counter++;
|
|
28
|
+
}
|
|
29
|
+
return mask;
|
|
24
30
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { mgf1 };
|
package/lib/esm/pbkdf2.js
CHANGED
|
@@ -1,68 +1,75 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DIGEST_SIZES, SUPPORTED_ALGORITHMS, normalizeAlgorithm, toBuffer } from "./crypto-utils.js";
|
|
2
2
|
import { Hmac } from "./hmac.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
|
|
5
|
+
//#region src/pbkdf2.ts
|
|
4
6
|
function hmacDigest(algo, key, data) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
const hmac = new Hmac(algo, key);
|
|
8
|
+
hmac.update(data);
|
|
9
|
+
return hmac.digest();
|
|
8
10
|
}
|
|
9
11
|
function validateParameters(iterations, keylen) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
if (typeof iterations !== "number" || iterations < 0 || !Number.isFinite(iterations)) {
|
|
13
|
+
throw new TypeError("iterations must be a positive number");
|
|
14
|
+
}
|
|
15
|
+
if (iterations === 0) {
|
|
16
|
+
throw new TypeError("iterations must be a positive number");
|
|
17
|
+
}
|
|
18
|
+
if (typeof keylen !== "number" || keylen < 0 || !Number.isFinite(keylen) || keylen > 2147483647) {
|
|
19
|
+
throw new TypeError("keylen must be a positive number");
|
|
20
|
+
}
|
|
19
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Synchronous PBKDF2 key derivation.
|
|
24
|
+
*/
|
|
20
25
|
function pbkdf2Sync(password, salt, iterations, keylen, digest) {
|
|
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
|
-
|
|
26
|
+
validateParameters(iterations, keylen);
|
|
27
|
+
const passwordBuf = toBuffer(password);
|
|
28
|
+
const saltBuf = toBuffer(salt);
|
|
29
|
+
const algo = normalizeAlgorithm(digest || "sha1");
|
|
30
|
+
const hashLen = DIGEST_SIZES[algo];
|
|
31
|
+
if (!SUPPORTED_ALGORITHMS.has(algo) || hashLen === undefined) {
|
|
32
|
+
throw new TypeError(`Unknown message digest: ${digest || "sha1"}`);
|
|
33
|
+
}
|
|
34
|
+
if (keylen === 0) {
|
|
35
|
+
return Buffer.alloc(0);
|
|
36
|
+
}
|
|
37
|
+
const numBlocks = Math.ceil(keylen / hashLen);
|
|
38
|
+
const dk = Buffer.allocUnsafe(numBlocks * hashLen);
|
|
39
|
+
for (let blockIndex = 1; blockIndex <= numBlocks; blockIndex++) {
|
|
40
|
+
const block = Buffer.allocUnsafe(saltBuf.length + 4);
|
|
41
|
+
saltBuf.copy(block, 0);
|
|
42
|
+
block.writeUInt32BE(blockIndex, saltBuf.length);
|
|
43
|
+
let u = hmacDigest(algo, passwordBuf, block);
|
|
44
|
+
let t = Buffer.from(u);
|
|
45
|
+
for (let iter = 1; iter < iterations; iter++) {
|
|
46
|
+
u = hmacDigest(algo, passwordBuf, u);
|
|
47
|
+
for (let k = 0; k < hashLen; k++) {
|
|
48
|
+
t[k] ^= u[k];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
t.copy(dk, (blockIndex - 1) * hashLen);
|
|
52
|
+
}
|
|
53
|
+
return Buffer.from(dk.buffer, dk.byteOffset, keylen);
|
|
49
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Asynchronous PBKDF2 key derivation.
|
|
57
|
+
*/
|
|
50
58
|
function pbkdf2(password, salt, iterations, keylen, digest, callback) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
try {
|
|
60
|
+
validateParameters(iterations, keylen);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
try {
|
|
66
|
+
const result = pbkdf2Sync(password, salt, iterations, keylen, digest);
|
|
67
|
+
callback(null, result);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
callback(err instanceof Error ? err : new Error(String(err)));
|
|
70
|
+
}
|
|
71
|
+
}, 0);
|
|
64
72
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
};
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { pbkdf2, pbkdf2Sync };
|
|
@@ -1,175 +1,222 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
import { randomBytes } from "./random.js";
|
|
3
1
|
import { parsePemKey, rsaKeySize } from "./asn1.js";
|
|
4
|
-
import {
|
|
2
|
+
import { bigIntToBytes, bytesToBigInt, modPow } from "./bigint-math.js";
|
|
3
|
+
import { randomBytes } from "./random.js";
|
|
4
|
+
import { Buffer } from "node:buffer";
|
|
5
|
+
|
|
6
|
+
//#region src/public-encrypt.ts
|
|
5
7
|
function extractPem(key) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
if (typeof key === "string") {
|
|
9
|
+
return key;
|
|
10
|
+
}
|
|
11
|
+
if (Buffer.isBuffer(key) || key instanceof Uint8Array) {
|
|
12
|
+
return Buffer.from(key).toString("utf8");
|
|
13
|
+
}
|
|
14
|
+
if (key && typeof key === "object" && "key" in key) {
|
|
15
|
+
const k = key.key;
|
|
16
|
+
if (typeof k === "string") return k;
|
|
17
|
+
if (Buffer.isBuffer(k) || k instanceof Uint8Array) return Buffer.from(k).toString("utf8");
|
|
18
|
+
}
|
|
19
|
+
throw new TypeError("Invalid key argument");
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Apply PKCS#1 v1.5 Type 2 padding (for encryption).
|
|
23
|
+
* Format: 0x00 0x02 [random non-zero bytes] 0x00 [data]
|
|
24
|
+
* The padding string (PS) must be at least 8 bytes.
|
|
25
|
+
*/
|
|
19
26
|
function pkcs1v15Type2Pad(data, keyLen) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
const maxDataLen = keyLen - 11;
|
|
28
|
+
if (data.length > maxDataLen) {
|
|
29
|
+
throw new Error(`Data too long for key size. Max ${maxDataLen} bytes, got ${data.length}`);
|
|
30
|
+
}
|
|
31
|
+
const padLen = keyLen - data.length - 3;
|
|
32
|
+
const em = new Uint8Array(keyLen);
|
|
33
|
+
em[0] = 0;
|
|
34
|
+
em[1] = 2;
|
|
35
|
+
const padding = randomBytes(padLen);
|
|
36
|
+
for (let i = 0; i < padLen; i++) {
|
|
37
|
+
while (padding[i] === 0) {
|
|
38
|
+
const replacement = randomBytes(1);
|
|
39
|
+
padding[i] = replacement[0];
|
|
40
|
+
}
|
|
41
|
+
em[2 + i] = padding[i];
|
|
42
|
+
}
|
|
43
|
+
em[2 + padLen] = 0;
|
|
44
|
+
em.set(data, 3 + padLen);
|
|
45
|
+
return em;
|
|
39
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Apply PKCS#1 v1.5 Type 1 padding (for private-key encryption / signature).
|
|
49
|
+
* Format: 0x00 0x01 [0xFF bytes] 0x00 [data]
|
|
50
|
+
*/
|
|
40
51
|
function pkcs1v15Type1Pad(data, keyLen) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const maxDataLen = keyLen - 11;
|
|
53
|
+
if (data.length > maxDataLen) {
|
|
54
|
+
throw new Error(`Data too long for key size. Max ${maxDataLen} bytes, got ${data.length}`);
|
|
55
|
+
}
|
|
56
|
+
const padLen = keyLen - data.length - 3;
|
|
57
|
+
const em = new Uint8Array(keyLen);
|
|
58
|
+
em[0] = 0;
|
|
59
|
+
em[1] = 1;
|
|
60
|
+
for (let i = 2; i < 2 + padLen; i++) {
|
|
61
|
+
em[i] = 255;
|
|
62
|
+
}
|
|
63
|
+
em[2 + padLen] = 0;
|
|
64
|
+
em.set(data, 3 + padLen);
|
|
65
|
+
return em;
|
|
55
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Remove PKCS#1 v1.5 Type 2 padding (after decryption with private key).
|
|
69
|
+
* Expects: 0x00 0x02 [random non-zero bytes] 0x00 [data]
|
|
70
|
+
*/
|
|
56
71
|
function pkcs1v15Type2Unpad(em) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
if (em.length < 11) {
|
|
73
|
+
throw new Error("Decryption error: message too short");
|
|
74
|
+
}
|
|
75
|
+
if (em[0] !== 0 || em[1] !== 2) {
|
|
76
|
+
throw new Error("Decryption error: invalid padding");
|
|
77
|
+
}
|
|
78
|
+
let sepIdx = 2;
|
|
79
|
+
while (sepIdx < em.length && em[sepIdx] !== 0) {
|
|
80
|
+
sepIdx++;
|
|
81
|
+
}
|
|
82
|
+
if (sepIdx >= em.length || sepIdx < 10) {
|
|
83
|
+
throw new Error("Decryption error: invalid padding");
|
|
84
|
+
}
|
|
85
|
+
return em.slice(sepIdx + 1);
|
|
71
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Remove PKCS#1 v1.5 Type 1 padding (after decryption with public key).
|
|
89
|
+
* Expects: 0x00 0x01 [0xFF bytes] 0x00 [data]
|
|
90
|
+
*/
|
|
72
91
|
function pkcs1v15Type1Unpad(em) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
if (em.length < 11) {
|
|
93
|
+
throw new Error("Decryption error: message too short");
|
|
94
|
+
}
|
|
95
|
+
if (em[0] !== 0 || em[1] !== 1) {
|
|
96
|
+
throw new Error("Decryption error: invalid padding");
|
|
97
|
+
}
|
|
98
|
+
let sepIdx = 2;
|
|
99
|
+
while (sepIdx < em.length && em[sepIdx] === 255) {
|
|
100
|
+
sepIdx++;
|
|
101
|
+
}
|
|
102
|
+
if (sepIdx >= em.length || em[sepIdx] !== 0 || sepIdx < 10) {
|
|
103
|
+
throw new Error("Decryption error: invalid padding");
|
|
104
|
+
}
|
|
105
|
+
return em.slice(sepIdx + 1);
|
|
87
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Encrypt data using an RSA public key with PKCS#1 v1.5 Type 2 padding.
|
|
109
|
+
*
|
|
110
|
+
* @param key - PEM-encoded RSA public key (or private key, from which public components are extracted)
|
|
111
|
+
* @param buffer - Data to encrypt (must be <= keyLen - 11 bytes)
|
|
112
|
+
* @returns Encrypted data as a Buffer
|
|
113
|
+
*/
|
|
88
114
|
function publicEncrypt(key, buffer) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
115
|
+
const pem = extractPem(key);
|
|
116
|
+
const parsed = parsePemKey(pem);
|
|
117
|
+
let n;
|
|
118
|
+
let e;
|
|
119
|
+
if (parsed.type === "rsa-public") {
|
|
120
|
+
n = parsed.components.n;
|
|
121
|
+
e = parsed.components.e;
|
|
122
|
+
} else if (parsed.type === "rsa-private") {
|
|
123
|
+
n = parsed.components.n;
|
|
124
|
+
e = parsed.components.e;
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error("Key must be an RSA public or private key");
|
|
127
|
+
}
|
|
128
|
+
const keyLen = rsaKeySize(n);
|
|
129
|
+
const data = buffer instanceof Uint8Array ? buffer : Buffer.from(buffer);
|
|
130
|
+
const em = pkcs1v15Type2Pad(data, keyLen);
|
|
131
|
+
const m = bytesToBigInt(em);
|
|
132
|
+
const c = modPow(m, e, n);
|
|
133
|
+
return Buffer.from(bigIntToBytes(c, keyLen));
|
|
108
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Decrypt data using an RSA private key (reverses publicEncrypt).
|
|
137
|
+
*
|
|
138
|
+
* @param key - PEM-encoded RSA private key
|
|
139
|
+
* @param buffer - Encrypted data
|
|
140
|
+
* @returns Decrypted data as a Buffer
|
|
141
|
+
*/
|
|
109
142
|
function privateDecrypt(key, buffer) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
143
|
+
const pem = extractPem(key);
|
|
144
|
+
const parsed = parsePemKey(pem);
|
|
145
|
+
if (parsed.type !== "rsa-private") {
|
|
146
|
+
throw new Error("Key must be an RSA private key");
|
|
147
|
+
}
|
|
148
|
+
const { n, d } = parsed.components;
|
|
149
|
+
const keyLen = rsaKeySize(n);
|
|
150
|
+
const data = buffer instanceof Uint8Array ? buffer : Buffer.from(buffer);
|
|
151
|
+
if (data.length !== keyLen) {
|
|
152
|
+
throw new Error(`Data length (${data.length}) does not match key length (${keyLen})`);
|
|
153
|
+
}
|
|
154
|
+
const c = bytesToBigInt(data);
|
|
155
|
+
if (c >= n) {
|
|
156
|
+
throw new Error("Decryption error: cipher value out of range");
|
|
157
|
+
}
|
|
158
|
+
const m = modPow(c, d, n);
|
|
159
|
+
const em = bigIntToBytes(m, keyLen);
|
|
160
|
+
return Buffer.from(pkcs1v15Type2Unpad(em));
|
|
128
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Encrypt data using an RSA private key with PKCS#1 v1.5 Type 1 padding.
|
|
164
|
+
* This is the raw RSA private-key operation used for compatibility with
|
|
165
|
+
* signature-like use cases.
|
|
166
|
+
*
|
|
167
|
+
* @param key - PEM-encoded RSA private key
|
|
168
|
+
* @param buffer - Data to encrypt
|
|
169
|
+
* @returns Encrypted data as a Buffer
|
|
170
|
+
*/
|
|
129
171
|
function privateEncrypt(key, buffer) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
172
|
+
const pem = extractPem(key);
|
|
173
|
+
const parsed = parsePemKey(pem);
|
|
174
|
+
if (parsed.type !== "rsa-private") {
|
|
175
|
+
throw new Error("Key must be an RSA private key");
|
|
176
|
+
}
|
|
177
|
+
const { n, d } = parsed.components;
|
|
178
|
+
const keyLen = rsaKeySize(n);
|
|
179
|
+
const data = buffer instanceof Uint8Array ? buffer : Buffer.from(buffer);
|
|
180
|
+
const em = pkcs1v15Type1Pad(data, keyLen);
|
|
181
|
+
const m = bytesToBigInt(em);
|
|
182
|
+
const c = modPow(m, d, n);
|
|
183
|
+
return Buffer.from(bigIntToBytes(c, keyLen));
|
|
142
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Decrypt data using an RSA public key (reverses privateEncrypt).
|
|
187
|
+
* Removes PKCS#1 v1.5 Type 1 padding.
|
|
188
|
+
*
|
|
189
|
+
* @param key - PEM-encoded RSA public key (or private key for public components)
|
|
190
|
+
* @param buffer - Encrypted data
|
|
191
|
+
* @returns Decrypted data as a Buffer
|
|
192
|
+
*/
|
|
143
193
|
function publicDecrypt(key, buffer) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
194
|
+
const pem = extractPem(key);
|
|
195
|
+
const parsed = parsePemKey(pem);
|
|
196
|
+
let n;
|
|
197
|
+
let e;
|
|
198
|
+
if (parsed.type === "rsa-public") {
|
|
199
|
+
n = parsed.components.n;
|
|
200
|
+
e = parsed.components.e;
|
|
201
|
+
} else if (parsed.type === "rsa-private") {
|
|
202
|
+
n = parsed.components.n;
|
|
203
|
+
e = parsed.components.e;
|
|
204
|
+
} else {
|
|
205
|
+
throw new Error("Key must be an RSA public or private key");
|
|
206
|
+
}
|
|
207
|
+
const keyLen = rsaKeySize(n);
|
|
208
|
+
const data = buffer instanceof Uint8Array ? buffer : Buffer.from(buffer);
|
|
209
|
+
if (data.length !== keyLen) {
|
|
210
|
+
throw new Error(`Data length (${data.length}) does not match key length (${keyLen})`);
|
|
211
|
+
}
|
|
212
|
+
const c = bytesToBigInt(data);
|
|
213
|
+
if (c >= n) {
|
|
214
|
+
throw new Error("Decryption error: cipher value out of range");
|
|
215
|
+
}
|
|
216
|
+
const m = modPow(c, e, n);
|
|
217
|
+
const em = bigIntToBytes(m, keyLen);
|
|
218
|
+
return Buffer.from(pkcs1v15Type1Unpad(em));
|
|
169
219
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
publicDecrypt,
|
|
174
|
-
publicEncrypt
|
|
175
|
-
};
|
|
220
|
+
|
|
221
|
+
//#endregion
|
|
222
|
+
export { privateDecrypt, privateEncrypt, publicDecrypt, publicEncrypt };
|