@gjsify/crypto 0.3.15 → 0.3.17

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.
@@ -1,222 +1 @@
1
- import { parsePemKey, rsaKeySize } from "./asn1.js";
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
7
- function extractPem(key) {
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");
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
- */
26
- function pkcs1v15Type2Pad(data, keyLen) {
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;
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
- */
51
- function pkcs1v15Type1Pad(data, keyLen) {
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;
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
- */
71
- function pkcs1v15Type2Unpad(em) {
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);
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
- */
91
- function pkcs1v15Type1Unpad(em) {
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);
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
- */
114
- function publicEncrypt(key, buffer) {
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));
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
- */
142
- function privateDecrypt(key, buffer) {
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));
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
- */
171
- function privateEncrypt(key, buffer) {
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));
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
- */
193
- function publicDecrypt(key, buffer) {
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));
219
- }
220
-
221
- //#endregion
222
- export { privateDecrypt, privateEncrypt, publicDecrypt, publicEncrypt };
1
+ import{parsePemKey as e,rsaKeySize as t}from"./asn1.js";import{bigIntToBytes as n,bytesToBigInt as r,modPow as i}from"./bigint-math.js";import{randomBytes as a}from"./random.js";import{Buffer as o}from"node:buffer";function s(e){if(typeof e==`string`)return e;if(o.isBuffer(e)||e instanceof Uint8Array)return o.from(e).toString(`utf8`);if(e&&typeof e==`object`&&`key`in e){let t=e.key;if(typeof t==`string`)return t;if(o.isBuffer(t)||t instanceof Uint8Array)return o.from(t).toString(`utf8`)}throw TypeError(`Invalid key argument`)}function c(e,t){let n=t-11;if(e.length>n)throw Error(`Data too long for key size. Max ${n} bytes, got ${e.length}`);let r=t-e.length-3,i=new Uint8Array(t);i[0]=0,i[1]=2;let o=a(r);for(let e=0;e<r;e++){for(;o[e]===0;)o[e]=a(1)[0];i[2+e]=o[e]}return i[2+r]=0,i.set(e,3+r),i}function l(e,t){let n=t-11;if(e.length>n)throw Error(`Data too long for key size. Max ${n} bytes, got ${e.length}`);let r=t-e.length-3,i=new Uint8Array(t);i[0]=0,i[1]=1;for(let e=2;e<2+r;e++)i[e]=255;return i[2+r]=0,i.set(e,3+r),i}function u(e){if(e.length<11)throw Error(`Decryption error: message too short`);if(e[0]!==0||e[1]!==2)throw Error(`Decryption error: invalid padding`);let t=2;for(;t<e.length&&e[t]!==0;)t++;if(t>=e.length||t<10)throw Error(`Decryption error: invalid padding`);return e.slice(t+1)}function d(e){if(e.length<11)throw Error(`Decryption error: message too short`);if(e[0]!==0||e[1]!==1)throw Error(`Decryption error: invalid padding`);let t=2;for(;t<e.length&&e[t]===255;)t++;if(t>=e.length||e[t]!==0||t<10)throw Error(`Decryption error: invalid padding`);return e.slice(t+1)}function f(a,l){let u=e(s(a)),d,f;if(u.type===`rsa-public`)d=u.components.n,f=u.components.e;else if(u.type===`rsa-private`)d=u.components.n,f=u.components.e;else throw Error(`Key must be an RSA public or private key`);let p=t(d),m=i(r(c(l instanceof Uint8Array?l:o.from(l),p)),f,d);return o.from(n(m,p))}function p(a,c){let l=e(s(a));if(l.type!==`rsa-private`)throw Error(`Key must be an RSA private key`);let{n:d,d:f}=l.components,p=t(d),m=c instanceof Uint8Array?c:o.from(c);if(m.length!==p)throw Error(`Data length (${m.length}) does not match key length (${p})`);let h=r(m);if(h>=d)throw Error(`Decryption error: cipher value out of range`);let g=n(i(h,f,d),p);return o.from(u(g))}function m(a,c){let u=e(s(a));if(u.type!==`rsa-private`)throw Error(`Key must be an RSA private key`);let{n:d,d:f}=u.components,p=t(d),m=i(r(l(c instanceof Uint8Array?c:o.from(c),p)),f,d);return o.from(n(m,p))}function h(a,c){let l=e(s(a)),u,f;if(l.type===`rsa-public`)u=l.components.n,f=l.components.e;else if(l.type===`rsa-private`)u=l.components.n,f=l.components.e;else throw Error(`Key must be an RSA public or private key`);let p=t(u),m=c instanceof Uint8Array?c:o.from(c);if(m.length!==p)throw Error(`Data length (${m.length}) does not match key length (${p})`);let h=r(m);if(h>=u)throw Error(`Decryption error: cipher value out of range`);let g=n(i(h,f,u),p);return o.from(d(g))}export{p as privateDecrypt,m as privateEncrypt,h as publicDecrypt,f as publicEncrypt};
package/lib/esm/random.js CHANGED
@@ -1,151 +1 @@
1
- import { Buffer } from "node:buffer";
2
-
3
- //#region src/random.ts
4
- const hasWebCrypto = typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.getRandomValues === "function";
5
- /**
6
- * Fill a Uint8Array with random bytes, using WebCrypto or GLib.Random fallback.
7
- */
8
- function fillRandom(view) {
9
- if (hasWebCrypto) {
10
- for (let offset = 0; offset < view.length; offset += 65536) {
11
- const length = Math.min(view.length - offset, 65536);
12
- const slice = new Uint8Array(view.buffer, view.byteOffset + offset, length);
13
- globalThis.crypto.getRandomValues(slice);
14
- }
15
- } else {
16
- try {
17
- const GLib = imports.gi.GLib;
18
- for (let i = 0; i < view.length; i++) {
19
- view[i] = GLib.random_int_range(0, 256);
20
- }
21
- } catch {
22
- for (let i = 0; i < view.length; i++) {
23
- view[i] = Math.floor(Math.random() * 256);
24
- }
25
- }
26
- }
27
- }
28
- function randomBytes(size, callback) {
29
- if (typeof size !== "number" || size < 0 || !Number.isInteger(size)) {
30
- throw new TypeError(`The "size" argument must be a non-negative integer. Received ${size}`);
31
- }
32
- try {
33
- const buf = Buffer.alloc(size);
34
- if (size > 0) {
35
- fillRandom(new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
36
- }
37
- if (callback) {
38
- callback(null, buf);
39
- } else {
40
- return buf;
41
- }
42
- } catch (err) {
43
- if (callback) {
44
- callback(err, Buffer.alloc(0));
45
- } else {
46
- throw err;
47
- }
48
- }
49
- }
50
- /**
51
- * Fill a buffer with cryptographically strong pseudo-random data (synchronous).
52
- */
53
- function randomFillSync(buffer, offset = 0, size) {
54
- const length = size ?? buffer.length - offset;
55
- if (offset < 0 || offset > buffer.length) {
56
- throw new RangeError(`The value of "offset" is out of range. Received ${offset}`);
57
- }
58
- if (length < 0 || offset + length > buffer.length) {
59
- throw new RangeError(`The value of "size" is out of range. Received ${length}`);
60
- }
61
- if (length > 0) {
62
- const byteOffset = buffer instanceof Buffer ? buffer.byteOffset : buffer.byteOffset;
63
- const view = new Uint8Array(buffer.buffer, byteOffset + offset, length);
64
- fillRandom(view);
65
- }
66
- return buffer;
67
- }
68
- /**
69
- * Fill a buffer with cryptographically strong pseudo-random data (async).
70
- */
71
- function randomFill(buffer, offset, size, callback) {
72
- let _offset;
73
- let _size;
74
- let _callback;
75
- if (typeof offset === "function") {
76
- _callback = offset;
77
- _offset = 0;
78
- _size = buffer.length;
79
- } else if (typeof size === "function") {
80
- _callback = size;
81
- _offset = offset;
82
- _size = buffer.length - offset;
83
- } else {
84
- _callback = callback;
85
- _offset = offset;
86
- _size = size;
87
- }
88
- try {
89
- randomFillSync(buffer, _offset, _size);
90
- _callback(null, buffer);
91
- } catch (err) {
92
- _callback(err, buffer);
93
- }
94
- }
95
- /**
96
- * Generate a random UUID v4 string.
97
- */
98
- function randomUUID() {
99
- if (hasWebCrypto && typeof globalThis.crypto.randomUUID === "function") {
100
- return globalThis.crypto.randomUUID();
101
- }
102
- const bytes = new Uint8Array(16);
103
- fillRandom(bytes);
104
- bytes[6] = bytes[6] & 15 | 64;
105
- bytes[8] = bytes[8] & 63 | 128;
106
- const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
107
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
108
- }
109
- /**
110
- * Generate a random integer between min (inclusive) and max (exclusive).
111
- */
112
- function randomInt(min, max, callback) {
113
- let _min;
114
- let _max;
115
- let _callback;
116
- if (typeof max === "function") {
117
- _callback = max;
118
- _max = min;
119
- _min = 0;
120
- } else if (typeof max === "number") {
121
- _min = min;
122
- _max = max;
123
- _callback = callback;
124
- } else {
125
- _max = min;
126
- _min = 0;
127
- _callback = callback;
128
- }
129
- if (!Number.isInteger(_min)) {
130
- throw new TypeError(`The "min" argument must be a safe integer. Received ${_min}`);
131
- }
132
- if (!Number.isInteger(_max)) {
133
- throw new TypeError(`The "max" argument must be a safe integer. Received ${_max}`);
134
- }
135
- if (_min >= _max) {
136
- throw new RangeError(`The value of "min" must be less than "max". Received min: ${_min}, max: ${_max}`);
137
- }
138
- const range = _max - _min;
139
- const bytes = new Uint32Array(1);
140
- const view = new Uint8Array(bytes.buffer);
141
- fillRandom(view);
142
- const value = _min + bytes[0] % range;
143
- if (_callback) {
144
- _callback(null, value);
145
- } else {
146
- return value;
147
- }
148
- }
149
-
150
- //#endregion
151
- export { randomBytes, randomFill, randomFillSync, randomInt, randomUUID };
1
+ import{Buffer as e}from"node:buffer";const t=globalThis.crypto!==void 0&&typeof globalThis.crypto.getRandomValues==`function`;function n(e){if(t)for(let t=0;t<e.length;t+=65536){let n=Math.min(e.length-t,65536),r=new Uint8Array(e.buffer,e.byteOffset+t,n);globalThis.crypto.getRandomValues(r)}else try{let t=imports.gi.GLib;for(let n=0;n<e.length;n++)e[n]=t.random_int_range(0,256)}catch{for(let t=0;t<e.length;t++)e[t]=Math.floor(Math.random()*256)}}function r(t,r){if(typeof t!=`number`||t<0||!Number.isInteger(t))throw TypeError(`The "size" argument must be a non-negative integer. Received ${t}`);try{let i=e.alloc(t);if(t>0&&n(new Uint8Array(i.buffer,i.byteOffset,i.byteLength)),r)r(null,i);else return i}catch(t){if(r)r(t,e.alloc(0));else throw t}}function i(t,r=0,i){let a=i??t.length-r;if(r<0||r>t.length)throw RangeError(`The value of "offset" is out of range. Received ${r}`);if(a<0||r+a>t.length)throw RangeError(`The value of "size" is out of range. Received ${a}`);if(a>0){let i=(t instanceof e,t.byteOffset);n(new Uint8Array(t.buffer,i+r,a))}return t}function a(e,t,n,r){let a,o,s;typeof t==`function`?(s=t,a=0,o=e.length):typeof n==`function`?(s=n,a=t,o=e.length-t):(s=r,a=t,o=n);try{i(e,a,o),s(null,e)}catch(t){s(t,e)}}function o(){if(t&&typeof globalThis.crypto.randomUUID==`function`)return globalThis.crypto.randomUUID();let e=new Uint8Array(16);n(e),e[6]=e[6]&15|64,e[8]=e[8]&63|128;let r=Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``);return`${r.slice(0,8)}-${r.slice(8,12)}-${r.slice(12,16)}-${r.slice(16,20)}-${r.slice(20)}`}function s(e,t,r){let i,a,o;if(typeof t==`function`?(o=t,a=e,i=0):typeof t==`number`?(i=e,a=t,o=r):(a=e,i=0,o=r),!Number.isInteger(i))throw TypeError(`The "min" argument must be a safe integer. Received ${i}`);if(!Number.isInteger(a))throw TypeError(`The "max" argument must be a safe integer. Received ${a}`);if(i>=a)throw RangeError(`The value of "min" must be less than "max". Received min: ${i}, max: ${a}`);let s=a-i,c=new Uint32Array(1);n(new Uint8Array(c.buffer));let l=i+c[0]%s;if(o)o(null,l);else return l}export{r as randomBytes,a as randomFill,i as randomFillSync,s as randomInt,o as randomUUID};
@@ -1,102 +1 @@
1
- import { parsePemKey, rsaKeySize } from "./asn1.js";
2
- import { bigIntToBytes, bytesToBigInt, modPow } from "./bigint-math.js";
3
- import { hashSize } from "./crypto-utils.js";
4
- import { randomBytes } from "./random.js";
5
- import { Hash } from "./hash.js";
6
- import { mgf1 } from "./mgf1.js";
7
-
8
- //#region src/rsa-oaep.ts
9
- function hashDigest(algo, data) {
10
- const h = new Hash(algo);
11
- h.update(data);
12
- return new Uint8Array(h.digest());
13
- }
14
- /**
15
- * RSA-OAEP encrypt using PEM public key.
16
- */
17
- function rsaOaepEncrypt(hashAlgo, pubKeyPem, plaintext, label) {
18
- const parsed = parsePemKey(pubKeyPem);
19
- let n, e;
20
- if (parsed.type === "rsa-public") {
21
- ({n, e} = parsed.components);
22
- } else if (parsed.type === "rsa-private") {
23
- ({n, e} = parsed.components);
24
- } else {
25
- throw new Error("RSA-OAEP: expected RSA key");
26
- }
27
- const keyBytes = Math.ceil(rsaKeySize(n) / 8);
28
- const hLen = hashSize(hashAlgo);
29
- if (plaintext.length > keyBytes - 2 * hLen - 2) {
30
- throw new Error("RSA-OAEP: message too long");
31
- }
32
- const lHash = hashDigest(hashAlgo, label || new Uint8Array(0));
33
- const dbLen = keyBytes - hLen - 1;
34
- const DB = new Uint8Array(dbLen);
35
- DB.set(lHash, 0);
36
- DB[dbLen - plaintext.length - 1] = 1;
37
- DB.set(plaintext, dbLen - plaintext.length);
38
- const seed = new Uint8Array(randomBytes(hLen));
39
- const dbMask = mgf1(hashAlgo, seed, dbLen);
40
- const maskedDB = new Uint8Array(dbLen);
41
- for (let i = 0; i < dbLen; i++) maskedDB[i] = DB[i] ^ dbMask[i];
42
- const seedMask = mgf1(hashAlgo, maskedDB, hLen);
43
- const maskedSeed = new Uint8Array(hLen);
44
- for (let i = 0; i < hLen; i++) maskedSeed[i] = seed[i] ^ seedMask[i];
45
- const EM = new Uint8Array(keyBytes);
46
- EM[0] = 0;
47
- EM.set(maskedSeed, 1);
48
- EM.set(maskedDB, 1 + hLen);
49
- const m = bytesToBigInt(EM);
50
- const c = modPow(m, e, n);
51
- return bigIntToBytes(c, keyBytes);
52
- }
53
- /**
54
- * RSA-OAEP decrypt using PEM private key.
55
- */
56
- function rsaOaepDecrypt(hashAlgo, privKeyPem, ciphertext, label) {
57
- const parsed = parsePemKey(privKeyPem);
58
- if (parsed.type !== "rsa-private") throw new Error("RSA-OAEP: expected RSA private key");
59
- const { n, d } = parsed.components;
60
- const keyBytes = Math.ceil(rsaKeySize(n) / 8);
61
- const hLen = hashSize(hashAlgo);
62
- if (ciphertext.length !== keyBytes || keyBytes < 2 * hLen + 2) {
63
- throw new Error("RSA-OAEP: decryption error");
64
- }
65
- const c = bytesToBigInt(ciphertext);
66
- const m = modPow(c, d, n);
67
- const EM = bigIntToBytes(m, keyBytes);
68
- const Y = EM[0];
69
- const maskedSeed = EM.slice(1, 1 + hLen);
70
- const maskedDB = EM.slice(1 + hLen);
71
- const dbLen = keyBytes - hLen - 1;
72
- const seedMask = mgf1(hashAlgo, maskedDB, hLen);
73
- const seed = new Uint8Array(hLen);
74
- for (let i = 0; i < hLen; i++) seed[i] = maskedSeed[i] ^ seedMask[i];
75
- const dbMask = mgf1(hashAlgo, seed, dbLen);
76
- const DB = new Uint8Array(dbLen);
77
- for (let i = 0; i < dbLen; i++) DB[i] = maskedDB[i] ^ dbMask[i];
78
- const lHash = hashDigest(hashAlgo, label || new Uint8Array(0));
79
- const lHashPrime = DB.slice(0, hLen);
80
- let valid = Y === 0 ? 1 : 0;
81
- for (let i = 0; i < hLen; i++) {
82
- valid &= lHash[i] === lHashPrime[i] ? 1 : 0;
83
- }
84
- let sepIdx = -1;
85
- for (let i = hLen; i < dbLen; i++) {
86
- if (DB[i] === 1) {
87
- sepIdx = i;
88
- break;
89
- } else if (DB[i] !== 0) {
90
- valid = 0;
91
- break;
92
- }
93
- }
94
- if (sepIdx === -1) valid = 0;
95
- if (!valid) {
96
- throw new Error("RSA-OAEP: decryption error");
97
- }
98
- return DB.slice(sepIdx + 1);
99
- }
100
-
101
- //#endregion
102
- export { rsaOaepDecrypt, rsaOaepEncrypt };
1
+ import{parsePemKey as e,rsaKeySize as t}from"./asn1.js";import{bigIntToBytes as n,bytesToBigInt as r,modPow as i}from"./bigint-math.js";import{hashSize as a}from"./crypto-utils.js";import{randomBytes as o}from"./random.js";import{Hash as s}from"./hash.js";import{mgf1 as c}from"./mgf1.js";function l(e,t){let n=new s(e);return n.update(t),new Uint8Array(n.digest())}function u(s,u,d,f){let p=e(u),m,h;if(p.type===`rsa-public`)({n:m,e:h}=p.components);else if(p.type===`rsa-private`)({n:m,e:h}=p.components);else throw Error(`RSA-OAEP: expected RSA key`);let g=Math.ceil(t(m)/8),_=a(s);if(d.length>g-2*_-2)throw Error(`RSA-OAEP: message too long`);let v=l(s,f||new Uint8Array),y=g-_-1,b=new Uint8Array(y);b.set(v,0),b[y-d.length-1]=1,b.set(d,y-d.length);let x=new Uint8Array(o(_)),S=c(s,x,y),C=new Uint8Array(y);for(let e=0;e<y;e++)C[e]=b[e]^S[e];let w=c(s,C,_),T=new Uint8Array(_);for(let e=0;e<_;e++)T[e]=x[e]^w[e];let E=new Uint8Array(g);return E[0]=0,E.set(T,1),E.set(C,1+_),n(i(r(E),h,m),g)}function d(o,s,u,d){let f=e(s);if(f.type!==`rsa-private`)throw Error(`RSA-OAEP: expected RSA private key`);let{n:p,d:m}=f.components,h=Math.ceil(t(p)/8),g=a(o);if(u.length!==h||h<2*g+2)throw Error(`RSA-OAEP: decryption error`);let _=n(i(r(u),m,p),h),v=_[0],y=_.slice(1,1+g),b=_.slice(1+g),x=h-g-1,S=c(o,b,g),C=new Uint8Array(g);for(let e=0;e<g;e++)C[e]=y[e]^S[e];let w=c(o,C,x),T=new Uint8Array(x);for(let e=0;e<x;e++)T[e]=b[e]^w[e];let E=l(o,d||new Uint8Array),D=T.slice(0,g),O=+(v===0);for(let e=0;e<g;e++)O&=+(E[e]===D[e]);let k=-1;for(let e=g;e<x;e++)if(T[e]===1){k=e;break}else if(T[e]!==0){O=0;break}if(k===-1&&(O=0),!O)throw Error(`RSA-OAEP: decryption error`);return T.slice(k+1)}export{d as rsaOaepDecrypt,u as rsaOaepEncrypt};
@@ -1,107 +1 @@
1
- import { parsePemKey, rsaKeySize } from "./asn1.js";
2
- import { bigIntToBytes, bytesToBigInt, modPow } from "./bigint-math.js";
3
- import { hashSize } from "./crypto-utils.js";
4
- import { randomBytes } from "./random.js";
5
- import { Hash } from "./hash.js";
6
- import { mgf1 } from "./mgf1.js";
7
-
8
- //#region src/rsa-pss.ts
9
- function hashDigest(algo, data) {
10
- const h = new Hash(algo);
11
- h.update(data);
12
- return new Uint8Array(h.digest());
13
- }
14
- function emsaPssEncode(mHash, emBits, hashAlgo, saltLength) {
15
- const hLen = hashSize(hashAlgo);
16
- const emLen = Math.ceil(emBits / 8);
17
- if (emLen < hLen + saltLength + 2) {
18
- throw new Error("RSA-PSS: encoding error — key too short");
19
- }
20
- const salt = saltLength > 0 ? new Uint8Array(randomBytes(saltLength)) : new Uint8Array(0);
21
- const mPrime = new Uint8Array(8 + hLen + saltLength);
22
- mPrime.set(mHash, 8);
23
- mPrime.set(salt, 8 + hLen);
24
- const H = hashDigest(hashAlgo, mPrime);
25
- const dbLen = emLen - hLen - 1;
26
- const DB = new Uint8Array(dbLen);
27
- DB[dbLen - saltLength - 1] = 1;
28
- DB.set(salt, dbLen - saltLength);
29
- const dbMask = mgf1(hashAlgo, H, dbLen);
30
- const maskedDB = new Uint8Array(dbLen);
31
- for (let i = 0; i < dbLen; i++) maskedDB[i] = DB[i] ^ dbMask[i];
32
- const zeroBits = 8 * emLen - emBits;
33
- if (zeroBits > 0) maskedDB[0] &= 255 >>> zeroBits;
34
- const EM = new Uint8Array(emLen);
35
- EM.set(maskedDB, 0);
36
- EM.set(H, dbLen);
37
- EM[emLen - 1] = 188;
38
- return EM;
39
- }
40
- function emsaPssVerify(mHash, EM, emBits, hashAlgo, saltLength) {
41
- const hLen = hashSize(hashAlgo);
42
- const emLen = Math.ceil(emBits / 8);
43
- if (emLen < hLen + saltLength + 2) return false;
44
- if (EM[emLen - 1] !== 188) return false;
45
- const dbLen = emLen - hLen - 1;
46
- const maskedDB = EM.slice(0, dbLen);
47
- const H = EM.slice(dbLen, dbLen + hLen);
48
- const zeroBits = 8 * emLen - emBits;
49
- if (zeroBits > 0 && (maskedDB[0] & 255 << 8 - zeroBits) !== 0) return false;
50
- const dbMask = mgf1(hashAlgo, H, dbLen);
51
- const DB = new Uint8Array(dbLen);
52
- for (let i = 0; i < dbLen; i++) DB[i] = maskedDB[i] ^ dbMask[i];
53
- if (zeroBits > 0) DB[0] &= 255 >>> zeroBits;
54
- for (let i = 0; i < dbLen - saltLength - 1; i++) {
55
- if (DB[i] !== 0) return false;
56
- }
57
- if (DB[dbLen - saltLength - 1] !== 1) return false;
58
- const salt = DB.slice(dbLen - saltLength);
59
- const mPrime = new Uint8Array(8 + hLen + saltLength);
60
- mPrime.set(mHash, 8);
61
- mPrime.set(salt, 8 + hLen);
62
- const HPrime = hashDigest(hashAlgo, mPrime);
63
- if (H.length !== HPrime.length) return false;
64
- let diff = 0;
65
- for (let i = 0; i < H.length; i++) diff |= H[i] ^ HPrime[i];
66
- return diff === 0;
67
- }
68
- /**
69
- * RSA-PSS sign using PEM private key.
70
- */
71
- function rsaPssSign(hashAlgo, privKeyPem, data, saltLength) {
72
- const parsed = parsePemKey(privKeyPem);
73
- if (parsed.type !== "rsa-private") throw new Error("RSA-PSS: expected RSA private key");
74
- const { n, d } = parsed.components;
75
- const keyBits = rsaKeySize(n);
76
- const keyBytes = Math.ceil(keyBits / 8);
77
- const mHash = hashDigest(hashAlgo, data);
78
- const EM = emsaPssEncode(mHash, keyBits - 1, hashAlgo, saltLength);
79
- const m = bytesToBigInt(EM);
80
- const s = modPow(m, d, n);
81
- return bigIntToBytes(s, keyBytes);
82
- }
83
- /**
84
- * RSA-PSS verify using PEM public key.
85
- */
86
- function rsaPssVerify(hashAlgo, pubKeyPem, signature, data, saltLength) {
87
- const parsed = parsePemKey(pubKeyPem);
88
- let n, e;
89
- if (parsed.type === "rsa-public") {
90
- ({n, e} = parsed.components);
91
- } else if (parsed.type === "rsa-private") {
92
- ({n, e} = parsed.components);
93
- } else {
94
- throw new Error("RSA-PSS: expected RSA key");
95
- }
96
- const keyBits = rsaKeySize(n);
97
- const keyBytes = Math.ceil(keyBits / 8);
98
- if (signature.length !== keyBytes) return false;
99
- const s = bytesToBigInt(signature);
100
- const m = modPow(s, e, n);
101
- const EM = bigIntToBytes(m, Math.ceil((keyBits - 1) / 8));
102
- const mHash = hashDigest(hashAlgo, data);
103
- return emsaPssVerify(mHash, EM, keyBits - 1, hashAlgo, saltLength);
104
- }
105
-
106
- //#endregion
107
- export { rsaPssSign, rsaPssVerify };
1
+ import{parsePemKey as e,rsaKeySize as t}from"./asn1.js";import{bigIntToBytes as n,bytesToBigInt as r,modPow as i}from"./bigint-math.js";import{hashSize as a}from"./crypto-utils.js";import{randomBytes as o}from"./random.js";import{Hash as s}from"./hash.js";import{mgf1 as c}from"./mgf1.js";function l(e,t){let n=new s(e);return n.update(t),new Uint8Array(n.digest())}function u(e,t,n,r){let i=a(n),s=Math.ceil(t/8);if(s<i+r+2)throw Error(`RSA-PSS: encoding error — key too short`);let u=r>0?new Uint8Array(o(r)):new Uint8Array,d=new Uint8Array(8+i+r);d.set(e,8),d.set(u,8+i);let f=l(n,d),p=s-i-1,m=new Uint8Array(p);m[p-r-1]=1,m.set(u,p-r);let h=c(n,f,p),g=new Uint8Array(p);for(let e=0;e<p;e++)g[e]=m[e]^h[e];let _=8*s-t;_>0&&(g[0]&=255>>>_);let v=new Uint8Array(s);return v.set(g,0),v.set(f,p),v[s-1]=188,v}function d(e,t,n,r,i){let o=a(r),s=Math.ceil(n/8);if(s<o+i+2||t[s-1]!==188)return!1;let u=s-o-1,d=t.slice(0,u),f=t.slice(u,u+o),p=8*s-n;if(p>0&&d[0]&255<<8-p)return!1;let m=c(r,f,u),h=new Uint8Array(u);for(let e=0;e<u;e++)h[e]=d[e]^m[e];p>0&&(h[0]&=255>>>p);for(let e=0;e<u-i-1;e++)if(h[e]!==0)return!1;if(h[u-i-1]!==1)return!1;let g=h.slice(u-i),_=new Uint8Array(8+o+i);_.set(e,8),_.set(g,8+o);let v=l(r,_);if(f.length!==v.length)return!1;let y=0;for(let e=0;e<f.length;e++)y|=f[e]^v[e];return y===0}function f(a,o,s,c){let d=e(o);if(d.type!==`rsa-private`)throw Error(`RSA-PSS: expected RSA private key`);let{n:f,d:p}=d.components,m=t(f),h=Math.ceil(m/8);return n(i(r(u(l(a,s),m-1,a,c)),p,f),h)}function p(a,o,s,c,u){let f=e(o),p,m;if(f.type===`rsa-public`)({n:p,e:m}=f.components);else if(f.type===`rsa-private`)({n:p,e:m}=f.components);else throw Error(`RSA-PSS: expected RSA key`);let h=t(p),g=Math.ceil(h/8);if(s.length!==g)return!1;let _=n(i(r(s),m,p),Math.ceil((h-1)/8));return d(l(a,c),_,h-1,a,u)}export{f as rsaPssSign,p as rsaPssVerify};