rsa-aes-crypto 1.0.1
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/bin/index.js +142 -0
- package/package.json +11 -0
package/bin/index.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const publicKeyPath = path.join(__dirname, 'public.pem');
|
|
8
|
+
const privateKeyPath = path.join(__dirname, 'private.pem');
|
|
9
|
+
|
|
10
|
+
/** 生成 RSA 公钥/私钥 */
|
|
11
|
+
function generateKeys() {
|
|
12
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
|
|
13
|
+
modulusLength: 2048,
|
|
14
|
+
publicKeyEncoding: { type: 'pkcs1', format: 'pem' },
|
|
15
|
+
privateKeyEncoding: { type: 'pkcs1', format: 'pem' },
|
|
16
|
+
});
|
|
17
|
+
fs.writeFileSync(publicKeyPath, publicKey);
|
|
18
|
+
fs.writeFileSync(privateKeyPath, privateKey);
|
|
19
|
+
console.log('✅ RSA 公钥和私钥生成完成');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 加密文件(混合加密) */
|
|
23
|
+
function encryptFile(inputFile, outputFile) {
|
|
24
|
+
const publicKey = fs.readFileSync(publicKeyPath, 'utf8');
|
|
25
|
+
|
|
26
|
+
// 随机生成 AES key 和 IV
|
|
27
|
+
const aesKey = crypto.randomBytes(32); // AES-256
|
|
28
|
+
const iv = crypto.randomBytes(16);
|
|
29
|
+
|
|
30
|
+
// 用 AES 流加密文件
|
|
31
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, iv);
|
|
32
|
+
const input = fs.createReadStream(inputFile);
|
|
33
|
+
const output = fs.createWriteStream(outputFile);
|
|
34
|
+
|
|
35
|
+
// 用 RSA 加密 AES key + IV
|
|
36
|
+
const keyIvBuffer = Buffer.concat([aesKey, iv]); // 32 + 16 = 48 bytes
|
|
37
|
+
const encryptedKeyIv = crypto.publicEncrypt(publicKey, keyIvBuffer);
|
|
38
|
+
|
|
39
|
+
// 写入 RSA 加密的 key 长度 + 加密 key + AES 数据
|
|
40
|
+
const keyLengthBuffer = Buffer.alloc(4);
|
|
41
|
+
keyLengthBuffer.writeUInt32BE(encryptedKeyIv.length, 0);
|
|
42
|
+
output.write(keyLengthBuffer);
|
|
43
|
+
output.write(encryptedKeyIv);
|
|
44
|
+
|
|
45
|
+
input.pipe(cipher).pipe(output);
|
|
46
|
+
|
|
47
|
+
output.on('finish', () => console.log(`✅ 文件加密完成:${outputFile}`));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 解密文件(混合加密) */
|
|
51
|
+
function decryptFile(inputFile, outputFile) {
|
|
52
|
+
const privateKey = fs.readFileSync(privateKeyPath, 'utf8');
|
|
53
|
+
const input = fs.createReadStream(inputFile);
|
|
54
|
+
|
|
55
|
+
let headerRead = false;
|
|
56
|
+
let encryptedKeyIvLength = 0;
|
|
57
|
+
let encryptedKeyIv = Buffer.alloc(0);
|
|
58
|
+
let remainingBuffers = [];
|
|
59
|
+
|
|
60
|
+
input.on('readable', () => {
|
|
61
|
+
let chunk;
|
|
62
|
+
while ((chunk = input.read()) !== null) {
|
|
63
|
+
if (!headerRead) {
|
|
64
|
+
remainingBuffers.push(chunk);
|
|
65
|
+
const bufferConcat = Buffer.concat(remainingBuffers);
|
|
66
|
+
if (bufferConcat.length >= 4) {
|
|
67
|
+
encryptedKeyIvLength = bufferConcat.readUInt32BE(0);
|
|
68
|
+
if (bufferConcat.length >= 4 + encryptedKeyIvLength) {
|
|
69
|
+
encryptedKeyIv = bufferConcat.slice(
|
|
70
|
+
4,
|
|
71
|
+
4 + encryptedKeyIvLength,
|
|
72
|
+
);
|
|
73
|
+
const aesDataStart = 4 + encryptedKeyIvLength;
|
|
74
|
+
const aesData = bufferConcat.slice(aesDataStart);
|
|
75
|
+
|
|
76
|
+
// 解密 AES key + IV
|
|
77
|
+
const keyIvBuffer = crypto.privateDecrypt(
|
|
78
|
+
privateKey,
|
|
79
|
+
encryptedKeyIv,
|
|
80
|
+
);
|
|
81
|
+
const aesKey = keyIvBuffer.slice(0, 32);
|
|
82
|
+
const iv = keyIvBuffer.slice(32, 48);
|
|
83
|
+
|
|
84
|
+
// AES 解密流
|
|
85
|
+
const decipher = crypto.createDecipheriv(
|
|
86
|
+
'aes-256-cbc',
|
|
87
|
+
aesKey,
|
|
88
|
+
iv,
|
|
89
|
+
);
|
|
90
|
+
const output = fs.createWriteStream(outputFile);
|
|
91
|
+
|
|
92
|
+
// 把已经读到的 AES 数据先解密
|
|
93
|
+
const readable = crypto.Readable.from(aesData);
|
|
94
|
+
readable.pipe(decipher).pipe(output);
|
|
95
|
+
|
|
96
|
+
// 之后剩余的 input 数据直接解密
|
|
97
|
+
input.pipe(decipher);
|
|
98
|
+
|
|
99
|
+
output.on('finish', () =>
|
|
100
|
+
console.log(`✅ 文件解密完成:${outputFile}`),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
headerRead = true;
|
|
104
|
+
remainingBuffers = null;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// CLI
|
|
114
|
+
const args = process.argv.slice(2);
|
|
115
|
+
if (args[0] === 'genkey') {
|
|
116
|
+
generateKeys();
|
|
117
|
+
} else if (args[0] === 'encrypt') {
|
|
118
|
+
const [_, inputFile, outputFile] = args;
|
|
119
|
+
if (!inputFile || !outputFile) {
|
|
120
|
+
console.log(
|
|
121
|
+
'用法: node rsa_aes_file_crypto.js encrypt <输入文件> <输出文件>',
|
|
122
|
+
);
|
|
123
|
+
} else {
|
|
124
|
+
encryptFile(inputFile, outputFile);
|
|
125
|
+
}
|
|
126
|
+
} else if (args[0] === 'decrypt') {
|
|
127
|
+
const [_, inputFile, outputFile] = args;
|
|
128
|
+
if (!inputFile || !outputFile) {
|
|
129
|
+
console.log(
|
|
130
|
+
'用法: node rsa_aes_file_crypto.js decrypt <输入文件> <输出文件>',
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
decryptFile(inputFile, outputFile);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
console.log(`
|
|
137
|
+
用法:
|
|
138
|
+
node rsa_aes_file_crypto.js genkey 生成公钥/私钥
|
|
139
|
+
node rsa_aes_file_crypto.js encrypt <in> <out> 加密文件
|
|
140
|
+
node rsa_aes_file_crypto.js decrypt <in> <out> 解密文件
|
|
141
|
+
`);
|
|
142
|
+
}
|