rn-pdf-decrypt 1.0.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.
@@ -0,0 +1,183 @@
1
+ /**
2
+ * rn-pdf-decrypt - RC4 cryptographic utilities
3
+ * React Native compatible fork of @pdfsmaller/pdf-decrypt
4
+ *
5
+ * @author imdewan (https://github.com/imdewan/rn-pdf-decrypt)
6
+ * @license MIT
7
+ * @see https://github.com/imdewan/rn-pdf-decrypt
8
+ *
9
+ * This minimal cryptographic implementation was built to solve the "impossible"
10
+ * problem of real PDF encryption within Cloudflare Workers' 1MB limit.
11
+ * Total size: ~7KB for complete PDF encryption!
12
+ */
13
+
14
+ // Minimal cryptographic functions for PDF encryption
15
+ // Implements only what's needed for PDF Standard Security Handler
16
+
17
+ /**
18
+ * Minimal MD5 implementation
19
+ * Based on the MD5 algorithm - only what's needed for PDF encryption
20
+ * Part of rn-pdf-decrypt
21
+ */
22
+ export function md5(data) {
23
+ const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
24
+
25
+ // Initialize MD5 constants
26
+ const S = [
27
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
28
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
29
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
30
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
31
+ ];
32
+
33
+ const K = new Uint32Array([
34
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
35
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
36
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
37
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
38
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
39
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
40
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
41
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
42
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
43
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
44
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
45
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
46
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
47
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
48
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
49
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
50
+ ]);
51
+
52
+ // Initialize hash values
53
+ let a0 = 0x67452301;
54
+ let b0 = 0xefcdab89;
55
+ let c0 = 0x98badcfe;
56
+ let d0 = 0x10325476;
57
+
58
+ // Pre-processing
59
+ const msgLen = bytes.length;
60
+ const msgBitLen = msgLen * 8;
61
+ const msgLenPadded = ((msgLen + 9 + 63) & ~63);
62
+ const msg = new Uint8Array(msgLenPadded);
63
+ msg.set(bytes);
64
+ msg[msgLen] = 0x80;
65
+
66
+ // Append length in bits
67
+ const dataView = new DataView(msg.buffer);
68
+ dataView.setUint32(msgLenPadded - 8, msgBitLen, true);
69
+ dataView.setUint32(msgLenPadded - 4, 0, true);
70
+
71
+ // Process message in 512-bit chunks
72
+ for (let offset = 0; offset < msgLenPadded; offset += 64) {
73
+ const chunk = new Uint32Array(msg.buffer, offset, 16);
74
+
75
+ let a = a0, b = b0, c = c0, d = d0;
76
+
77
+ for (let i = 0; i < 64; i++) {
78
+ let f, g;
79
+
80
+ if (i < 16) {
81
+ f = (b & c) | ((~b) & d);
82
+ g = i;
83
+ } else if (i < 32) {
84
+ f = (d & b) | ((~d) & c);
85
+ g = (5 * i + 1) % 16;
86
+ } else if (i < 48) {
87
+ f = b ^ c ^ d;
88
+ g = (3 * i + 5) % 16;
89
+ } else {
90
+ f = c ^ (b | (~d));
91
+ g = (7 * i) % 16;
92
+ }
93
+
94
+ f = (f + a + K[i] + chunk[g]) >>> 0;
95
+ a = d;
96
+ d = c;
97
+ c = b;
98
+ b = (b + ((f << S[i]) | (f >>> (32 - S[i])))) >>> 0;
99
+ }
100
+
101
+ a0 = (a0 + a) >>> 0;
102
+ b0 = (b0 + b) >>> 0;
103
+ c0 = (c0 + c) >>> 0;
104
+ d0 = (d0 + d) >>> 0;
105
+ }
106
+
107
+ // Produce the final hash value
108
+ const result = new Uint8Array(16);
109
+ const view = new DataView(result.buffer);
110
+ view.setUint32(0, a0, true);
111
+ view.setUint32(4, b0, true);
112
+ view.setUint32(8, c0, true);
113
+ view.setUint32(12, d0, true);
114
+
115
+ return result;
116
+ }
117
+
118
+ /**
119
+ * RC4 encryption/decryption
120
+ * RC4 is symmetric, so encryption and decryption are the same operation
121
+ * Part of rn-pdf-decrypt
122
+ */
123
+ export class RC4 {
124
+ constructor(key) {
125
+ this.s = new Uint8Array(256);
126
+ this.i = 0;
127
+ this.j = 0;
128
+
129
+ // Key scheduling algorithm (KSA)
130
+ for (let i = 0; i < 256; i++) {
131
+ this.s[i] = i;
132
+ }
133
+
134
+ let j = 0;
135
+ for (let i = 0; i < 256; i++) {
136
+ j = (j + this.s[i] + key[i % key.length]) & 0xFF;
137
+ // Swap
138
+ [this.s[i], this.s[j]] = [this.s[j], this.s[i]];
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Encrypt/decrypt data
144
+ * @param {Uint8Array} data - Data to encrypt or decrypt
145
+ * @returns {Uint8Array} - Encrypted/decrypted data
146
+ */
147
+ process(data) {
148
+ const result = new Uint8Array(data.length);
149
+
150
+ for (let k = 0; k < data.length; k++) {
151
+ this.i = (this.i + 1) & 0xFF;
152
+ this.j = (this.j + this.s[this.i]) & 0xFF;
153
+
154
+ // Swap
155
+ [this.s[this.i], this.s[this.j]] = [this.s[this.j], this.s[this.i]];
156
+
157
+ const t = (this.s[this.i] + this.s[this.j]) & 0xFF;
158
+ result[k] = data[k] ^ this.s[t];
159
+ }
160
+
161
+ return result;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Convert hex string to Uint8Array
167
+ */
168
+ export function hexToBytes(hex) {
169
+ const bytes = new Uint8Array(hex.length / 2);
170
+ for (let i = 0; i < bytes.length; i++) {
171
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
172
+ }
173
+ return bytes;
174
+ }
175
+
176
+ /**
177
+ * Convert Uint8Array to hex string
178
+ */
179
+ export function bytesToHex(bytes) {
180
+ return Array.from(bytes)
181
+ .map(b => b.toString(16).padStart(2, '0'))
182
+ .join('');
183
+ }
@@ -0,0 +1,33 @@
1
+ export declare function decryptPDF(
2
+ pdfBytes: Uint8Array,
3
+ password: string
4
+ ): Promise<Uint8Array>;
5
+
6
+ export declare function isEncrypted(
7
+ pdfBytes: Uint8Array
8
+ ): Promise<{
9
+ encrypted: boolean;
10
+ algorithm?: 'AES-256' | 'RC4';
11
+ version?: number;
12
+ revision?: number;
13
+ keyLength?: number;
14
+ }>;
15
+
16
+ export declare function md5(data: Uint8Array | string): Uint8Array;
17
+ export declare class RC4 {
18
+ constructor(key: Uint8Array);
19
+ process(data: Uint8Array): Uint8Array;
20
+ }
21
+ export declare function hexToBytes(hex: string): Uint8Array;
22
+ export declare function bytesToHex(bytes: Uint8Array): string;
23
+
24
+ export declare function sha256(data: Uint8Array): Promise<Uint8Array>;
25
+ export declare function sha384(data: Uint8Array): Promise<Uint8Array>;
26
+ export declare function sha512(data: Uint8Array): Promise<Uint8Array>;
27
+ export declare function aes256CbcDecrypt(data: Uint8Array, key: Uint8Array, iv: Uint8Array): Promise<Uint8Array>;
28
+ export declare function aes256CbcDecryptNoPad(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Promise<Uint8Array>;
29
+ export declare function aes256EcbDecryptBlock(block: Uint8Array, key: Uint8Array): Promise<Uint8Array>;
30
+ export declare function importAES256DecryptKey(key: Uint8Array): Promise<Uint8Array>;
31
+ export declare function aes256CbcDecryptWithKey(data: Uint8Array, key: Uint8Array, iv: Uint8Array): Promise<Uint8Array>;
32
+ export declare function computeHash2B(password: Uint8Array, salt: Uint8Array, userKey: Uint8Array): Promise<Uint8Array>;
33
+ export declare function concat(...arrays: Uint8Array[]): Uint8Array;
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ const { decryptPDF, isEncrypted } = require('./pdf-decrypt.js');
2
+ const { md5, RC4, hexToBytes, bytesToHex } = require('./crypto-rc4.js');
3
+ const { sha256, sha384, sha512, aes256CbcDecrypt, aes256CbcDecryptNoPad, aes256EcbDecryptBlock, importAES256DecryptKey, aes256CbcDecryptWithKey, computeHash2B, concat } = require('./crypto-aes.js');
4
+
5
+ module.exports = { decryptPDF, isEncrypted, md5, RC4, hexToBytes, bytesToHex, sha256, sha384, sha512, aes256CbcDecrypt, aes256CbcDecryptNoPad, aes256EcbDecryptBlock, importAES256DecryptKey, aes256CbcDecryptWithKey, computeHash2B, concat };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ export { decryptPDF, isEncrypted } from './pdf-decrypt.mjs';
2
+ export { md5, RC4, hexToBytes, bytesToHex } from './crypto-rc4.mjs';
3
+ export { sha256, sha384, sha512, aes256CbcDecrypt, aes256CbcDecryptNoPad, aes256EcbDecryptBlock, importAES256DecryptKey, aes256CbcDecryptWithKey, computeHash2B, concat } from './crypto-aes.mjs';