-
Notifications
You must be signed in to change notification settings - Fork 1
/
decrypt.js
140 lines (128 loc) · 4.12 KB
/
decrypt.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const openpgp = require('./initOpenpgp');
const fs = require('fs');
const process = require('process');
const utils = require('./utils');
const CANNOT_DECRYPT = 29;
const BAD_DATA = 41;
const KEY_IS_PROTECTED = 67;
const decrypt = async (withPassword, sessionKeyOut, withSessionKey, verifyWith, verificationsOut, keyfiles, withKeyPassword) => {
const encrypted = await utils.read_stdin();
let message;
try {
message = await openpgp.readMessage({ binaryMessage: encrypted });
} catch (e) {
try {
message = await openpgp.readMessage({ armoredMessage: encrypted.toString('utf8') });
} catch (e) {
console.error(e.message);
return process.exit(BAD_DATA);
}
}
if (!withPassword && !withSessionKey && !keyfiles.length) {
throw new Error('MISSING_ARG');
}
if (withPassword) {
const password = fs.readFileSync(withPassword);
const options = {
message: message,
passwords: password
};
openpgp.decrypt(options).then((clearText) => {
process.stdout.write(clearText.data);
}).catch((e) => {
console.error(e.message);
return process.exit(CANNOT_DECRYPT);
});
return;
}
if (withSessionKey) {
const sessionKeyEncoded = fs.readFileSync(withSessionKey, 'utf8');
const [algo, data] = sessionKeyEncoded.split(':');
const sessionKey = {
data: Buffer.from(data, 'hex'),
algorithm: openpgp.enums.read(openpgp.enums.symmetric, +algo)
};
const options = {
message: message,
sessionKeys: sessionKey
};
openpgp.decrypt(options).then(async (clearText) => {
process.stdout.write(clearText.data);
}).catch((e) => {
console.error(e.message);
return process.exit(CANNOT_DECRYPT);
});
return;
}
let decryptionKeys = await utils.load_keys(...keyfiles);
if (withKeyPassword) {
const keyPassword = fs.readFileSync(withKeyPassword, 'utf8');
decryptionKeys = await Promise.all(decryptionKeys.map(privateKey => openpgp.decryptKey({
privateKey,
passphrase: [keyPassword, keyPassword.trimEnd()]
}))).catch((e) => {
// TODO: Only error on key decryption failure if we can't decrypt
// the message with another key (or password or session key).
console.error(e.message);
process.exit(KEY_IS_PROTECTED);
});
}
const decryptedSessionKeys = await openpgp.decryptSessionKeys({
message,
decryptionKeys
}).catch((e) => {
console.error(e.message);
process.exit(CANNOT_DECRYPT);
});
const options = {
message,
sessionKeys: decryptedSessionKeys
};
let verificationKeys;
if (verifyWith.length) {
verificationKeys = await utils.load_certs(...verifyWith);
options.verificationKeys = verificationKeys;
}
openpgp.decrypt(options).then(async (clearText) => {
process.stdout.write(clearText.data);
if (verificationsOut) {
let verifications = '';
for (const s of clearText.signatures) {
let verified;
try {
verified = await s.verified;
} catch (e) {
console.error(e.message);
verified = false;
}
if (verified) {
const signature = await s.signature;
const timestamp = utils.format_date(signature.packets[0].created);
for (const cert of verificationKeys) {
const signKey = await cert.getSigningKey(s.keyID, null).catch(() => null);
if (signKey) {
verifications +=
timestamp
+ ' ' + signKey.getFingerprint().toUpperCase()
+ ' ' + cert.getFingerprint().toUpperCase()
+ '\n';
break;
}
}
}
}
fs.writeFileSync(verificationsOut, verifications);
}
if (sessionKeyOut) {
const { algorithm, data } = decryptedSessionKeys[0];
const sessionKeyEncoded =
openpgp.enums.write(openpgp.enums.symmetric, algorithm) +
':' + Buffer.from(data).toString('hex').toUpperCase();
fs.writeFileSync(sessionKeyOut, sessionKeyEncoded);
}
}).catch((e) => {
console.error(e.message);
process.exit(CANNOT_DECRYPT);
});
};
module.exports = decrypt;