@sendsafely/sendsafely 2.0.1 → 2.0.3
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/FileUtil.js +38 -47
- package/lib/SendSafely.js +3 -1
- package/lib/keyGeneratorWorker.js +158 -130
- package/lib/uploadWorker.js +101 -96
- package/package.json +2 -2
package/lib/FileUtil.js
CHANGED
|
@@ -23,13 +23,9 @@ function FileUtil(param) {
|
|
|
23
23
|
this.SEGMENT_SIZE = 2621440;
|
|
24
24
|
this.filePath = param.filePath;
|
|
25
25
|
this.callback = param.callback;
|
|
26
|
-
this.file = {size: 0, name: '', totalParts: 0};
|
|
27
|
-
this.readableStream = fs.createReadStream(myself.filePath);
|
|
28
|
-
this.reading = false;
|
|
29
26
|
this.eof = false;
|
|
30
27
|
this.data = [];
|
|
31
28
|
this.tempSize = 0;
|
|
32
|
-
this.part = 1;
|
|
33
29
|
|
|
34
30
|
this.init = function() {
|
|
35
31
|
return new Promise(function(resolve) {
|
|
@@ -37,20 +33,9 @@ function FileUtil(param) {
|
|
|
37
33
|
if (err) {
|
|
38
34
|
throw new Error('FileUtil: File does not exist, ' + myself.filePath);
|
|
39
35
|
} else {
|
|
40
|
-
myself.
|
|
41
|
-
myself.
|
|
42
|
-
|
|
43
|
-
if(myself.file.size > (myself.SEGMENT_SIZE/4)) {
|
|
44
|
-
myself.file.totalParts = 1 + Math.ceil((myself.file.size-(myself.SEGMENT_SIZE/4))/myself.SEGMENT_SIZE);
|
|
45
|
-
} else {
|
|
46
|
-
myself.file.totalParts = 1;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
resolve(myself.file);
|
|
50
|
-
|
|
51
|
-
myself.readableStream.on('readable', function() {
|
|
52
|
-
// keep reading chunk until it reaches SEGMENT_SIZE
|
|
53
|
-
if(myself.reading && !myself.eof) {
|
|
36
|
+
myself.readableStream = fs.createReadStream(myself.filePath);
|
|
37
|
+
myself.readableStream.on('readable', function () {
|
|
38
|
+
if (myself.waitingForRead) {
|
|
54
39
|
processChunk();
|
|
55
40
|
}
|
|
56
41
|
});
|
|
@@ -58,15 +43,19 @@ function FileUtil(param) {
|
|
|
58
43
|
myself.readableStream.on('end', function() {
|
|
59
44
|
// done reading file
|
|
60
45
|
myself.eof = true;
|
|
61
|
-
if(myself.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// increment extra part if file size is less than segment/4
|
|
65
|
-
// so that we callback with an empty array
|
|
66
|
-
myself.part++;
|
|
67
|
-
callback(false);
|
|
46
|
+
if (myself.waitingForRead) {
|
|
47
|
+
// Handle timing edge case where 'end' fires while a read is pending
|
|
48
|
+
processChunk();
|
|
68
49
|
}
|
|
69
50
|
});
|
|
51
|
+
|
|
52
|
+
const totalParts = stats.size === 0 ? 1 : Math.ceil(stats.size / myself.SEGMENT_SIZE);
|
|
53
|
+
|
|
54
|
+
resolve({
|
|
55
|
+
name: path.basename(myself.filePath),
|
|
56
|
+
size: stats.size,
|
|
57
|
+
totalParts: totalParts,
|
|
58
|
+
});
|
|
70
59
|
}
|
|
71
60
|
});
|
|
72
61
|
|
|
@@ -74,34 +63,36 @@ function FileUtil(param) {
|
|
|
74
63
|
}
|
|
75
64
|
|
|
76
65
|
this.read = function() {
|
|
77
|
-
if(
|
|
78
|
-
|
|
79
|
-
processChunk();
|
|
80
|
-
} else if(myself.part === myself.file.totalParts) {
|
|
81
|
-
//extra part padding with empty array if file size is less than segment/4
|
|
82
|
-
callback(true);
|
|
66
|
+
if (myself.eof && myself.tempSize === 0) {
|
|
67
|
+
return;
|
|
83
68
|
}
|
|
69
|
+
|
|
70
|
+
myself.waitingForRead = true;
|
|
71
|
+
processChunk();
|
|
84
72
|
}
|
|
85
73
|
|
|
86
74
|
function processChunk() {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
} else {
|
|
92
|
-
let chunk = myself.readableStream.read();
|
|
93
|
-
if(chunk !== null) {
|
|
94
|
-
myself.data.push(new Uint8Array(chunk));
|
|
95
|
-
myself.tempSize += chunk.length;
|
|
96
|
-
}
|
|
75
|
+
let chunk;
|
|
76
|
+
while ((chunk = myself.readableStream.read()) !== null) { // Completely drain the stream's internal buffer
|
|
77
|
+
myself.data.push(new Uint8Array(chunk));
|
|
78
|
+
myself.tempSize += chunk.length;
|
|
97
79
|
}
|
|
98
|
-
}
|
|
99
80
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
81
|
+
if (myself.tempSize >= myself.SEGMENT_SIZE || myself.eof) {
|
|
82
|
+
if (myself.tempSize > 0) {
|
|
83
|
+
// We have a full segment
|
|
84
|
+
const buf = concatenate(myself.data);
|
|
85
|
+
const seg = buf.slice(0, myself.SEGMENT_SIZE);
|
|
86
|
+
const remainder = buf.slice(myself.SEGMENT_SIZE);
|
|
87
|
+
myself.data = remainder.length > 0 ? [remainder] : [];
|
|
88
|
+
myself.tempSize = remainder.length;
|
|
89
|
+
myself.callback({data: seg, complete: myself.eof && myself.tempSize === 0});
|
|
90
|
+
} else {
|
|
91
|
+
// Emit an empty final segment to signal completion & handles empty files
|
|
92
|
+
myself.callback({data: new Uint8Array(0), complete: true});
|
|
93
|
+
}
|
|
94
|
+
myself.waitingForRead = false;
|
|
95
|
+
}
|
|
105
96
|
}
|
|
106
97
|
|
|
107
98
|
function concatenate(arrays) {
|
package/lib/SendSafely.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const URL = require('url').URL;
|
|
2
|
+
const { ReadableStream, WritableStream, TransformStream } = require('stream/web');
|
|
3
|
+
Object.assign(globalThis, {ReadableStream, WritableStream, TransformStream});
|
|
2
4
|
const Window = require('./window');
|
|
3
5
|
const window = new Window();
|
|
4
6
|
const self = window;
|
|
@@ -3941,7 +3943,7 @@ function GenerateKeyPair(eventHandler) {
|
|
|
3941
3943
|
}
|
|
3942
3944
|
|
|
3943
3945
|
function buildNameStr() {
|
|
3944
|
-
return
|
|
3946
|
+
return myself.NAME + ' <' + myself.EMAIL + '>';
|
|
3945
3947
|
}
|
|
3946
3948
|
|
|
3947
3949
|
}
|
|
@@ -1,47 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
try {
|
|
2
|
+
if (window === undefined) {
|
|
3
|
+
window = globalThis;
|
|
4
|
+
}
|
|
5
|
+
} catch (err) {
|
|
2
6
|
window = {};
|
|
3
7
|
}
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
getRandomValues: function (buf) {
|
|
7
|
-
for(var i = 0; i<buf.length; i++)
|
|
8
|
-
{
|
|
9
|
-
if((self.randomCounter%20) === 0) {
|
|
10
|
-
reportProgress(self.randomCounter);
|
|
11
|
-
}
|
|
12
|
-
if((self.randomCounter % 512) === 0)
|
|
13
|
-
{
|
|
14
|
-
self.send({'cmd': 'randBuff', 'bytes': 64});
|
|
15
|
-
}
|
|
16
|
-
buf[i] = self.randomness[self.randomCounter++].charCodeAt();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
self.randomCounter = 0;
|
|
22
|
-
|
|
23
|
-
self.addEventListener('message', async function(e) {
|
|
9
|
+
self.addEventListener('message', function(e) {
|
|
24
10
|
var data = e.data;
|
|
25
11
|
switch (data.cmd) {
|
|
26
12
|
case 'generate_key':
|
|
27
13
|
debug("Starting to generate key..");
|
|
28
|
-
self.randomCounter = 0;
|
|
29
|
-
self.randomness = data.randomness;
|
|
30
14
|
|
|
31
|
-
var bits = data.bits;
|
|
32
15
|
var userStr = data.userStr;
|
|
16
|
+
var splitUserStr = userStr.split('<');
|
|
17
|
+
var userObj = {};
|
|
18
|
+
if (splitUserStr.length > 1) {
|
|
19
|
+
var name = splitUserStr[0].substring(0, splitUserStr[0].length-1);
|
|
20
|
+
var email = splitUserStr[1].substring(0, splitUserStr[1].length-1);
|
|
21
|
+
userObj = {
|
|
22
|
+
email: email,
|
|
23
|
+
name: name
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var options = {};
|
|
28
|
+
options.rsaBits = 2048;
|
|
29
|
+
options.type = 'rsa';
|
|
30
|
+
options.userIDs = [userObj];
|
|
31
|
+
options.format = 'armored';
|
|
32
|
+
options.config = {showComment: true, showVersion: true};
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
var options =
|
|
36
|
-
{
|
|
37
|
-
userIds: [userStr], // multiple user IDs
|
|
38
|
-
numBits: 2048
|
|
39
|
-
};
|
|
40
|
-
|
|
41
34
|
openpgp.generateKey(options).then(function(key) {
|
|
42
|
-
|
|
43
|
-
var
|
|
44
|
-
|
|
35
|
+
debug("Generated key!");
|
|
36
|
+
var privateKey = key.privateKey;
|
|
37
|
+
var publicKey = key.publicKey;
|
|
45
38
|
self.send({'cmd': 'key_generated', 'privateKey': privateKey, 'publicKey': publicKey});
|
|
46
39
|
}, function(err) {
|
|
47
40
|
debug("An Unknown Error Occurred While Generating the key");
|
|
@@ -49,66 +42,119 @@ self.addEventListener('message', async function(e) {
|
|
|
49
42
|
});
|
|
50
43
|
break;
|
|
51
44
|
case 'convert_key':
|
|
52
|
-
self.randomCounter = 0;
|
|
53
|
-
self.randomness = data.randomness;
|
|
54
45
|
var result = convertRawKey(data.rsaKeys, data.userStr);
|
|
55
46
|
self.send({'cmd': 'key_converted', 'privateKey': result.privateKeyArmored, 'publicKey': result.publicKeyArmored});
|
|
56
47
|
break;
|
|
57
48
|
case 'encrypt_keycode':
|
|
58
|
-
self.randomCounter = 0;
|
|
59
|
-
self.randomness = data.randomness;
|
|
60
|
-
|
|
61
49
|
debug(data.publicKey);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
50
|
+
// Read in armored keys
|
|
51
|
+
openpgp.readKeys({"armoredKeys": data.publicKey})
|
|
52
|
+
.then(function(publicKeys) {
|
|
53
|
+
if(publicKeys.length > 0) {
|
|
54
|
+
// Create open PGP message
|
|
55
|
+
openpgp.createMessage({"text": data.keyCode})
|
|
56
|
+
.then(function(message) {
|
|
57
|
+
var options = {
|
|
58
|
+
message,
|
|
59
|
+
encryptionKeys: publicKeys,
|
|
60
|
+
config: {
|
|
61
|
+
s2kIterationCountByte: 96,
|
|
62
|
+
allowMissingKeyFlags: true
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Encrypt open PGP message
|
|
67
|
+
openpgp.encrypt(options)
|
|
68
|
+
.then(function(encryptedMessage) {
|
|
69
|
+
self.send({'cmd': 'keycode_encrypted', 'encryptedKeyCode': encryptedMessage});
|
|
70
|
+
}, function(err) {
|
|
71
|
+
debug('ERROR');
|
|
72
|
+
debug(err);
|
|
73
|
+
sendError(err);
|
|
74
|
+
});
|
|
75
|
+
}, function(err) {
|
|
76
|
+
debug('ERROR');
|
|
77
|
+
debug(err);
|
|
78
|
+
sendError(err);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}, function(err) {
|
|
82
|
+
console.error(err);
|
|
83
|
+
sendError(err);
|
|
84
|
+
});
|
|
79
85
|
break;
|
|
80
86
|
case 'decrypt_keycode':
|
|
81
|
-
|
|
82
|
-
self.randomCounter = 0;
|
|
83
|
-
self.randomness = data.randomness;
|
|
84
|
-
var privKeys = await openpgp.key.readArmored(data.privateKey);
|
|
85
|
-
privKey = privKeys.keys[0];
|
|
86
|
-
var message = await openpgp.message.readArmored(data.keyCode);
|
|
87
|
-
|
|
88
|
-
options =
|
|
89
|
-
{
|
|
90
|
-
message: message, // parse armored message
|
|
91
|
-
privateKeys: [privKey] // for decryption
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
openpgp.decrypt(options).then(function(plaintext) {
|
|
95
|
-
self.send({'cmd': 'keycode_decrypted', 'decryptedKeycode': plaintext.data});
|
|
96
|
-
}, function(err) {
|
|
97
|
-
debug('ERROR');
|
|
98
|
-
debug(err);
|
|
99
|
-
sendError(err);
|
|
100
|
-
});
|
|
101
|
-
} catch (err) {
|
|
102
|
-
sendError(err);
|
|
103
|
-
}
|
|
87
|
+
decryptKeycode(data.privateKey, data.keyCode, 0);
|
|
104
88
|
break;
|
|
105
|
-
case 'randBuff':
|
|
106
|
-
self.randomness += data.randomness;
|
|
107
89
|
default:
|
|
108
90
|
;
|
|
109
91
|
};
|
|
110
92
|
}, false);
|
|
111
93
|
|
|
94
|
+
function decryptKeycode(privateKey, keyCode, failback) {
|
|
95
|
+
// read in armored private key
|
|
96
|
+
openpgp.readKeys({"armoredKeys": privateKey}).then(function (privateKeys) {
|
|
97
|
+
if (privateKeys != undefined && privateKeys.length > 0) {
|
|
98
|
+
// Read encrypted message from key code
|
|
99
|
+
openpgp.readMessage({"armoredMessage": keyCode}).then(async function (encryptedMessage) {
|
|
100
|
+
let options = {
|
|
101
|
+
message: encryptedMessage,
|
|
102
|
+
decryptionKeys: privateKeys
|
|
103
|
+
}
|
|
104
|
+
if (failback === 1) {
|
|
105
|
+
options.config = {
|
|
106
|
+
allowInsecureDecryptionWithSigningKeys: true
|
|
107
|
+
}
|
|
108
|
+
} else if (failback === 2) {
|
|
109
|
+
options.config = {
|
|
110
|
+
allowInsecureDecryptionWithSigningKeys: true,
|
|
111
|
+
allowUnauthenticatedMessages: true
|
|
112
|
+
}
|
|
113
|
+
} else if (failback === 3) {
|
|
114
|
+
options.config = {
|
|
115
|
+
allowMissingKeyFlags: true
|
|
116
|
+
}
|
|
117
|
+
} else if (failback === 4) {
|
|
118
|
+
options.config = {
|
|
119
|
+
allowInsecureDecryptionWithSigningKeys: true,
|
|
120
|
+
allowUnauthenticatedMessages: true,
|
|
121
|
+
allowMissingKeyFlags: true
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
let {data: decrypted} = await openpgp.decrypt(options);
|
|
126
|
+
self.send({'cmd': 'keycode_decrypted', 'decryptedKeycode': decrypted});
|
|
127
|
+
} catch (e) {
|
|
128
|
+
if (e.message === 'Error decrypting message: No decryption key packets found') {
|
|
129
|
+
// this might be a keycode encrypted with our old Java or .NET API that was incorrectly encrypting keycodes with the signing key
|
|
130
|
+
// update the config to bypass this and try again.
|
|
131
|
+
decryptKeycode(privateKey, keyCode, 1)
|
|
132
|
+
} else if (e.message === 'Error decrypting message: Message is not authenticated.' && failback !== 3) {
|
|
133
|
+
// this might be a keycode encrypted with our old Java API that wasn't setting setWithIntegrity = true.
|
|
134
|
+
// update the config to bypass this and try again.
|
|
135
|
+
decryptKeycode(privateKey, keyCode, 2)
|
|
136
|
+
} else if (e.message === 'Error decrypting message: None of the key flags is set: consider passing `config.allowMissingKeyFlags`') {
|
|
137
|
+
// this might be a keycode encrypted with an incorrectly formatted SCEAR key
|
|
138
|
+
// update the config to bypass this and try again.
|
|
139
|
+
decryptKeycode(privateKey, keyCode, 3)
|
|
140
|
+
} else if (e.message === 'Error decrypting message: Message is not authenticated.' && failback === 3) {
|
|
141
|
+
// this might be a keycode encrypted with our old Java API that wasn't setting setWithIntegrity = true,
|
|
142
|
+
// and the keycode was encrypted with an incorrectly formatted SCEAR key
|
|
143
|
+
// update the config to bypass this and try again.
|
|
144
|
+
decryptKeycode(privateKey, keyCode, 4)
|
|
145
|
+
} else {
|
|
146
|
+
// something else is the issue so log it
|
|
147
|
+
debug('ERROR');
|
|
148
|
+
debug(e);
|
|
149
|
+
console.log(e);
|
|
150
|
+
sendError(e);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
112
158
|
function convertRawKey(rsaKeys, userStr) {
|
|
113
159
|
|
|
114
160
|
var secretKey = createSecretKey(rsaKeys.privateKey);
|
|
@@ -125,33 +171,33 @@ function convertRawKey(rsaKeys, userStr) {
|
|
|
125
171
|
|
|
126
172
|
function wrapKeyObject(userId, secretKeyPacket, secretSubkeyPacket)
|
|
127
173
|
{
|
|
128
|
-
packetlist = new
|
|
174
|
+
var packetlist = new openpgp.PacketList();
|
|
129
175
|
|
|
130
|
-
userIdPacket = new
|
|
176
|
+
var userIdPacket = new openpgp.UserIDPacket();
|
|
131
177
|
userIdPacket.read(userId);
|
|
132
178
|
|
|
133
179
|
dataToSign = {};
|
|
134
180
|
dataToSign.userid = userIdPacket;
|
|
135
181
|
dataToSign.key = secretKeyPacket;
|
|
136
|
-
signaturePacket = new
|
|
137
|
-
signaturePacket.signatureType =
|
|
138
|
-
signaturePacket.publicKeyAlgorithm =
|
|
139
|
-
signaturePacket.hashAlgorithm =
|
|
140
|
-
signaturePacket.keyFlags = [
|
|
182
|
+
var signaturePacket = new openpgp.Signature();
|
|
183
|
+
signaturePacket.signatureType = openpgp.enums.signature.cert_generic;
|
|
184
|
+
signaturePacket.publicKeyAlgorithm = openpgp.enums.publicKey.rsa_encrypt_sign;
|
|
185
|
+
signaturePacket.hashAlgorithm = openpgp.config.prefer_hash_algorithm;
|
|
186
|
+
signaturePacket.keyFlags = [openpgp.enums.keyFlags.certify_keys | openpgp.enums.keyFlags.sign_data];
|
|
141
187
|
signaturePacket.preferredSymmetricAlgorithms = [];
|
|
142
|
-
signaturePacket.preferredSymmetricAlgorithms.push(
|
|
143
|
-
signaturePacket.preferredSymmetricAlgorithms.push(
|
|
144
|
-
signaturePacket.preferredSymmetricAlgorithms.push(
|
|
145
|
-
signaturePacket.preferredSymmetricAlgorithms.push(
|
|
146
|
-
signaturePacket.preferredSymmetricAlgorithms.push(
|
|
188
|
+
signaturePacket.preferredSymmetricAlgorithms.push(openpgp.enums.symmetric.aes256);
|
|
189
|
+
signaturePacket.preferredSymmetricAlgorithms.push(openpgp.enums.symmetric.aes192);
|
|
190
|
+
signaturePacket.preferredSymmetricAlgorithms.push(openpgp.enums.symmetric.aes128);
|
|
191
|
+
signaturePacket.preferredSymmetricAlgorithms.push(openpgp.enums.symmetric.cast5);
|
|
192
|
+
signaturePacket.preferredSymmetricAlgorithms.push(openpgp.enums.symmetric.tripledes);
|
|
147
193
|
signaturePacket.preferredHashAlgorithms = [];
|
|
148
|
-
signaturePacket.preferredHashAlgorithms.push(
|
|
149
|
-
signaturePacket.preferredHashAlgorithms.push(
|
|
150
|
-
signaturePacket.preferredHashAlgorithms.push(
|
|
194
|
+
signaturePacket.preferredHashAlgorithms.push(openpgp.enums.hash.sha256);
|
|
195
|
+
signaturePacket.preferredHashAlgorithms.push(openpgp.enums.hash.sha1);
|
|
196
|
+
signaturePacket.preferredHashAlgorithms.push(openpgp.enums.hash.sha512);
|
|
151
197
|
signaturePacket.preferredCompressionAlgorithms = [];
|
|
152
|
-
signaturePacket.preferredCompressionAlgorithms.push(
|
|
153
|
-
signaturePacket.preferredCompressionAlgorithms.push(
|
|
154
|
-
if (
|
|
198
|
+
signaturePacket.preferredCompressionAlgorithms.push(openpgp.enums.compression.zlib);
|
|
199
|
+
signaturePacket.preferredCompressionAlgorithms.push(openpgp.enums.compression.zip);
|
|
200
|
+
if (openpgp.config.integrity_protect) {
|
|
155
201
|
signaturePacket.features = [];
|
|
156
202
|
signaturePacket.features.push(1); // Modification Detection
|
|
157
203
|
}
|
|
@@ -160,11 +206,11 @@ function wrapKeyObject(userId, secretKeyPacket, secretSubkeyPacket)
|
|
|
160
206
|
dataToSign = {};
|
|
161
207
|
dataToSign.key = secretKeyPacket;
|
|
162
208
|
dataToSign.bind = secretSubkeyPacket;
|
|
163
|
-
subkeySignaturePacket = new
|
|
164
|
-
subkeySignaturePacket.signatureType =
|
|
165
|
-
subkeySignaturePacket.publicKeyAlgorithm =
|
|
166
|
-
subkeySignaturePacket.hashAlgorithm =
|
|
167
|
-
subkeySignaturePacket.keyFlags = [
|
|
209
|
+
var subkeySignaturePacket = new openpgp.Signature();
|
|
210
|
+
subkeySignaturePacket.signatureType = openpgp.enums.signature.subkey_binding;
|
|
211
|
+
subkeySignaturePacket.publicKeyAlgorithm = openpgp.enums.publicKey.rsa_encrypt_sign;
|
|
212
|
+
subkeySignaturePacket.hashAlgorithm = openpgp.config.prefer_hash_algorithm;
|
|
213
|
+
subkeySignaturePacket.keyFlags = [openpgp.enums.keyFlags.encrypt_communication | openpgp.enums.keyFlags.encrypt_storage];
|
|
168
214
|
subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
|
|
169
215
|
|
|
170
216
|
packetlist.push(secretKeyPacket);
|
|
@@ -173,20 +219,20 @@ function wrapKeyObject(userId, secretKeyPacket, secretSubkeyPacket)
|
|
|
173
219
|
packetlist.push(secretSubkeyPacket);
|
|
174
220
|
packetlist.push(subkeySignaturePacket);
|
|
175
221
|
|
|
176
|
-
return new
|
|
222
|
+
return new openpgp.Key(packetlist);
|
|
177
223
|
}
|
|
178
224
|
|
|
179
225
|
function createSecretKey(key)
|
|
180
226
|
{
|
|
181
227
|
var mpiList = createMPIList(key);
|
|
182
|
-
var packet = createSecretKeyPacketFromList(mpiList,
|
|
228
|
+
var packet = createSecretKeyPacketFromList(mpiList, openpgp.SecretKeyPacket);
|
|
183
229
|
return packet;
|
|
184
230
|
}
|
|
185
231
|
|
|
186
232
|
function createSecretSubKey(key)
|
|
187
233
|
{
|
|
188
234
|
var mpiList = createMPIList(key);
|
|
189
|
-
var packet = createSecretKeyPacketFromList(mpiList,
|
|
235
|
+
var packet = createSecretKeyPacketFromList(mpiList, openpgp.SecretSubkeyPacket);
|
|
190
236
|
return packet;
|
|
191
237
|
}
|
|
192
238
|
|
|
@@ -195,7 +241,7 @@ function createSecretKeyPacketFromList(mpiList, PacketType)
|
|
|
195
241
|
var secretKeyPacket = new PacketType();
|
|
196
242
|
secretKeyPacket.mpi = mpiList;
|
|
197
243
|
secretKeyPacket.isDecrypted = true;
|
|
198
|
-
secretKeyPacket.algorithm =
|
|
244
|
+
secretKeyPacket.algorithm = openpgp.enums.read(openpgp.enums.publicKey, openpgp.enums.publicKey.rsa_encrypt_sign);
|
|
199
245
|
return secretKeyPacket;
|
|
200
246
|
}
|
|
201
247
|
|
|
@@ -218,13 +264,13 @@ function createMPIList(privateKey)
|
|
|
218
264
|
|
|
219
265
|
function createMPI(value, radix)
|
|
220
266
|
{
|
|
221
|
-
var BigInteger =
|
|
267
|
+
var BigInteger = openpgp.crypto.publicKey.jsbn;
|
|
222
268
|
var bn = new BigInteger(value, radix);
|
|
223
269
|
return createMPIFromBI(bn);
|
|
224
270
|
}
|
|
225
271
|
|
|
226
272
|
function createMPIFromBI(bigIntegeger) {
|
|
227
|
-
var mpi = new
|
|
273
|
+
var mpi = new openpgp.MPI();
|
|
228
274
|
mpi.fromBigInteger(bigIntegeger);
|
|
229
275
|
return mpi;
|
|
230
276
|
}
|
|
@@ -248,7 +294,7 @@ function sendError(err) {
|
|
|
248
294
|
function SecureRandom() {
|
|
249
295
|
function nextBytes(byteArray) {
|
|
250
296
|
for (var n = 0; n < byteArray.length; n++) {
|
|
251
|
-
byteArray[n] =
|
|
297
|
+
byteArray[n] = openpgp.crypto.random.getSecureRandomOctet();
|
|
252
298
|
}
|
|
253
299
|
}
|
|
254
300
|
this.nextBytes = nextBytes;
|
|
@@ -261,26 +307,8 @@ function debug(msg) {
|
|
|
261
307
|
|
|
262
308
|
function send(content) {
|
|
263
309
|
if(self.postMessage != undefined) {
|
|
264
|
-
self.postMessage(content);
|
|
310
|
+
self.postMessage(content, '*');
|
|
265
311
|
} else {
|
|
266
|
-
postMessage(content);
|
|
312
|
+
postMessage(content, '*');
|
|
267
313
|
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function execute(cmd, errMsg) {
|
|
271
|
-
// wrap the sync cmd in a promise
|
|
272
|
-
var promise = new Promise(function(resolve) {
|
|
273
|
-
var result = cmd();
|
|
274
|
-
resolve(result);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// handler error globally
|
|
278
|
-
return promise.catch(onError.bind(null, errMsg));
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function onError(message, error) {
|
|
282
|
-
// log the stack trace
|
|
283
|
-
console.error(error.stack);
|
|
284
|
-
// rethrow new high level error for api users
|
|
285
|
-
throw new Error(message);
|
|
286
314
|
}
|
package/lib/uploadWorker.js
CHANGED
|
@@ -1,56 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
window.crypto = {
|
|
6
|
-
getRandomValues: function (buf) {
|
|
7
|
-
if(self.ivCounter + buf > self.iv.size)
|
|
8
|
-
{
|
|
9
|
-
self.send({'cmd': 'randBuff'});
|
|
10
|
-
}
|
|
11
|
-
for(var i = 0; i<buf.length; i++)
|
|
12
|
-
{
|
|
13
|
-
buf[i] = self.iv[self.ivCounter++].charCodeAt();
|
|
14
|
-
}
|
|
1
|
+
try {
|
|
2
|
+
if (window === undefined) {
|
|
3
|
+
window = globalThis;
|
|
15
4
|
}
|
|
16
|
-
}
|
|
5
|
+
} catch (err) {
|
|
6
|
+
window = {};
|
|
7
|
+
}
|
|
17
8
|
|
|
18
|
-
self.ivCounter = 0;
|
|
19
9
|
self.log = "";
|
|
20
10
|
|
|
21
11
|
self.addEventListener('message', function(e) {
|
|
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
|
-
self.start();
|
|
49
|
-
break;
|
|
50
|
-
|
|
51
|
-
case 'randBuff':
|
|
52
|
-
self.iv = data.iv;
|
|
53
|
-
self.ivCounter = 0;
|
|
12
|
+
var data = e.data;
|
|
13
|
+
switch (data.cmd) {
|
|
14
|
+
case 'start':
|
|
15
|
+
self.csrf = data.csrf;
|
|
16
|
+
self.serverSecret = data.serverSecret;
|
|
17
|
+
self.packageId = data.packageId;
|
|
18
|
+
self.directoryId = data.directoryId;
|
|
19
|
+
self.file = data.file;
|
|
20
|
+
self.fileId = data.fileId;
|
|
21
|
+
self.uploadUrl = data.uploadUrl;
|
|
22
|
+
self.keycode = data.keycode;
|
|
23
|
+
self.name = data.name;
|
|
24
|
+
self.browser = data.browser;
|
|
25
|
+
self.uploadedBytes = 0;
|
|
26
|
+
self.SEGMENT_SIZE = data.SEGMENT_SIZE;
|
|
27
|
+
self.filePart = data.filePart;
|
|
28
|
+
self.totalFileSize = data.totalFileSize;
|
|
29
|
+
self.totalParts = data.parts;
|
|
30
|
+
self.id = data.id;
|
|
31
|
+
self.boundary = data.boundary;
|
|
32
|
+
|
|
33
|
+
// Add file
|
|
34
|
+
self.postMessage({'cmd': 'state', 'fileId': self.fileId, 'name': self.name, 'state': 'ENCRYPTION_STARTED', 'part': self.filePart, 'filesize': self.totalFileSize}, '*');
|
|
35
|
+
|
|
36
|
+
self.start();
|
|
54
37
|
break;
|
|
55
38
|
|
|
56
39
|
case 'encrypt_message':
|
|
@@ -60,14 +43,14 @@ self.addEventListener('message', function(e) {
|
|
|
60
43
|
self.cspUrl = data.cspUrl;
|
|
61
44
|
self.keycode = data.keycode;
|
|
62
45
|
self.salt = data.salt;
|
|
63
|
-
self.iv = data.iv;
|
|
64
46
|
self.workerId = data.workerId;
|
|
47
|
+
|
|
65
48
|
self.debug('Starting to encrypt');
|
|
66
49
|
self.encryptMessage();
|
|
67
50
|
|
|
68
51
|
break;
|
|
69
52
|
case 'decrypt_message':
|
|
70
|
-
|
|
53
|
+
self.debug('Starting to decrypt message');
|
|
71
54
|
self.serverSecret = data.serverSecret;
|
|
72
55
|
self.message = data.message;
|
|
73
56
|
self.cspUrl = data.cspUrl;
|
|
@@ -75,14 +58,12 @@ self.addEventListener('message', function(e) {
|
|
|
75
58
|
self.workerId = data.workerId;
|
|
76
59
|
|
|
77
60
|
self.salt = data.salt;
|
|
78
|
-
self.iv = data.iv;
|
|
79
61
|
|
|
80
62
|
self.decryptMessage();
|
|
81
63
|
|
|
82
64
|
break;
|
|
83
65
|
case 'decrypt_file':
|
|
84
|
-
self.
|
|
85
|
-
self.iv = data.randomness;
|
|
66
|
+
self.debug('Starting to decrypt file');
|
|
86
67
|
self.decryptionKey = data.decryptionKey;
|
|
87
68
|
self.fileId = data.fileId;
|
|
88
69
|
self.file = data.file;
|
|
@@ -97,9 +78,10 @@ self.addEventListener('message', function(e) {
|
|
|
97
78
|
}, false);
|
|
98
79
|
|
|
99
80
|
function decryptFile()
|
|
100
|
-
{
|
|
81
|
+
{
|
|
82
|
+
|
|
101
83
|
self.pgpDecryptMessage(self.file, self.decryptionKey, function(decryptedData) {
|
|
102
|
-
|
|
84
|
+
self.postMessage({'cmd': 'decrypted', 'fileId': self.fileId, 'workerId': self.workerId, 'data': decryptedData, 'part': self.part}, '*');
|
|
103
85
|
});
|
|
104
86
|
}
|
|
105
87
|
|
|
@@ -123,7 +105,7 @@ function decryptMessage() {
|
|
|
123
105
|
var decoded = base64Decode(self.message);
|
|
124
106
|
self.pgpDecryptMessage(decoded, decryptionKey, function (decryptedMsg) {
|
|
125
107
|
var plaintextString = typedArrayToUnicodeString(decryptedMsg); // Uint8Array([0x01, 0x01, 0x01])
|
|
126
|
-
self.postMessage({'cmd': 'done', data: plaintextString},'*');
|
|
108
|
+
self.postMessage({'cmd': 'done', data: plaintextString}, '*');
|
|
127
109
|
});
|
|
128
110
|
} catch(e) {
|
|
129
111
|
throw(e);
|
|
@@ -133,23 +115,33 @@ function decryptMessage() {
|
|
|
133
115
|
|
|
134
116
|
function encryptMessage() {
|
|
135
117
|
var encryptionKey = self.serverSecret + self.keycode;
|
|
118
|
+
|
|
136
119
|
self.pgpEncryptMessage(encryptionKey, self.message, 'msg.txt', function (encryptedMsg) {
|
|
137
120
|
var base64EncodedResponse = base64EncodeArray(encryptedMsg);
|
|
138
|
-
self.postMessage({'cmd': 'done', data: base64EncodedResponse},'*');
|
|
121
|
+
self.postMessage({'cmd': 'done', data: base64EncodedResponse}, '*');
|
|
139
122
|
});
|
|
140
123
|
}
|
|
141
124
|
|
|
142
125
|
function pgpEncryptMessage(encryptionKey, data, filename, callback)
|
|
143
126
|
{
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
127
|
+
// Create open PGP message
|
|
128
|
+
openpgp.createMessage({ "text": data })
|
|
129
|
+
.then(function (message) {
|
|
130
|
+
var options = {
|
|
131
|
+
message, // input as message obj per openPGPv6
|
|
132
|
+
passwords: [encryptionKey], // multiple passwords possible
|
|
133
|
+
format: 'object',
|
|
134
|
+
config: {
|
|
135
|
+
s2kIterationCountByte: 96
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Encrypt open PGP message
|
|
140
|
+
openpgp.encrypt(options)
|
|
141
|
+
.then(function(ciphertext) {
|
|
142
|
+
callback(ciphertext.packets.write());
|
|
143
|
+
});
|
|
144
|
+
});
|
|
153
145
|
}
|
|
154
146
|
|
|
155
147
|
function typedArrayToUnicodeString(ua) {
|
|
@@ -166,19 +158,27 @@ function typedArrayToUnicodeString(ua) {
|
|
|
166
158
|
return decodeURIComponent(escstr);
|
|
167
159
|
}
|
|
168
160
|
|
|
169
|
-
|
|
161
|
+
function pgpDecryptMessage(encryptedString, passphrase, callback)
|
|
170
162
|
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
163
|
+
// Read in string as message
|
|
164
|
+
openpgp.readMessage({"binaryMessage": encryptedString})
|
|
165
|
+
.then(function(message) {
|
|
166
|
+
var options = {
|
|
167
|
+
message, // parse encrypted bytes
|
|
168
|
+
passwords: [passphrase], // decrypt with password
|
|
169
|
+
format: 'binary',
|
|
170
|
+
config: {
|
|
171
|
+
s2kIterationCountByte: 96
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// And decrypt message with openPGP
|
|
176
|
+
openpgp.decrypt(options)
|
|
177
|
+
.then(function(plaintext) {
|
|
178
|
+
callback(plaintext.data); // String
|
|
179
|
+
plaintext = undefined; //Free up for GC
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function base64EncodeArray(t,o)
|
|
@@ -262,23 +262,28 @@ function base64Decode(t)
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
function start() {
|
|
265
|
-
debug("Using browser: " + self.browser);
|
|
266
265
|
|
|
267
266
|
var encryptionKey = self.serverSecret + self.keycode;
|
|
268
|
-
//var reader = new FileReaderSync();
|
|
269
267
|
var typedArray = new Uint8Array(self.file);
|
|
270
268
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
269
|
+
openpgp.createMessage({ "binary": typedArray })
|
|
270
|
+
.then(function (message) {
|
|
271
|
+
var options = {
|
|
272
|
+
message, // input as messageObj per openPGPv6 update
|
|
273
|
+
passwords: [encryptionKey], // multiple passwords possible
|
|
274
|
+
format: 'binary',
|
|
275
|
+
config: {
|
|
276
|
+
s2kIterationCountByte: 96
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Encrypt file with new message obj in options
|
|
281
|
+
openpgp.encrypt(options)
|
|
282
|
+
.then(function(ciphertext) {
|
|
283
|
+
self.postMessage({'cmd': 'state', 'name': self.name, 'fileId': self.fileId, 'state': 'FILE_ENCRYPTED', 'part': self.filePart}, '*');
|
|
284
|
+
self.postMessage({'cmd': 'upload', 'packageId': self.packageId, 'id': self.id, 'boundary': self.boundary, 'file': ciphertext, 'name': self.name, 'fileId': self.fileId, 'part': self.filePart, 'parts': self.totalParts, 'filesize': self.totalFileSize}, '*');
|
|
285
|
+
});
|
|
286
|
+
});
|
|
282
287
|
}
|
|
283
288
|
|
|
284
289
|
function updateProgress(type, number) {
|
|
@@ -292,9 +297,9 @@ function debug(msg) {
|
|
|
292
297
|
|
|
293
298
|
function send(content) {
|
|
294
299
|
if(self.postMessage != undefined) {
|
|
295
|
-
self.postMessage(content,'*');
|
|
300
|
+
self.postMessage(content, '*');
|
|
296
301
|
} else {
|
|
297
|
-
postMessage(content,'*');
|
|
302
|
+
postMessage(content, '*');
|
|
298
303
|
}
|
|
299
304
|
}
|
|
300
305
|
|
|
@@ -304,8 +309,8 @@ function fatalError(msg, err) {
|
|
|
304
309
|
self.debug(err.stack);
|
|
305
310
|
}
|
|
306
311
|
|
|
307
|
-
self.postMessage({'cmd': 'fatal', 'msg': msg, 'debug': self.log});
|
|
308
|
-
throw new Error('
|
|
312
|
+
self.postMessage({'cmd': 'fatal', 'msg': msg, 'debug': self.log, 'workerId': self.workerId});
|
|
313
|
+
throw new Error(msg + ': ' + err.stack);
|
|
309
314
|
}
|
|
310
315
|
|
|
311
316
|
self.updateProgres = updateProgress;
|
|
@@ -319,4 +324,4 @@ self.encryptMessage = encryptMessage;
|
|
|
319
324
|
self.base64EncodeArray = base64EncodeArray;
|
|
320
325
|
self.base64Decode = base64Decode;
|
|
321
326
|
self.pgpEncryptMessage = pgpEncryptMessage;
|
|
322
|
-
self.pgpDecryptMessage = pgpDecryptMessage;
|
|
327
|
+
self.pgpDecryptMessage = pgpDecryptMessage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendsafely/sendsafely",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"main": "./lib/SendSafely.js",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"jquery": "^3.4.1",
|
|
16
16
|
"jsdom": "^26.0.0",
|
|
17
17
|
"make-fetch-happen": "^11.1.1",
|
|
18
|
-
"openpgp": "
|
|
18
|
+
"openpgp": "6.1.1",
|
|
19
19
|
"sjcl": "1.0.8",
|
|
20
20
|
"xmlhttprequest": "^1.8.0"
|
|
21
21
|
},
|