From cec4e029f0c84b20ce1bdf74accae53ac81a4e46 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Mon, 3 Apr 2023 15:45:23 +0200
Subject: [PATCH 001/224] Update web-stream-tools
---
package-lock.json | 73 ++++++++++++++---------------------------------
package.json | 2 +-
2 files changed, 22 insertions(+), 53 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index cefc59316..b568e01fa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,7 @@
"@openpgp/pako": "^1.0.12",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
- "@openpgp/web-stream-tools": "0.0.11-patch-0",
+ "@openpgp/web-stream-tools": "^0.0.13",
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-replace": "^2.3.2",
@@ -487,15 +487,6 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "node_modules/@mattiasbuelens/web-streams-adapter": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/@mattiasbuelens/web-streams-adapter/-/web-streams-adapter-0.1.0.tgz",
- "integrity": "sha512-oV4PyZfwJNtmFWhvlJLqYIX1Nn22ML8FZpS16ZUKv0hg7414xV1fjsGqxQzLT2dyK92TKxsJSwMOd7VNHAtPmA==",
- "dev": true,
- "engines": {
- "node": ">= 12"
- }
- },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -627,22 +618,17 @@
"dev": true
},
"node_modules/@openpgp/web-stream-tools": {
- "version": "0.0.11-patch-0",
- "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.11-patch-0.tgz",
- "integrity": "sha512-NrIF4DkCqC3WDcMDAgz17z+0Iik1fVrKuvdbjZXCnMZgYAWHpIG8CWnbp8yQRahAdF26jqCopA/qXrp8CYI2yw==",
+ "version": "0.0.13",
+ "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.13.tgz",
+ "integrity": "sha512-VQ0O0lUcD9ilLcMLQMJMgPhp8fDgMd4copd+UhSBGjud0vbI1ONQ3ffAhixEMml/AApLJtqCpd7PJcccPliFSA==",
"dev": true,
- "dependencies": {
- "@mattiasbuelens/web-streams-adapter": "~0.1.0",
- "web-streams-polyfill": "~3.0.3"
- }
- },
- "node_modules/@openpgp/web-stream-tools/node_modules/web-streams-polyfill": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.0.3.tgz",
- "integrity": "sha512-d2H/t0eqRNM4w2WvmTdoeIvzAUSpK7JmATB8Nr2lb7nQ9BTIJVjbQ/TRFVEh2gUH1HwclPdoPtfMoFfetXaZnA==",
- "dev": true,
- "engines": {
- "node": ">= 8"
+ "peerDependencies": {
+ "typescript": ">=4.2"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
"node_modules/@rollup/plugin-commonjs": {
@@ -6980,9 +6966,9 @@
}
},
"node_modules/typescript": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
- "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==",
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -7856,12 +7842,6 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "@mattiasbuelens/web-streams-adapter": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/@mattiasbuelens/web-streams-adapter/-/web-streams-adapter-0.1.0.tgz",
- "integrity": "sha512-oV4PyZfwJNtmFWhvlJLqYIX1Nn22ML8FZpS16ZUKv0hg7414xV1fjsGqxQzLT2dyK92TKxsJSwMOd7VNHAtPmA==",
- "dev": true
- },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -7967,22 +7947,11 @@
"dev": true
},
"@openpgp/web-stream-tools": {
- "version": "0.0.11-patch-0",
- "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.11-patch-0.tgz",
- "integrity": "sha512-NrIF4DkCqC3WDcMDAgz17z+0Iik1fVrKuvdbjZXCnMZgYAWHpIG8CWnbp8yQRahAdF26jqCopA/qXrp8CYI2yw==",
+ "version": "0.0.13",
+ "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.13.tgz",
+ "integrity": "sha512-VQ0O0lUcD9ilLcMLQMJMgPhp8fDgMd4copd+UhSBGjud0vbI1ONQ3ffAhixEMml/AApLJtqCpd7PJcccPliFSA==",
"dev": true,
- "requires": {
- "@mattiasbuelens/web-streams-adapter": "~0.1.0",
- "web-streams-polyfill": "~3.0.3"
- },
- "dependencies": {
- "web-streams-polyfill": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.0.3.tgz",
- "integrity": "sha512-d2H/t0eqRNM4w2WvmTdoeIvzAUSpK7JmATB8Nr2lb7nQ9BTIJVjbQ/TRFVEh2gUH1HwclPdoPtfMoFfetXaZnA==",
- "dev": true
- }
- }
+ "requires": {}
},
"@rollup/plugin-commonjs": {
"version": "11.1.0",
@@ -12938,9 +12907,9 @@
}
},
"typescript": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
- "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==",
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true
},
"ua-parser-js": {
diff --git a/package.json b/package.json
index b4fd982ed..6dc92a052 100644
--- a/package.json
+++ b/package.json
@@ -60,7 +60,7 @@
"@openpgp/pako": "^1.0.12",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
- "@openpgp/web-stream-tools": "0.0.11-patch-0",
+ "@openpgp/web-stream-tools": "^0.0.13",
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-replace": "^2.3.2",
From de5549ff690c6511101040423a04615bdf166ac8 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Fri, 2 Sep 2022 22:20:33 +0200
Subject: [PATCH 002/224] Remove embedded Web Streams ponyfill
Require the application to load a polyfill instead.
---
src/message.js | 10 +---------
src/openpgp.js | 5 +----
src/packet/aead_encrypted_data.js | 2 +-
src/packet/packet.js | 2 +-
test/general/openpgp.js | 12 ++++++------
test/general/signature.js | 16 ++++++++--------
test/general/streaming.js | 11 ++++++-----
test/unittests.js | 4 ++++
8 files changed, 28 insertions(+), 34 deletions(-)
diff --git a/src/message.js b/src/message.js
index 186fec42e..ce922dccf 100644
--- a/src/message.js
+++ b/src/message.js
@@ -877,10 +877,6 @@ export async function readMessage({ armoredMessage, binaryMessage, config, ...re
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const streamType = util.isStream(input);
- if (streamType) {
- await stream.loadStreamsPonyfill();
- input = stream.toStream(input);
- }
if (armoredMessage) {
const { type, data } = await unarmor(input, config);
if (type !== enums.armor.message) {
@@ -907,7 +903,7 @@ export async function readMessage({ armoredMessage, binaryMessage, config, ...re
* @static
*/
export async function createMessage({ text, binary, filename, date = new Date(), format = text !== undefined ? 'utf8' : 'binary', ...rest }) {
- let input = text !== undefined ? text : binary;
+ const input = text !== undefined ? text : binary;
if (input === undefined) {
throw new Error('createMessage: must pass options object containing `text` or `binary`');
}
@@ -920,10 +916,6 @@ export async function createMessage({ text, binary, filename, date = new Date(),
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const streamType = util.isStream(input);
- if (streamType) {
- await stream.loadStreamsPonyfill();
- input = stream.toStream(input);
- }
const literalDataPacket = new LiteralDataPacket(date);
if (text !== undefined) {
literalDataPacket.setText(input, enums.write(enums.literal, format));
diff --git a/src/openpgp.js b/src/openpgp.js
index 4d11f0a82..28554e7b9 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -663,7 +663,7 @@ function toArray(param) {
/**
* Convert data to or from Stream
* @param {Object} data - the data to convert
- * @param {'web'|'ponyfill'|'node'|false} streaming - Whether to return a ReadableStream, and of what type
+ * @param {'web'|'node'|false} streaming - Whether to return a ReadableStream, and of what type
* @param {'utf8'|'binary'} [encoding] - How to return data in Node Readable streams
* @returns {Promise} The data in the respective format.
* @async
@@ -679,9 +679,6 @@ async function convertStream(data, streaming, encoding = 'utf8') {
if (encoding !== 'binary') data.setEncoding(encoding);
return data;
}
- if (streaming === 'web' && streamType === 'ponyfill') {
- return stream.toNativeReadable(data);
- }
return data;
}
diff --git a/src/packet/aead_encrypted_data.js b/src/packet/aead_encrypted_data.js
index 3e24323b7..5f42a8fbb 100644
--- a/src/packet/aead_encrypted_data.js
+++ b/src/packet/aead_encrypted_data.js
@@ -152,7 +152,7 @@ class AEADEncryptedDataPacket {
const iv = this.iv;
return stream.transformPair(data, async (readable, writable) => {
if (util.isStream(readable) !== 'array') {
- const buffer = new stream.TransformStream({}, {
+ const buffer = new TransformStream({}, {
highWaterMark: util.getHardwareConcurrency() * 2 ** (this.chunkSizeByte + 6),
size: array => array.length
});
diff --git a/src/packet/packet.js b/src/packet/packet.js
index d18b6c285..b42e4edf3 100644
--- a/src/packet/packet.js
+++ b/src/packet/packet.js
@@ -153,7 +153,7 @@ export async function readPackets(input, callback) {
writer = stream.getWriter(arrayStream);
packet = arrayStream;
} else {
- const transform = new stream.TransformStream();
+ const transform = new TransformStream();
writer = stream.getWriter(transform.writable);
packet = transform.readable;
}
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 0b59cc32a..cfebc1e0d 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1,5 +1,5 @@
/* eslint-disable max-lines */
-/* globals tryTests: true */
+/* globals tryTests: true, loadStreamsPolyfill */
const spy = require('sinon/lib/sinon/spy');
const stream = require('@openpgp/web-stream-tools');
const { use: chaiUse, expect } = require('chai');
@@ -3000,20 +3000,20 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
throw new Error('Was not able to successfully modify checksum');
}
const badBodyEncrypted = data.replace(/\n=([a-zA-Z0-9/+]{4})/, 'aaa\n=$1');
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
try {
for (const allowStreaming of [true, false]) {
openpgp.config.allowUnauthenticatedStream = allowStreaming;
await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => {
await Promise.all([
encrypted,
- new stream.ReadableStream({
+ new ReadableStream({
start(controller) {
controller.enqueue(encrypted);
controller.close();
}
}),
- new stream.ReadableStream({
+ new ReadableStream({
start() {
this.remaining = encrypted.split('\n');
},
@@ -3265,7 +3265,7 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
const plaintext = [];
let i = 0;
const useNativeStream = (() => { try { new global.ReadableStream(); return true; } catch (e) { return false; } })(); // eslint-disable-line no-new
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
const ReadableStream = useNativeStream ? global.ReadableStream : stream.ReadableStream;
const data = new ReadableStream({
pull(controller) {
@@ -3622,7 +3622,7 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
packets.push(message.packets.findPacket(openpgp.enums.packet.literalData));
verifyOpt.message = await openpgp.readMessage({
binaryMessage: stream[
- global.ReadableStream ? (global.ReadableStream === stream.ReadableStream ? 'toStream' : 'toNativeReadable') : 'webToNode'
+ global.ReadableStream ? 'toStream' : 'webToNode'
](packets.write())
});
return openpgp.verify(verifyOpt);
diff --git a/test/general/signature.js b/test/general/signature.js
index 914a13e3a..5c123d7ce 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1,5 +1,5 @@
/* eslint-disable max-lines */
-/* globals tryTests: true */
+/* globals tryTests: true, loadStreamsPolyfill */
const stream = require('@openpgp/web-stream-tools');
const { use: chaiUse, expect } = require('chai');
chaiUse(require('chai-as-promised'));
@@ -900,7 +900,7 @@ AkLaG/AkATpuH+DMkYDmKbDLGgD+N4yuxXBJmBfC2IBe4J1S2Gg=
date: key.keyPacket.created,
format: 'object'
});
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey,
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
@@ -931,7 +931,7 @@ aMsUdQBgnPAcSGVsbG8gV29ybGQgOik=
date: key.keyPacket.created,
format: 'object'
});
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey,
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
@@ -961,7 +961,7 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
date: key.keyPacket.created,
format: 'object'
});
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey,
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
@@ -1454,9 +1454,9 @@ yYDnCgA=
-----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
const message = await openpgp.readMessage({
- armoredMessage: new stream.ReadableStream({
+ armoredMessage: new ReadableStream({
async pull(controller) {
await new Promise(setTimeout);
controller.enqueue(armoredMessage.shift());
@@ -1520,9 +1520,9 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
-----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
const message = await openpgp.readMessage({
- armoredMessage: new stream.ReadableStream({
+ armoredMessage: new ReadableStream({
async pull(controller) {
await new Promise(setTimeout);
controller.enqueue(armoredMessage.shift());
diff --git a/test/general/streaming.js b/test/general/streaming.js
index b604907a3..41b73dc90 100644
--- a/test/general/streaming.js
+++ b/test/general/streaming.js
@@ -1,4 +1,5 @@
/* eslint-disable max-lines */
+/* globals loadStreamsPolyfill */
const stream = require('@openpgp/web-stream-tools');
const stub = require('sinon/lib/sinon/stub');
const { use: chaiUse, expect } = require('chai');
@@ -423,7 +424,7 @@ function tests() {
expect(stream.isStream(encrypted)).to.equal(expectedType);
const message = await openpgp.readMessage({
- armoredMessage: stream[expectedType === 'node' ? 'webToNode' : global.ReadableStream === stream.ReadableStream ? 'toStream' : 'toNativeReadable'](stream.transform(encrypted, value => {
+ armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => {
value += '';
if (value === '=' || value.length === 5) return; // Remove checksum
const newlineIndex = value.indexOf('\n', 500);
@@ -461,7 +462,7 @@ function tests() {
expect(stream.isStream(encrypted)).to.equal(expectedType);
const message = await openpgp.readMessage({
- armoredMessage: stream[expectedType === 'node' ? 'webToNode' : global.ReadableStream === stream.ReadableStream ? 'toStream' : 'toNativeReadable'](stream.transform(encrypted, value => {
+ armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => {
value += '';
const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
@@ -498,7 +499,7 @@ function tests() {
expect(stream.isStream(encrypted)).to.equal(expectedType);
const message = await openpgp.readMessage({
- armoredMessage: stream[expectedType === 'node' ? 'webToNode' : global.ReadableStream === stream.ReadableStream ? 'toStream' : 'toNativeReadable'](stream.transform(encrypted, value => {
+ armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => {
value += '';
const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
@@ -531,7 +532,7 @@ function tests() {
expect(stream.isStream(signed)).to.equal(expectedType);
const message = await openpgp.readMessage({
- armoredMessage: stream[expectedType === 'node' ? 'webToNode' : global.ReadableStream === stream.ReadableStream ? 'toStream' : 'toNativeReadable'](stream.transform(signed, value => {
+ armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(signed, value => {
value += '';
const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
@@ -956,7 +957,7 @@ module.exports = () => describe('Streaming', function() {
passphrase: 'hello world'
});
- await stream.loadStreamsPonyfill();
+ loadStreamsPolyfill();
});
beforeEach(function() {
diff --git a/test/unittests.js b/test/unittests.js
index b8e43a1e1..3b28d9892 100644
--- a/test/unittests.js
+++ b/test/unittests.js
@@ -26,6 +26,10 @@ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp
}
};
+(typeof window !== 'undefined' ? window : global).loadStreamsPolyfill = function() {
+ require('web-streams-polyfill/es2018'); // eslint-disable-line import/no-unassigned-import
+};
+
describe('Unit Tests', function () {
openpgp.config.s2kIterationCountByte = 0;
From 95c73738fabdc8986e21715c3d29478c60bcc9ef Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Fri, 2 Sep 2022 22:24:11 +0200
Subject: [PATCH 003/224] Update ESLint globals syntax
---
test/general/brainpool.js | 2 +-
test/general/key.js | 2 +-
test/general/openpgp.js | 2 +-
test/general/signature.js | 2 +-
test/worker/application_worker.js | 2 +-
test/worker/worker_example.js | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/general/brainpool.js b/test/general/brainpool.js
index c432b7664..fbcc9b940 100644
--- a/test/general/brainpool.js
+++ b/test/general/brainpool.js
@@ -1,4 +1,4 @@
-/* globals tryTests: true */
+/* globals tryTests */
const { use: chaiUse, expect } = require('chai');
chaiUse(require('chai-as-promised'));
diff --git a/test/general/key.js b/test/general/key.js
index c75aaa3e1..7bf66805d 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -1,5 +1,5 @@
/* eslint-disable max-lines */
-/* globals tryTests: true */
+/* globals tryTests */
const { use: chaiUse, expect } = require('chai');
chaiUse(require('chai-as-promised'));
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index cfebc1e0d..1ae43b016 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1,5 +1,5 @@
/* eslint-disable max-lines */
-/* globals tryTests: true, loadStreamsPolyfill */
+/* globals tryTests, loadStreamsPolyfill */
const spy = require('sinon/lib/sinon/spy');
const stream = require('@openpgp/web-stream-tools');
const { use: chaiUse, expect } = require('chai');
diff --git a/test/general/signature.js b/test/general/signature.js
index 5c123d7ce..75468fb86 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1,5 +1,5 @@
/* eslint-disable max-lines */
-/* globals tryTests: true, loadStreamsPolyfill */
+/* globals tryTests, loadStreamsPolyfill */
const stream = require('@openpgp/web-stream-tools');
const { use: chaiUse, expect } = require('chai');
chaiUse(require('chai-as-promised'));
diff --git a/test/worker/application_worker.js b/test/worker/application_worker.js
index 0d0966132..cbd1fa941 100644
--- a/test/worker/application_worker.js
+++ b/test/worker/application_worker.js
@@ -1,4 +1,4 @@
-/* globals tryTests: true */
+/* globals tryTests */
const { expect } = require('chai');
diff --git a/test/worker/worker_example.js b/test/worker/worker_example.js
index b5b76341b..fbd2cee1a 100644
--- a/test/worker/worker_example.js
+++ b/test/worker/worker_example.js
@@ -1,4 +1,4 @@
-/* globals openpgp: true */
+/* globals openpgp */
importScripts('../../dist/openpgp.js');
From e1ba0b23737db149e4dadbda88864b98b6b90440 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Fri, 2 Sep 2022 22:24:54 +0200
Subject: [PATCH 004/224] Use globalThis for setting test helper functions
globals
---
test/unittests.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/unittests.js b/test/unittests.js
index 3b28d9892..4bf00069e 100644
--- a/test/unittests.js
+++ b/test/unittests.js
@@ -2,15 +2,15 @@ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp
(typeof window !== 'undefined' ? window : global).globalThis = (typeof window !== 'undefined' ? window : global);
-(typeof window !== 'undefined' ? window : global).resolves = function(val) {
+globalThis.resolves = function(val) {
return new Promise(function(res) { res(val); });
};
-(typeof window !== 'undefined' ? window : global).rejects = function(val) {
+globalThis.rejects = function(val) {
return new Promise(function(res, rej) { rej(val); });
};
-(typeof window !== 'undefined' ? window : global).tryTests = function(name, tests, options) {
+globalThis.tryTests = function(name, tests, options) {
if (options.if) {
describe(name, function() {
if (options.before) { before(options.before); }
@@ -26,7 +26,7 @@ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp
}
};
-(typeof window !== 'undefined' ? window : global).loadStreamsPolyfill = function() {
+globalThis.loadStreamsPolyfill = function() {
require('web-streams-polyfill/es2018'); // eslint-disable-line import/no-unassigned-import
};
From 204f32791d2c8f1276bc302711dc402cb15c7955 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 3 Apr 2023 17:52:21 +0200
Subject: [PATCH 005/224] CI: temporarily enable for PRs to v6 branch
---
.github/workflows/benchmark.yml | 2 +-
.github/workflows/docs.yml | 2 +-
.github/workflows/sop-test-suite.yml | 2 +-
.github/workflows/tests.yml | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 8f537a60f..7f3482e31 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -2,7 +2,7 @@ name: Performance Regression Test
on:
pull_request:
- branches: [main]
+ branches: [main, v6]
jobs:
benchmark:
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 0a9e8c96a..b0bc6afda 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -4,7 +4,7 @@ on:
push:
branches: [main]
pull_request:
- branches: [main]
+ branches: [main, v6]
jobs:
lint:
diff --git a/.github/workflows/sop-test-suite.yml b/.github/workflows/sop-test-suite.yml
index 39f26c1ae..cf1701b42 100644
--- a/.github/workflows/sop-test-suite.yml
+++ b/.github/workflows/sop-test-suite.yml
@@ -2,7 +2,7 @@ name: SOP interoperability test suite
on:
pull_request:
- branches: [ main ]
+ branches: [ main, v6 ]
jobs:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index feed0fbee..c816f93eb 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -4,7 +4,7 @@ on:
push:
branches: [main]
pull_request:
- branches: [main]
+ branches: [main, v6]
jobs:
build: # cache both dist and tests (non-lightweight only), based on commit hash
From ebf22f2ee716f6dceb613dc4a59fb69b29664afa Mon Sep 17 00:00:00 2001
From: larabr
Date: Tue, 4 Apr 2023 14:22:13 +0200
Subject: [PATCH 006/224] `crypto-refresh`: add support for Argon2 S2K (#1597)
In terms of API, this feature is backwards compatible, no breaking changes.
However, since a Wasm module is loaded for the Argon2 computation, browser apps
might need to make changes to their CSP policy in order to use the feature.
Newly introduced config fields:
- `config.s2kType` (defaulting to `enums.s2k.iterated`): s2k to use on
password-based encryption as well as private key encryption;
- `config.s2kArgon2Params` (defaulting to "uniformly safe settings" from Argon
RFC): parameters to use on encryption when `config.s2kType` is set to
`enums.s2k.argon2`;
---
openpgp.d.ts | 10 ++
package-lock.json | 38 +++++++
package.json | 2 +
rollup.config.js | 31 ++++--
src/config/config.js | 33 +++++-
src/enums.js | 1 +
src/message.js | 4 +
src/packet/secret_key.js | 11 +-
src/packet/sym_encrypted_session_key.js | 9 +-
src/type/s2k/argon2.js | 137 ++++++++++++++++++++++++
src/type/{s2k.js => s2k/generic.js} | 31 +++---
src/type/s2k/index.js | 46 ++++++++
test/general/openpgp.js | 64 +++++++++++
test/general/packet.js | 2 +-
14 files changed, 387 insertions(+), 32 deletions(-)
create mode 100644 src/type/s2k/argon2.js
rename src/type/{s2k.js => s2k/generic.js} (92%)
create mode 100644 src/type/s2k/index.js
diff --git a/openpgp.d.ts b/openpgp.d.ts
index 56175b269..c161efac0 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -332,7 +332,9 @@ interface Config {
v5Keys: boolean;
preferredAEADAlgorithm: enums.aead;
aeadChunkSizeByte: number;
+ s2kType: enums.s2k.iterated | enums.s2k.argon2;
s2kIterationCountByte: number;
+ s2kArgon2Params: { passes: number, parallelism: number; memoryExponent: number; };
minBytesForWebCrypto: number;
maxUserIDLength: number;
knownNotations: string[];
@@ -909,4 +911,12 @@ export namespace enums {
utf8 = 117,
mime = 109
}
+
+ enum s2k {
+ simple = 0,
+ salted = 1,
+ iterated = 3,
+ argon2 = 4,
+ gnu = 101
+ }
}
diff --git a/package-lock.json b/package-lock.json
index b568e01fa..0e86bc5c9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,9 @@
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-replace": "^2.3.2",
+ "@rollup/plugin-wasm": "^6.1.2",
"@types/chai": "^4.2.14",
+ "argon2id": "^1.0.1",
"benchmark": "^2.1.4",
"bn.js": "^4.11.8",
"chai": "^4.3.6",
@@ -693,6 +695,23 @@
"rollup": "^1.20.0 || ^2.0.0"
}
},
+ "node_modules/@rollup/plugin-wasm": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.1.2.tgz",
+ "integrity": "sha512-YdrQ7zfnZ54Y+6raCev3tR1PrhQGxYKSTajGylhyP0oBacouuNo6KcNCk+pYKw9M98jxRWLFFca/udi76IDXzg==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rollup/pluginutils": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.9.tgz",
@@ -952,6 +971,12 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
+ "node_modules/argon2id": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/argon2id/-/argon2id-1.0.1.tgz",
+ "integrity": "sha512-rsiD3lX+0L0CsiZARp3bf9EGxprtuWAT7PpiJd+Fk53URV0/USOQkBIP1dLTV8t6aui0ECbymQ9W9YCcTd6XgA==",
+ "dev": true
+ },
"node_modules/argparse": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
@@ -7999,6 +8024,13 @@
"magic-string": "^0.25.5"
}
},
+ "@rollup/plugin-wasm": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.1.2.tgz",
+ "integrity": "sha512-YdrQ7zfnZ54Y+6raCev3tR1PrhQGxYKSTajGylhyP0oBacouuNo6KcNCk+pYKw9M98jxRWLFFca/udi76IDXzg==",
+ "dev": true,
+ "requires": {}
+ },
"@rollup/pluginutils": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.9.tgz",
@@ -8214,6 +8246,12 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
+ "argon2id": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/argon2id/-/argon2id-1.0.1.tgz",
+ "integrity": "sha512-rsiD3lX+0L0CsiZARp3bf9EGxprtuWAT7PpiJd+Fk53URV0/USOQkBIP1dLTV8t6aui0ECbymQ9W9YCcTd6XgA==",
+ "dev": true
+ },
"argparse": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
diff --git a/package.json b/package.json
index 6dc92a052..b48b07fcc 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,9 @@
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-replace": "^2.3.2",
+ "@rollup/plugin-wasm": "^6.1.2",
"@types/chai": "^4.2.14",
+ "argon2id": "^1.0.1",
"benchmark": "^2.1.4",
"bn.js": "^4.11.8",
"chai": "^4.3.6",
diff --git a/rollup.config.js b/rollup.config.js
index 6e1b51043..97656497f 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -6,10 +6,25 @@ import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
+import { wasm } from '@rollup/plugin-wasm';
+
import pkg from './package.json';
const nodeDependencies = Object.keys(pkg.dependencies);
+const wasmOptions = {
+ node: { targetEnv: 'node' },
+ browser: { targetEnv: 'browser', maxFileSize: undefined } // always inlline (our wasm files are small)
+};
+
+const getChunkFileName = (chunkInfo, extension) => {
+ // index files result in chunks named simply 'index', so we rename them to include the package name
+ if (chunkInfo.name === 'index') {
+ const packageName = chunkInfo.facadeModuleId.split('/').at(-2); // assume index file is under the root folder
+ return `${packageName}.${extension}`;
+ }
+ return `[name].${extension}`;
+};
const banner =
`/*! OpenPGP.js v${pkg.version} - ` +
@@ -50,7 +65,8 @@ export default Object.assign([
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
'require(': 'void(',
delimiters: ['', '']
- })
+ }),
+ wasm(wasmOptions.browser)
]
},
{
@@ -68,14 +84,15 @@ export default Object.assign([
commonjs(),
replace({
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`
- })
+ }),
+ wasm(wasmOptions.node)
]
},
{
input: 'src/index.js',
output: [
- { dir: 'dist/lightweight', entryFileNames: 'openpgp.mjs', chunkFileNames: '[name].mjs', format: 'es', banner, intro },
- { dir: 'dist/lightweight', entryFileNames: 'openpgp.min.mjs', chunkFileNames: '[name].min.mjs', format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
+ { dir: 'dist/lightweight', entryFileNames: 'openpgp.mjs', chunkFileNames: chunkInfo => getChunkFileName(chunkInfo, 'mjs'), format: 'es', banner, intro },
+ { dir: 'dist/lightweight', entryFileNames: 'openpgp.min.mjs', chunkFileNames: chunkInfo => getChunkFileName(chunkInfo, 'min.mjs'), format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
],
preserveEntrySignatures: 'allow-extension',
plugins: [
@@ -89,7 +106,8 @@ export default Object.assign([
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
'require(': 'void(',
delimiters: ['', '']
- })
+ }),
+ wasm(wasmOptions.browser)
]
},
{
@@ -110,7 +128,8 @@ export default Object.assign([
"import openpgpjs from '../../..';": `import * as openpgpjs from '/dist/${process.env.npm_config_lightweight ? 'lightweight/' : ''}openpgp.mjs'; window.openpgp = openpgpjs;`,
'require(': 'void(',
delimiters: ['', '']
- })
+ }),
+ wasm(wasmOptions.browser)
]
}
].filter(config => {
diff --git a/src/config/config.js b/src/config/config.js
index ccfee7e13..6f2baadb6 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -76,12 +76,41 @@ export default {
*/
v5Keys: false,
/**
- * {@link https://tools.ietf.org/html/rfc4880#section-3.7.1.3|RFC4880 3.7.1.3}:
- * Iteration Count Byte for S2K (String to Key)
+ * S2K (String to Key) type, used for key derivation in the context of secret key encryption
+ * and password-encrypted data. Weaker s2k options are not allowed.
+ * Note: Argon2 is the strongest option but not all OpenPGP implementations are compatible with it
+ * (pending standardisation).
+ * @memberof module:config
+ * @property {enums.s2k.argon2|enums.s2k.iterated} s2kType {@link module:enums.s2k}
+ */
+ s2kType: enums.s2k.iterated,
+ /**
+ * {@link https://tools.ietf.org/html/rfc4880#section-3.7.1.3| RFC4880 3.7.1.3}:
+ * Iteration Count Byte for Iterated and Salted S2K (String to Key).
+ * Only relevant if `config.s2kType` is set to `enums.s2k.iterated`.
+ * Note: this is the exponent value, not the final number of iterations (refer to specs for more details).
* @memberof module:config
* @property {Integer} s2kIterationCountByte
*/
s2kIterationCountByte: 224,
+ /**
+ * {@link https://tools.ietf.org/html/draft-ietf-openpgp-crypto-refresh-07.html#section-3.7.1.4| draft-crypto-refresh 3.7.1.4}:
+ * Argon2 parameters for S2K (String to Key).
+ * Only relevant if `config.s2kType` is set to `enums.s2k.argon2`.
+ * Default settings correspond to the second recommendation from RFC9106 ("uniformly safe option"),
+ * to ensure compatibility with memory-constrained environments.
+ * For more details on the choice of parameters, see https://tools.ietf.org/html/rfc9106#section-4.
+ * @memberof module:config
+ * @property {Object} params
+ * @property {Integer} params.passes - number of iterations t
+ * @property {Integer} params.parallelism - degree of parallelism p
+ * @property {Integer} params.memoryExponent - one-octet exponent indicating the memory size, which will be: 2**memoryExponent kibibytes.
+ */
+ s2kArgon2Params: {
+ passes: 3,
+ parallelism: 4, // lanes
+ memoryExponent: 16 // 64 MiB of RAM
+ },
/**
* Allow decryption of messages without integrity protection.
* This is an **insecure** setting:
diff --git a/src/enums.js b/src/enums.js
index 220ed807a..33982062a 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -91,6 +91,7 @@ export default {
simple: 0,
salted: 1,
iterated: 3,
+ argon2: 4,
gnu: 101
},
diff --git a/src/message.js b/src/message.js
index ce922dccf..5a88e7b08 100644
--- a/src/message.js
+++ b/src/message.js
@@ -18,6 +18,7 @@
import * as stream from '@openpgp/web-stream-tools';
import { armor, unarmor } from './encoding/armor';
import KeyID from './type/keyid';
+import { Argon2OutOfMemoryError } from './type/s2k';
import defaultConfig from './config';
import crypto from './crypto';
import enums from './enums';
@@ -183,6 +184,9 @@ export class Message {
decryptedSessionKeyPackets.push(skeskPacket);
} catch (err) {
util.printDebugError(err);
+ if (err instanceof Argon2OutOfMemoryError) {
+ exception = err;
+ }
}
}));
}));
diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js
index a0df643a2..cab073350 100644
--- a/src/packet/secret_key.js
+++ b/src/packet/secret_key.js
@@ -16,7 +16,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import PublicKeyPacket from './public_key';
-import S2K from '../type/s2k';
+import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
import crypto from '../crypto';
import enums from '../enums';
import util from '../util';
@@ -115,7 +115,8 @@ class SecretKeyPacket extends PublicKeyPacket {
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above.
- this.s2k = new S2K();
+ const s2kType = bytes[i++];
+ this.s2k = newS2KFromType(s2kType);
i += this.s2k.read(bytes.subarray(i, bytes.length));
if (this.s2k.type === 'gnu-dummy') {
@@ -279,7 +280,7 @@ class SecretKeyPacket extends PublicKeyPacket {
delete this.unparseableKeyMaterial;
this.isEncrypted = null;
this.keyMaterial = null;
- this.s2k = new S2K(config);
+ this.s2k = newS2KFromType(enums.s2k.gnu, config);
this.s2k.algorithm = 0;
this.s2k.c = 0;
this.s2k.type = 'gnu-dummy';
@@ -310,8 +311,8 @@ class SecretKeyPacket extends PublicKeyPacket {
throw new Error('A non-empty passphrase is required for key encryption.');
}
- this.s2k = new S2K(config);
- this.s2k.salt = crypto.random.getRandomBytes(8);
+ this.s2k = newS2KFromConfig(config);
+ this.s2k.generateSalt();
const cleartext = crypto.serializeParams(this.algorithm, this.privateParams);
this.symmetric = enums.symmetric.aes256;
const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js
index a383c711a..6e940779e 100644
--- a/src/packet/sym_encrypted_session_key.js
+++ b/src/packet/sym_encrypted_session_key.js
@@ -15,7 +15,7 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-import S2K from '../type/s2k';
+import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
import defaultConfig from '../config';
import crypto from '../crypto';
import enums from '../enums';
@@ -89,7 +89,8 @@ class SymEncryptedSessionKeyPacket {
}
// A string-to-key (S2K) specifier, length as defined above.
- this.s2k = new S2K();
+ const s2kType = bytes[offset++];
+ this.s2k = newS2KFromType(s2kType);
offset += this.s2k.read(bytes.subarray(offset, bytes.length));
if (this.version === 5) {
@@ -178,8 +179,8 @@ class SymEncryptedSessionKeyPacket {
this.sessionKeyEncryptionAlgorithm = algo;
- this.s2k = new S2K(config);
- this.s2k.salt = crypto.random.getRandomBytes(8);
+ this.s2k = newS2KFromConfig(config);
+ this.s2k.generateSalt();
const { blockSize, keySize } = crypto.getCipher(algo);
const encryptionKey = await this.s2k.produceKey(passphrase, keySize);
diff --git a/src/type/s2k/argon2.js b/src/type/s2k/argon2.js
new file mode 100644
index 000000000..f79e3ef6f
--- /dev/null
+++ b/src/type/s2k/argon2.js
@@ -0,0 +1,137 @@
+import defaultConfig from '../../config';
+import enums from '../../enums';
+import util from '../../util';
+import crypto from '../../crypto';
+
+const ARGON2_TYPE = 0x02; // id
+const ARGON2_VERSION = 0x13;
+const ARGON2_SALT_SIZE = 16;
+
+export class Argon2OutOfMemoryError extends Error {
+ constructor(...params) {
+ super(...params);
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, Argon2OutOfMemoryError);
+ }
+
+ this.name = 'Argon2OutOfMemoryError';
+ }
+}
+
+// cache argon wasm module
+let loadArgonWasmModule;
+let argon2Promise;
+// reload wasm module above this treshold, to deallocated used memory
+const ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19;
+
+class Argon2S2K {
+ /**
+ * @param {Object} [config] - Full configuration, defaults to openpgp.config
+ */
+ constructor(config = defaultConfig) {
+ const { passes, parallelism, memoryExponent } = config.s2kArgon2Params;
+
+ this.type = 'argon2';
+ /** @type {Uint8Array} 16 bytes of salt */
+ this.salt = null;
+ /** @type {Integer} number of passes */
+ this.t = passes;
+ /** @type {Integer} degree of parallelism (lanes) */
+ this.p = parallelism;
+ /** @type {Integer} exponent indicating memory size */
+ this.encodedM = memoryExponent;
+ }
+
+ generateSalt() {
+ this.salt = crypto.random.getRandomBytes(ARGON2_SALT_SIZE);
+ }
+
+ /**
+ * Parsing function for argon2 string-to-key specifier.
+ * @param {Uint8Array} bytes - Payload of argon2 string-to-key specifier
+ * @returns {Integer} Actual length of the object.
+ */
+ read(bytes) {
+ let i = 0;
+
+ this.salt = bytes.subarray(i, i + 16);
+ i += 16;
+
+ this.t = bytes[i++];
+ this.p = bytes[i++];
+ this.encodedM = bytes[i++]; // memory size exponent, one-octect
+
+ return i;
+ }
+
+ /**
+ * Serializes s2k information
+ * @returns {Uint8Array} Binary representation of s2k.
+ */
+ write() {
+ const arr = [
+ new Uint8Array([enums.write(enums.s2k, this.type)]),
+ this.salt,
+ new Uint8Array([this.t, this.p, this.encodedM])
+ ];
+
+ return util.concatUint8Array(arr);
+ }
+
+ /**
+ * Produces a key using the specified passphrase and the defined
+ * hashAlgorithm
+ * @param {String} passphrase - Passphrase containing user input
+ * @returns {Promise} Produced key with a length corresponding to `keySize`
+ * @throws {Argon2OutOfMemoryError|Errors}
+ * @async
+ */
+ async produceKey(passphrase, keySize) {
+ const decodedM = 2 << (this.encodedM - 1);
+
+ try {
+ // on first load, the argon2 lib is imported and the WASM module is initialized.
+ // the two steps need to be atomic to avoid race conditions causing multiple wasm modules
+ // being loaded when `argon2Promise` is not initialized.
+ loadArgonWasmModule = loadArgonWasmModule || (await import('argon2id')).default;
+ argon2Promise = argon2Promise || loadArgonWasmModule();
+
+ // important to keep local ref to argon2 in case the module is reloaded by another instance
+ const argon2 = await argon2Promise;
+
+ const passwordBytes = util.encodeUTF8(passphrase);
+ const hash = argon2({
+ version: ARGON2_VERSION,
+ type: ARGON2_TYPE,
+ password: passwordBytes,
+ salt: this.salt,
+ tagLength: keySize,
+ memorySize: decodedM,
+ parallelism: this.p,
+ passes: this.t
+ });
+
+ // a lot of memory was used, reload to deallocate
+ if (decodedM > ARGON2_WASM_MEMORY_THRESHOLD_RELOAD) {
+ // it will be awaited if needed at the next `produceKey` invocation
+ argon2Promise = loadArgonWasmModule();
+ argon2Promise.catch(() => {});
+ }
+ return hash;
+ } catch (e) {
+ if (e.message && (
+ e.message.includes('Unable to grow instance memory') || // Chrome
+ e.message.includes('failed to grow memory') || // Firefox
+ e.message.includes('WebAssembly.Memory.grow') || // Safari
+ e.message.includes('Out of memory') // Safari iOS
+ )) {
+ throw new Argon2OutOfMemoryError('Could not allocate required memory for Argon2');
+ } else {
+ throw e;
+ }
+ }
+ }
+}
+
+export default Argon2S2K;
diff --git a/src/type/s2k.js b/src/type/s2k/generic.js
similarity index 92%
rename from src/type/s2k.js
rename to src/type/s2k/generic.js
index 250c7e25f..ab9b28556 100644
--- a/src/type/s2k.js
+++ b/src/type/s2k/generic.js
@@ -28,17 +28,17 @@
* @private
*/
-import defaultConfig from '../config';
-import crypto from '../crypto';
-import enums from '../enums';
-import { UnsupportedError } from '../packet/packet';
-import util from '../util';
+import defaultConfig from '../../config';
+import crypto from '../../crypto';
+import enums from '../../enums';
+import { UnsupportedError } from '../../packet/packet';
+import util from '../../util';
-class S2K {
+class GenericS2K {
/**
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
- constructor(config = defaultConfig) {
+ constructor(s2kType, config = defaultConfig) {
/**
* Hash function identifier, or 0 for gnu-dummy keys
* @type {module:enums.hash | 0}
@@ -48,7 +48,7 @@ class S2K {
* enums.s2k identifier or 'gnu-dummy'
* @type {String}
*/
- this.type = 'iterated';
+ this.type = enums.read(enums.s2k, s2kType);
/** @type {Integer} */
this.c = config.s2kIterationCountByte;
/** Eight bytes of salt in a binary string.
@@ -57,6 +57,14 @@ class S2K {
this.salt = null;
}
+ generateSalt() {
+ switch (this.type) {
+ case 'salted':
+ case 'iterated':
+ this.salt = crypto.random.getRandomBytes(8);
+ }
+ }
+
getCount() {
// Exponent bias, defined in RFC4880
const expbias = 6;
@@ -71,11 +79,6 @@ class S2K {
*/
read(bytes) {
let i = 0;
- try {
- this.type = enums.read(enums.s2k, bytes[i++]);
- } catch (err) {
- throw new UnsupportedError('Unknown S2K type.');
- }
this.algorithm = bytes[i++];
switch (this.type) {
@@ -196,4 +199,4 @@ class S2K {
}
}
-export default S2K;
+export default GenericS2K;
diff --git a/src/type/s2k/index.js b/src/type/s2k/index.js
new file mode 100644
index 000000000..8a725c180
--- /dev/null
+++ b/src/type/s2k/index.js
@@ -0,0 +1,46 @@
+import defaultConfig from '../../config';
+import Argon2S2K, { Argon2OutOfMemoryError } from './argon2';
+import GenericS2K from './generic';
+import enums from '../../enums';
+import { UnsupportedError } from '../../packet/packet';
+
+const allowedS2KTypesForEncryption = new Set([enums.s2k.argon2, enums.s2k.iterated]);
+
+/**
+ * Instantiate a new S2K instance of the given type
+ * @param {module:enums.s2k} type
+ * @oaram {Object} [config]
+ * @returns {Object} New s2k object
+ * @throws {Error} for unknown or unsupported types
+ */
+export function newS2KFromType(type, config = defaultConfig) {
+ switch (type) {
+ case enums.s2k.argon2:
+ return new Argon2S2K(config);
+ case enums.s2k.iterated:
+ case enums.s2k.gnu:
+ case enums.s2k.salted:
+ case enums.s2k.simple:
+ return new GenericS2K(type, config);
+ default:
+ throw new UnsupportedError('Unsupported S2K type');
+ }
+}
+
+/**
+ * Instantiate a new S2K instance based on the config settings
+ * @oaram {Object} config
+ * @returns {Object} New s2k object
+ * @throws {Error} for unknown or unsupported types
+ */
+export function newS2KFromConfig(config) {
+ const { s2kType } = config;
+
+ if (!allowedS2KTypesForEncryption.has(s2kType)) {
+ throw new Error('The provided `config.s2kType` value is not allowed');
+ }
+
+ return newS2KFromType(s2kType, config);
+}
+
+export { Argon2OutOfMemoryError };
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 1ae43b016..f03f13b5e 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -15,6 +15,7 @@ const { isAEADSupported } = require('../../src/key');
const input = require('./testInputs');
const detectNode = () => typeof globalThis.process === 'object' && typeof globalThis.process.versions === 'object';
+const detectBrowser = () => typeof navigator === 'object';
const pub_key = [
'-----BEGIN PGP PUBLIC KEY BLOCK-----',
@@ -1243,6 +1244,25 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
expect(unlocked.isDecrypted()).to.be.true;
});
+ it('should support encrypting with argon2 s2k', async function() {
+ const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
+ const locked = await openpgp.encryptKey({
+ privateKey: key,
+ passphrase: passphrase,
+ config: { s2kType: openpgp.enums.s2k.argon2 }
+ });
+ expect(key.isDecrypted()).to.be.true;
+ expect(locked.isDecrypted()).to.be.false;
+ expect(locked.keyPacket.isDummy()).to.be.true;
+ const unlocked = await openpgp.decryptKey({
+ privateKey: locked,
+ passphrase: passphrase
+ });
+ expect(key.isDecrypted()).to.be.true;
+ expect(unlocked.isDecrypted()).to.be.true;
+ expect(unlocked.keyPacket.isDummy()).to.be.true;
+ });
+
it('should encrypt gnu-dummy key', async function() {
const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
const locked = await openpgp.encryptKey({
@@ -2150,6 +2170,50 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
data: util.hexToUint8Array('3e99c1bb485e70a1fcef09a7ad8d38d171015243bbdd853e1a2b0e334d122ff3')
})).to.be.rejectedWith(/No encryption keys or passwords provided/);
});
+
+ it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
+ const passwords = 'password';
+ // Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+Comment: Encrypted using AES with 128-bit key
+Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
+
+wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
+YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
+XfA3pqV4mTzF
+-----END PGP MESSAGE-----`;
+ const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
+
+ try {
+ const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
+ message: await openpgp.readMessage({ armoredMessage }),
+ passwords
+ });
+ expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
+ expect(decryptedSessionKey.algorithm).to.equal('aes128');
+ } catch (err) {
+ if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
+ expect(err.message).to.match(/Could not allocate required memory/);
+ }
+ }
+
+ });
+
+ // keep this after the 'memory-heavy' test to confirm that the Wasm module was successfully reloaded
+ it('supports encrypting with argon2 s2k', async function() {
+ const config = { s2kType: openpgp.enums.s2k.argon2 };
+ const passwords = 'password';
+ const sessionKey = {
+ algorithm: 'aes128',
+ data: util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F')
+ };
+ const encrypted = await openpgp.encryptSessionKey({ ...sessionKey, passwords, config, format: 'object' });
+ expect(encrypted.packets).to.have.length(1);
+ const skesk = encrypted.packets[0];
+ expect(skesk.s2k.type).to.equal('argon2');
+ const [decryptedSessionKey] = await openpgp.decryptSessionKeys({ message: encrypted, passwords });
+ expect(decryptedSessionKey).to.deep.equal(sessionKey);
+ });
});
describe('encrypt, decrypt, sign, verify - integration tests', function() {
diff --git a/test/general/packet.js b/test/general/packet.js
index 212e874f5..8fd963ac1 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -1042,7 +1042,7 @@ kePFjAnu9cpynKXu3usf8+FuBw2zLsg1Id1n7ttxoAte416KjBN9lFBt8mcu
await expect(
openpgp.PacketList.fromBinary(binaryMessage, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: false })
- ).to.be.rejectedWith(/Unknown S2K type/);
+ ).to.be.rejectedWith(/Unsupported S2K type/);
});
it('Throws on disallowed packet even with tolerant mode enabled', async function() {
From 3520a357f58f85823b3d92faed84a6236c379e16 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 4 Apr 2023 14:32:39 +0200
Subject: [PATCH 007/224] CI: drop Node 14
---
.github/workflows/tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c816f93eb..4c55e9917 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -30,7 +30,7 @@ jobs:
node:
strategy:
matrix:
- node-version: [14.x, 16.x, 18.x, 20.x]
+ node-version: [16.x, 18.x, '20.x']
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
name: Node ${{ matrix.node-version }}
From d49d92e5cb45b262053cc3d4e6f570ba58eebacd Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 9 May 2023 18:45:46 +0200
Subject: [PATCH 008/224] Update to Mocha v10 in tests, declare lib as `module`
and add `exports` to package.json
Mocha v10 requires the lib to be esm compliant.
ESM mandates the use of file extensions in imports, so to minimize the
changes (for now), we rely on the flag `experimental-specifier-resolution=node`
and on `ts-node` (needed only for Node 20).
Breaking changes:
downstream bundlers might be affected by the package.json changes depending on
how they load the library.
NB: legacy package.json entrypoints are still available.
---
.jsdocrc.js => .jsdocrc.cjs | 0
.mocharc.json | 6 +
lightweight/package.json | 2 +-
package-lock.json | 2269 ++++++++++++---------
package.json | 55 +-
rollup.config.js | 35 +-
src/crypto/cmac.js | 1 -
src/crypto/mode/eax.js | 1 -
src/crypto/mode/index.js | 1 -
src/crypto/public_key/elliptic/ecdsa.js | 2 +-
src/crypto/public_key/rsa.js | 2 +-
src/key/subkey.js | 1 -
src/util.js | 11 +-
test/benchmarks/memory_usage.js | 16 +-
test/benchmarks/time.js | 4 +-
test/crypto/aes_kw.js | 8 +-
test/crypto/cipher/aes.js | 6 +-
test/crypto/cipher/blowfish.js | 8 +-
test/crypto/cipher/cast5.js | 8 +-
test/crypto/cipher/des.js | 8 +-
test/crypto/cipher/index.js | 18 +-
test/crypto/cipher/twofish.js | 8 +-
test/crypto/crypto.js | 15 +-
test/crypto/eax.js | 15 +-
test/crypto/ecdh.js | 25 +-
test/crypto/elliptic.js | 21 +-
test/crypto/elliptic_data.js | 2 +-
test/crypto/gcm.js | 15 +-
test/crypto/hash/index.js | 12 +-
test/crypto/hash/md5.js | 8 +-
test/crypto/hash/ripemd.js | 16 +-
test/crypto/hash/sha.js | 8 +-
test/crypto/hkdf.js | 13 +-
test/crypto/index.js | 42 +-
test/crypto/ocb.js | 13 +-
test/crypto/pkcs5.js | 6 +-
test/crypto/rsa.js | 17 +-
test/crypto/validate.js | 11 +-
test/general/armor.js | 7 +-
test/general/biginteger.js | 13 +-
test/general/brainpool.js | 13 +-
test/general/config.js | 6 +-
test/general/decompression.js | 9 +-
test/general/ecc_nist.js | 13 +-
test/general/ecc_secp256k1.js | 11 +-
test/general/index.js | 49 +-
test/general/key.js | 15 +-
test/general/oid.js | 8 +-
test/general/openpgp.js | 33 +-
test/general/packet.js | 19 +-
test/general/signature.js | 23 +-
test/general/streaming.js | 27 +-
test/general/testInputs.js | 4 +-
test/general/util.js | 7 +-
test/general/x25519.js | 22 +-
test/{karma.conf.js => karma.conf.cjs} | 0
test/security/index.js | 15 +-
test/security/message_signature_bypass.js | 11 +-
test/security/preferred_algo_mismatch.js | 9 +-
test/security/subkey_trust.js | 10 +-
test/security/unsigned_subpackets.js | 10 +-
test/typescript/definitions.ts | 2 +-
test/unittests.js | 19 +-
test/worker/application_worker.js | 5 +-
test/worker/index.js | 6 +-
tsconfig.json | 12 +-
66 files changed, 1712 insertions(+), 1375 deletions(-)
rename .jsdocrc.js => .jsdocrc.cjs (100%)
create mode 100644 .mocharc.json
rename test/{karma.conf.js => karma.conf.cjs} (100%)
diff --git a/.jsdocrc.js b/.jsdocrc.cjs
similarity index 100%
rename from .jsdocrc.js
rename to .jsdocrc.cjs
diff --git a/.mocharc.json b/.mocharc.json
new file mode 100644
index 000000000..7b963c2da
--- /dev/null
+++ b/.mocharc.json
@@ -0,0 +1,6 @@
+{
+ "node-option": [
+ "experimental-specifier-resolution=node",
+ "loader=ts-node/esm"
+ ]
+}
diff --git a/lightweight/package.json b/lightweight/package.json
index 134e03c9c..c141a35d3 100644
--- a/lightweight/package.json
+++ b/lightweight/package.json
@@ -1,5 +1,5 @@
{
"name": "openpgp-lightweight",
- "main": "../dist/lightweight/openpgp.min.mjs",
+ "browser": "../dist/lightweight/openpgp.min.mjs",
"types": "../openpgp.d.ts"
}
diff --git a/package-lock.json b/package-lock.json
index 0e86bc5c9..676a4bb7f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,20 +14,22 @@
"devDependencies": {
"@openpgp/asmcrypto.js": "^2.3.2",
"@openpgp/elliptic": "^6.5.1",
- "@openpgp/jsdoc": "^3.6.4",
+ "@openpgp/jsdoc": "^3.6.11",
"@openpgp/pako": "^1.0.12",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
- "@openpgp/web-stream-tools": "^0.0.13",
- "@rollup/plugin-commonjs": "^11.1.0",
- "@rollup/plugin-node-resolve": "^7.1.3",
- "@rollup/plugin-replace": "^2.3.2",
+ "@openpgp/web-stream-tools": "^0.0.14",
+ "@rollup/plugin-alias": "^5.0.0",
+ "@rollup/plugin-commonjs": "^24.0.1",
+ "@rollup/plugin-node-resolve": "^15.0.1",
+ "@rollup/plugin-replace": "^5.0.2",
+ "@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-wasm": "^6.1.2",
"@types/chai": "^4.2.14",
"argon2id": "^1.0.1",
"benchmark": "^2.1.4",
"bn.js": "^4.11.8",
- "chai": "^4.3.6",
+ "chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"email-addresses": "3.1.0",
"eslint": "^8.34.0",
@@ -35,7 +37,6 @@
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
- "esm": "^3.2.25",
"hash.js": "^1.1.3",
"http-server": "^14.1.1",
"karma": "^6.4.0",
@@ -45,12 +46,12 @@
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-webkit-launcher": "^2.1.0",
- "mocha": "^8.4.0",
+ "mocha": "^10.2.0",
"nyc": "^14.1.1",
"playwright": "^1.30.0",
- "rollup": "^2.38.5",
- "rollup-plugin-terser": "^7.0.2",
+ "rollup": "^2.79.1",
"sinon": "^4.3.0",
+ "ts-node": "^10.9.1",
"typescript": "^4.1.2",
"web-streams-polyfill": "^3.2.0"
},
@@ -59,70 +60,108 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
- "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "version": "7.21.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
+ "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.8.3"
+ "@babel/highlight": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/generator": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz",
- "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==",
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz",
+ "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.9.6",
- "jsesc": "^2.5.1",
- "lodash": "^4.17.13",
- "source-map": "^0.5.0"
+ "@babel/types": "^7.21.5",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-environment-visitor": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz",
+ "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.9.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
- "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+ "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
"dev": true,
"dependencies": {
- "@babel/helper-get-function-arity": "^7.8.3",
- "@babel/template": "^7.8.3",
- "@babel/types": "^7.9.5"
+ "@babel/template": "^7.20.7",
+ "@babel/types": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
- "node_modules/@babel/helper-get-function-arity": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
- "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.8.3"
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
- "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.8.3"
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz",
+ "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.9.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
- "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
- "dev": true
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
},
"node_modules/@babel/highlight": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
- "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"dev": true,
"dependencies": {
+ "@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
- "esutils": "^2.0.2",
"js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/highlight/node_modules/ansi-styles": {
@@ -151,12 +190,6 @@
"node": ">=4"
}
},
- "node_modules/@babel/highlight/node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
"node_modules/@babel/highlight/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -170,9 +203,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz",
- "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==",
+ "version": "7.21.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz",
+ "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -209,31 +242,38 @@
}
},
"node_modules/@babel/template": {
- "version": "7.8.6",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
- "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
+ "version": "7.20.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+ "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.8.3",
- "@babel/parser": "^7.8.6",
- "@babel/types": "^7.8.6"
+ "@babel/code-frame": "^7.18.6",
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz",
- "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.8.3",
- "@babel/generator": "^7.9.6",
- "@babel/helper-function-name": "^7.9.5",
- "@babel/helper-split-export-declaration": "^7.8.3",
- "@babel/parser": "^7.9.6",
- "@babel/types": "^7.9.6",
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz",
+ "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.21.4",
+ "@babel/generator": "^7.21.5",
+ "@babel/helper-environment-visitor": "^7.21.5",
+ "@babel/helper-function-name": "^7.21.0",
+ "@babel/helper-hoist-variables": "^7.18.6",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/parser": "^7.21.5",
+ "@babel/types": "^7.21.5",
"debug": "^4.1.0",
- "globals": "^11.1.0",
- "lodash": "^4.17.13"
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@babel/traverse/node_modules/debug": {
@@ -253,14 +293,17 @@
"dev": true
},
"node_modules/@babel/types": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz",
- "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==",
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz",
+ "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.9.5",
- "lodash": "^4.17.13",
+ "@babel/helper-string-parser": "^7.21.5",
+ "@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@colors/colors": {
@@ -272,6 +315,28 @@
"node": ">=0.1.90"
}
},
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
@@ -546,31 +611,32 @@
}
},
"node_modules/@openpgp/jsdoc": {
- "version": "3.6.4",
- "resolved": "https://registry.npmjs.org/@openpgp/jsdoc/-/jsdoc-3.6.4.tgz",
- "integrity": "sha512-PR4NtdOVev7wbUYe4/T0CeLDAr0qxDthBqUrqngKIHn6h+m9fgRz20vH5OBalIVYaDeHcUcxdwGbEFRT30/WSg==",
+ "version": "3.6.11",
+ "resolved": "https://registry.npmjs.org/@openpgp/jsdoc/-/jsdoc-3.6.11.tgz",
+ "integrity": "sha512-mwvKQrW9raTU4CM3Oa93deRPh3TknFL0PUaGJWXwk3Inqf5nT8x4Z867ctqKYPekqw9FdDGyTaGb4rkbyPl9fA==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.9.4",
+ "@types/markdown-it": "^12.2.3",
"bluebird": "^3.7.2",
- "catharsis": "^0.8.11",
+ "catharsis": "^0.9.0",
"escape-string-regexp": "^2.0.0",
- "js2xmlparser": "^4.0.1",
+ "js2xmlparser": "^4.0.2",
"klaw": "^3.0.0",
- "markdown-it": "^10.0.0",
- "markdown-it-anchor": "^5.2.7",
- "marked": "^0.8.2",
+ "markdown-it": "^12.3.2",
+ "markdown-it-anchor": "^8.4.1",
+ "marked": "^4.0.10",
"mkdirp": "^1.0.4",
"requizzle": "^0.2.3",
"strip-json-comments": "^3.1.0",
"taffydb": "2.6.2",
- "underscore": "~1.10.2"
+ "underscore": "~1.13.2"
},
"bin": {
"jsdoc": "jsdoc.js"
},
"engines": {
- "node": ">=8.15.0"
+ "node": ">=12.0.0"
}
},
"node_modules/@openpgp/jsdoc/node_modules/escape-string-regexp": {
@@ -620,9 +686,9 @@
"dev": true
},
"node_modules/@openpgp/web-stream-tools": {
- "version": "0.0.13",
- "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.13.tgz",
- "integrity": "sha512-VQ0O0lUcD9ilLcMLQMJMgPhp8fDgMd4copd+UhSBGjud0vbI1ONQ3ffAhixEMml/AApLJtqCpd7PJcccPliFSA==",
+ "version": "0.0.14",
+ "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.14.tgz",
+ "integrity": "sha512-6btCNVf6YSsmlyIS7yw+IbzXeXCEcJxeSpxvSxkDuZj9B/ekt4fXkZj4oOaIxG4SKTftIK1svnlVroJ1cCMT4g==",
"dev": true,
"peerDependencies": {
"typescript": ">=4.2"
@@ -633,72 +699,199 @@
}
}
},
+ "node_modules/@rollup/plugin-alias": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.0.0.tgz",
+ "integrity": "sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==",
+ "dev": true,
+ "dependencies": {
+ "slash": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rollup/plugin-commonjs": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.1.0.tgz",
- "integrity": "sha512-Ycr12N3ZPN96Fw2STurD21jMqzKwL9QuFhms3SD7KKRK7oaXUsBU9Zt0jL/rOPHiPYisI21/rXGO3jr9BnLHUA==",
+ "version": "24.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz",
+ "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==",
"dev": true,
"dependencies": {
- "@rollup/pluginutils": "^3.0.8",
+ "@rollup/pluginutils": "^5.0.1",
"commondir": "^1.0.1",
- "estree-walker": "^1.0.1",
- "glob": "^7.1.2",
- "is-reference": "^1.1.2",
- "magic-string": "^0.25.2",
- "resolve": "^1.11.0"
+ "estree-walker": "^2.0.2",
+ "glob": "^8.0.3",
+ "is-reference": "1.2.1",
+ "magic-string": "^0.27.0"
},
"engines": {
- "node": ">= 8.0.0"
+ "node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^1.20.0||^2.0.0"
+ "rollup": "^2.68.0||^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@rollup/plugin-commonjs/node_modules/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
}
},
"node_modules/@rollup/plugin-node-resolve": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
- "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==",
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz",
+ "integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==",
"dev": true,
"dependencies": {
- "@rollup/pluginutils": "^3.0.8",
- "@types/resolve": "0.0.8",
- "builtin-modules": "^3.1.0",
+ "@rollup/pluginutils": "^5.0.1",
+ "@types/resolve": "1.20.2",
+ "deepmerge": "^4.2.2",
+ "is-builtin-module": "^3.2.1",
"is-module": "^1.0.0",
- "resolve": "^1.14.2"
+ "resolve": "^1.22.1"
},
"engines": {
- "node": ">= 8.0.0"
+ "node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^1.20.0||^2.0.0"
+ "rollup": "^2.78.0||^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
}
},
"node_modules/@rollup/plugin-node-resolve/node_modules/builtin-modules": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
- "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@rollup/plugin-node-resolve/node_modules/is-builtin-module": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
"dev": true,
+ "dependencies": {
+ "builtin-modules": "^3.3.0"
+ },
"engines": {
"node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@rollup/plugin-replace": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.2.tgz",
- "integrity": "sha512-KEEL7V2tMNOsbAoNMKg91l1sNXBDoiP31GFlqXVOuV5691VQKzKBh91+OKKOG4uQWYqcFskcjFyh1d5YnZd0Zw==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz",
+ "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "magic-string": "^0.27.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-terser": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.1.tgz",
+ "integrity": "sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==",
"dev": true,
"dependencies": {
- "@rollup/pluginutils": "^3.0.8",
- "magic-string": "^0.25.5"
+ "serialize-javascript": "^6.0.0",
+ "smob": "^0.0.6",
+ "terser": "^5.15.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^1.20.0 || ^2.0.0"
+ "rollup": "^2.x || ^3.x"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-terser/node_modules/serialize-javascript": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
+ "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
}
},
"node_modules/@rollup/plugin-wasm": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.1.2.tgz",
- "integrity": "sha512-YdrQ7zfnZ54Y+6raCev3tR1PrhQGxYKSTajGylhyP0oBacouuNo6KcNCk+pYKw9M98jxRWLFFca/udi76IDXzg==",
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.1.3.tgz",
+ "integrity": "sha512-7ItTTeyauE6lwdDtQWceEHZ9+txbi4RRy0mYPFn9BW7rD7YdgBDu7HTHsLtHrRzJc313RM/1m6GKgV3np/aEaw==",
"dev": true,
"engines": {
"node": ">=14.0.0"
@@ -713,40 +906,36 @@
}
},
"node_modules/@rollup/pluginutils": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.9.tgz",
- "integrity": "sha512-TLZavlfPAZYI7v33wQh4mTP6zojne14yok3DNSLcjoG/Hirxfkonn6icP5rrNWRn8nZsirJBFFpijVOJzkUHDg==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
+ "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
"dev": true,
"dependencies": {
- "@types/estree": "0.0.39",
- "estree-walker": "^1.0.1",
- "micromatch": "^4.0.2"
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^2.3.1"
},
"engines": {
- "node": ">= 8.0.0"
+ "node": ">=14.0.0"
},
"peerDependencies": {
- "rollup": "^1.20.0||^2.0.0"
+ "rollup": "^1.20.0||^2.0.0||^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
}
},
"node_modules/@sinonjs/commons": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz",
- "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==",
+ "version": "1.8.6",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
+ "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
"dev": true,
"dependencies": {
"type-detect": "4.0.8"
}
},
- "node_modules/@sinonjs/commons/node_modules/type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@sinonjs/formatio": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
@@ -768,9 +957,9 @@
}
},
"node_modules/@sinonjs/text-encoding": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
- "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
+ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==",
"dev": true
},
"node_modules/@socket.io/component-emitter": {
@@ -779,10 +968,34 @@
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==",
"dev": true
},
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
+ "dev": true
+ },
"node_modules/@types/chai": {
- "version": "4.2.14",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz",
- "integrity": "sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==",
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
+ "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==",
"dev": true
},
"node_modules/@types/cookie": {
@@ -801,9 +1014,9 @@
}
},
"node_modules/@types/estree": {
- "version": "0.0.39",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
- "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
+ "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
"dev": true
},
"node_modules/@types/json5": {
@@ -812,6 +1025,28 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
+ "node_modules/@types/linkify-it": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
+ "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
+ "dev": true
+ },
+ "node_modules/@types/markdown-it": {
+ "version": "12.2.3",
+ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
+ "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/linkify-it": "*",
+ "@types/mdurl": "*"
+ }
+ },
+ "node_modules/@types/mdurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
+ "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
+ "dev": true
+ },
"node_modules/@types/node": {
"version": "13.13.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz",
@@ -819,18 +1054,9 @@
"dev": true
},
"node_modules/@types/resolve": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
- "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
- "dev": true,
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@ungap/promise-all-settled": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
- "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"dev": true
},
"node_modules/accepts": {
@@ -867,6 +1093,15 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
@@ -941,9 +1176,9 @@
}
},
"node_modules/anymatch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
- "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
@@ -971,6 +1206,12 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
"node_modules/argon2id": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/argon2id/-/argon2id-1.0.1.tgz",
@@ -1003,7 +1244,7 @@
"node_modules/array-from": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
- "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=",
+ "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==",
"dev": true
},
"node_modules/array-includes": {
@@ -1397,26 +1638,26 @@
}
},
"node_modules/catharsis": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
- "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+ "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
"dev": true,
"dependencies": {
- "lodash": "^4.17.14"
+ "lodash": "^4.17.15"
},
"engines": {
- "node": ">= 8"
+ "node": ">= 10"
}
},
"node_modules/chai": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
- "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+ "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
"dev": true,
"dependencies": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
- "deep-eql": "^3.0.1",
+ "deep-eql": "^4.1.2",
"get-func-name": "^2.0.0",
"loupe": "^2.3.1",
"pathval": "^1.1.1",
@@ -1457,31 +1698,37 @@
"node_modules/check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
- "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
"dev": true,
"engines": {
"node": "*"
}
},
"node_modules/chokidar": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
- "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
"dependencies": {
- "anymatch": "~3.1.1",
+ "anymatch": "~3.1.2",
"braces": "~3.0.2",
- "glob-parent": "~5.1.0",
+ "glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
- "readdirp": "~3.5.0"
+ "readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"optionalDependencies": {
- "fsevents": "~2.3.1"
+ "fsevents": "~2.3.2"
}
},
"node_modules/ci-info": {
@@ -1677,6 +1924,12 @@
"node": ">=6"
}
},
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -1747,15 +2000,15 @@
}
},
"node_modules/deep-eql": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
- "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+ "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
"dev": true,
"dependencies": {
"type-detect": "^4.0.0"
},
"engines": {
- "node": ">=0.12"
+ "node": ">=6"
}
},
"node_modules/deep-is": {
@@ -1764,6 +2017,15 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/default-require-extensions": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
@@ -1933,10 +2195,13 @@
"dev": true
},
"node_modules/entities": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
- "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
- "dev": true
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
},
"node_modules/error-ex": {
"version": "1.3.1",
@@ -2590,15 +2855,6 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
- "node_modules/esm": {
- "version": "3.2.25",
- "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
- "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/espree": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
@@ -2672,9 +2928,9 @@
}
},
"node_modules/estree-walker": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
- "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"node_modules/esutils": {
@@ -3075,7 +3331,7 @@
"node_modules/get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true,
"engines": {
"node": "*"
@@ -3185,15 +3441,6 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
- "node_modules/growl": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
- "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
- "dev": true,
- "engines": {
- "node": ">=4.x"
- }
- },
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -3710,12 +3957,12 @@
}
},
"node_modules/is-reference": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz",
- "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+ "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dev": true,
"dependencies": {
- "@types/estree": "0.0.39"
+ "@types/estree": "*"
}
},
"node_modules/is-regex": {
@@ -3791,6 +4038,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-weakref": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
@@ -3815,6 +4074,12 @@
"node": ">=8"
}
},
+ "node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+ "dev": true
+ },
"node_modules/isbinaryfile": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz",
@@ -3972,20 +4237,6 @@
"node": ">=6"
}
},
- "node_modules/jest-worker": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
- "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
- "dev": true,
- "dependencies": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^7.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
"node_modules/js-sdsl": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
@@ -3997,11 +4248,10 @@
}
},
"node_modules/js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true,
- "peer": true
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
},
"node_modules/js-yaml": {
"version": "3.13.1",
@@ -4017,12 +4267,12 @@
}
},
"node_modules/js2xmlparser": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz",
- "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+ "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
"dev": true,
"dependencies": {
- "xmlcreate": "^2.0.3"
+ "xmlcreate": "^2.0.4"
}
},
"node_modules/jsesc": {
@@ -4093,6 +4343,12 @@
"node": ">=4.0"
}
},
+ "node_modules/just-extend": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
+ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==",
+ "dev": true
+ },
"node_modules/karma": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz",
@@ -4445,9 +4701,9 @@
}
},
"node_modules/linkify-it": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
- "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
"dev": true,
"dependencies": {
"uc.micro": "^1.0.1"
@@ -4483,7 +4739,7 @@
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
"dev": true
},
"node_modules/lodash.merge": {
@@ -4582,9 +4838,9 @@
"dev": true
},
"node_modules/lolex": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz",
- "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==",
+ "version": "2.7.5",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz",
+ "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==",
"dev": true
},
"node_modules/loose-envify": {
@@ -4601,21 +4857,24 @@
}
},
"node_modules/loupe": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
- "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==",
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+ "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
"dev": true,
"dependencies": {
"get-func-name": "^2.0.0"
}
},
"node_modules/magic-string": {
- "version": "0.25.7",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
- "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
+ "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==",
"dev": true,
"dependencies": {
- "sourcemap-codec": "^1.4.4"
+ "@jridgewell/sourcemap-codec": "^1.4.13"
+ },
+ "engines": {
+ "node": ">=12"
}
},
"node_modules/make-dir": {
@@ -4649,6 +4908,12 @@
"semver": "bin/semver"
}
},
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
"node_modules/map-stream": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
@@ -4656,14 +4921,14 @@
"dev": true
},
"node_modules/markdown-it": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
- "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"dev": true,
"dependencies": {
- "argparse": "^1.0.7",
- "entities": "~2.0.0",
- "linkify-it": "^2.0.0",
+ "argparse": "^2.0.1",
+ "entities": "~2.1.0",
+ "linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
@@ -4672,30 +4937,37 @@
}
},
"node_modules/markdown-it-anchor": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz",
- "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==",
+ "version": "8.6.7",
+ "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
+ "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
"dev": true,
"peerDependencies": {
+ "@types/markdown-it": "*",
"markdown-it": "*"
}
},
+ "node_modules/markdown-it/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
"node_modules/marked": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
- "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"bin": {
- "marked": "bin/marked"
+ "marked": "bin/marked.js"
},
"engines": {
- "node": ">= 8.16.2"
+ "node": ">= 12"
}
},
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
- "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
"dev": true
},
"node_modules/media-typer": {
@@ -4725,25 +4997,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
- },
- "node_modules/micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "dev": true,
- "dependencies": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
@@ -4822,43 +5075,39 @@
}
},
"node_modules/mocha": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
- "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+ "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
"dev": true,
"dependencies": {
- "@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
- "chokidar": "3.5.1",
- "debug": "4.3.1",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
- "glob": "7.1.6",
- "growl": "1.10.5",
+ "glob": "7.2.0",
"he": "1.2.0",
- "js-yaml": "4.0.0",
- "log-symbols": "4.0.0",
- "minimatch": "3.0.4",
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
"ms": "2.1.3",
- "nanoid": "3.1.20",
- "serialize-javascript": "5.0.1",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
- "which": "2.0.2",
- "wide-align": "1.1.3",
- "workerpool": "6.1.0",
+ "workerpool": "6.2.1",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
- "mocha": "bin/mocha"
+ "mocha": "bin/mocha.js"
},
"engines": {
- "node": ">= 10.12.0"
+ "node": ">= 14.0.0"
},
"funding": {
"type": "opencollective",
@@ -4883,9 +5132,9 @@
}
},
"node_modules/mocha/node_modules/debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
@@ -4933,9 +5182,9 @@
}
},
"node_modules/mocha/node_modules/glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -4983,9 +5232,9 @@
}
},
"node_modules/mocha/node_modules/js-yaml": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
- "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
@@ -4995,15 +5244,40 @@
}
},
"node_modules/mocha/node_modules/log-symbols": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
- "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"dependencies": {
- "chalk": "^4.0.0"
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
},
"engines": {
"node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mocha/node_modules/minimatch": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
}
},
"node_modules/mocha/node_modules/ms": {
@@ -5013,9 +5287,9 @@
"dev": true
},
"node_modules/mocha/node_modules/serialize-javascript": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
- "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0"
@@ -5050,21 +5324,6 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "node_modules/mocha/node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/mocha/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -5125,9 +5384,9 @@
"dev": true
},
"node_modules/nanoid": {
- "version": "3.1.20",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
- "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"dev": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
@@ -5180,12 +5439,6 @@
"@sinonjs/samsam": "^3.1.0"
}
},
- "node_modules/nise/node_modules/just-extend": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz",
- "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==",
- "dev": true
- },
"node_modules/nise/node_modules/lolex": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz",
@@ -5607,20 +5860,14 @@
"dev": true
},
"node_modules/path-to-regexp": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
- "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dev": true,
"dependencies": {
"isarray": "0.0.1"
}
},
- "node_modules/path-to-regexp/node_modules/isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
"node_modules/pathval": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
@@ -5640,9 +5887,9 @@
}
},
"node_modules/picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
@@ -5872,9 +6119,9 @@
"peer": true
},
"node_modules/readdirp": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
- "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"dependencies": {
"picomatch": "^2.2.1"
@@ -6019,9 +6266,9 @@
}
},
"node_modules/rollup": {
- "version": "2.38.5",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.38.5.tgz",
- "integrity": "sha512-VoWt8DysFGDVRGWuHTqZzT02J0ASgjVq/hPs9QcBOGMd7B+jfTr/iqMVEyOi901rE3xq+Deq66GzIT1yt7sGwQ==",
+ "version": "2.79.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
+ "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -6030,101 +6277,7 @@
"node": ">=10.0.0"
},
"optionalDependencies": {
- "fsevents": "~2.3.1"
- }
- },
- "node_modules/rollup-plugin-terser": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
- "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.10.4",
- "jest-worker": "^26.2.1",
- "serialize-javascript": "^4.0.0",
- "terser": "^5.0.0"
- },
- "peerDependencies": {
- "rollup": "^2.0.0"
- }
- },
- "node_modules/rollup-plugin-terser/node_modules/@babel/code-frame": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
- "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/rollup-plugin-terser/node_modules/@babel/helper-validator-identifier": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
- "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/rollup-plugin-terser/node_modules/@babel/highlight": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
- "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.14.5",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/rollup-plugin-terser/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/rollup-plugin-terser/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/rollup-plugin-terser/node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "node_modules/rollup-plugin-terser/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
+ "fsevents": "~2.3.2"
}
},
"node_modules/run-parallel": {
@@ -6198,15 +6351,6 @@
"semver": "bin/semver"
}
},
- "node_modules/serialize-javascript": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
- "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
- "dev": true,
- "dependencies": {
- "randombytes": "^2.1.0"
- }
- },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -6261,10 +6405,11 @@
"dev": true
},
"node_modules/sinon": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.3.0.tgz",
- "integrity": "sha512-pmf05hFgEZUS52AGJcsVjOjqAyJW2yo14cOwVYvzCyw7+inv06YXkLyW75WG6X6p951lzkoKh51L2sNbR9CDvw==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz",
+ "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==",
"dev": true,
+ "hasInstallScript": true,
"dependencies": {
"@sinonjs/formatio": "^2.0.0",
"diff": "^3.1.0",
@@ -6276,9 +6421,9 @@
}
},
"node_modules/sinon/node_modules/supports-color": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz",
- "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==",
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
@@ -6287,6 +6432,24 @@
"node": ">=4"
}
},
+ "node_modules/slash": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+ "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/smob": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/smob/-/smob-0.0.6.tgz",
+ "integrity": "sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==",
+ "dev": true
+ },
"node_modules/socket.io": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.0.tgz",
@@ -6372,15 +6535,6 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
- "node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
@@ -6400,12 +6554,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/sourcemap-codec": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
- "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
- "dev": true
- },
"node_modules/spawn-wrap": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz",
@@ -6932,6 +7080,58 @@
"node": ">=0.6"
}
},
+ "node_modules/ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ts-node/node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -6957,9 +7157,9 @@
}
},
"node_modules/type-detect": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz",
- "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true,
"engines": {
"node": ">=4"
@@ -7044,9 +7244,9 @@
}
},
"node_modules/underscore": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
- "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==",
+ "version": "1.13.6",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
+ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
"dev": true
},
"node_modules/union": {
@@ -7113,6 +7313,12 @@
"uuid": "bin/uuid"
}
},
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
"node_modules/validate-npm-package-license": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
@@ -7208,49 +7414,6 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
- "node_modules/wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "dev": true,
- "dependencies": {
- "string-width": "^1.0.2 || 2"
- }
- },
- "node_modules/wide-align/node_modules/ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/wide-align/node_modules/string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "dependencies": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/wide-align/node_modules/strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -7261,9 +7424,9 @@
}
},
"node_modules/workerpool": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz",
- "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
"dev": true
},
"node_modules/wrap-ansi": {
@@ -7341,9 +7504,9 @@
}
},
"node_modules/xmlcreate": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz",
- "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
"dev": true
},
"node_modules/y18n": {
@@ -7495,6 +7658,15 @@
"node": ">=4"
}
},
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -7510,69 +7682,80 @@
},
"dependencies": {
"@babel/code-frame": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
- "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "version": "7.21.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
+ "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.8.3"
+ "@babel/highlight": "^7.18.6"
}
},
"@babel/generator": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz",
- "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==",
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz",
+ "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==",
"dev": true,
"requires": {
- "@babel/types": "^7.9.6",
- "jsesc": "^2.5.1",
- "lodash": "^4.17.13",
- "source-map": "^0.5.0"
+ "@babel/types": "^7.21.5",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
}
},
+ "@babel/helper-environment-visitor": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz",
+ "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==",
+ "dev": true
+ },
"@babel/helper-function-name": {
- "version": "7.9.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
- "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+ "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
"dev": true,
"requires": {
- "@babel/helper-get-function-arity": "^7.8.3",
- "@babel/template": "^7.8.3",
- "@babel/types": "^7.9.5"
+ "@babel/template": "^7.20.7",
+ "@babel/types": "^7.21.0"
}
},
- "@babel/helper-get-function-arity": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
- "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+ "@babel/helper-hoist-variables": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"dev": true,
"requires": {
- "@babel/types": "^7.8.3"
+ "@babel/types": "^7.18.6"
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
- "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"dev": true,
"requires": {
- "@babel/types": "^7.8.3"
+ "@babel/types": "^7.18.6"
}
},
+ "@babel/helper-string-parser": {
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz",
+ "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==",
+ "dev": true
+ },
"@babel/helper-validator-identifier": {
- "version": "7.9.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
- "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"dev": true
},
"@babel/highlight": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
- "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"dev": true,
"requires": {
+ "@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
- "esutils": "^2.0.2",
"js-tokens": "^4.0.0"
},
"dependencies": {
@@ -7596,12 +7779,6 @@
"supports-color": "^5.3.0"
}
},
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -7614,9 +7791,9 @@
}
},
"@babel/parser": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz",
- "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==",
+ "version": "7.21.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz",
+ "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==",
"dev": true
},
"@babel/runtime": {
@@ -7641,31 +7818,32 @@
}
},
"@babel/template": {
- "version": "7.8.6",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
- "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
+ "version": "7.20.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+ "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.8.3",
- "@babel/parser": "^7.8.6",
- "@babel/types": "^7.8.6"
+ "@babel/code-frame": "^7.18.6",
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7"
}
},
"@babel/traverse": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz",
- "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.8.3",
- "@babel/generator": "^7.9.6",
- "@babel/helper-function-name": "^7.9.5",
- "@babel/helper-split-export-declaration": "^7.8.3",
- "@babel/parser": "^7.9.6",
- "@babel/types": "^7.9.6",
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz",
+ "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.21.4",
+ "@babel/generator": "^7.21.5",
+ "@babel/helper-environment-visitor": "^7.21.5",
+ "@babel/helper-function-name": "^7.21.0",
+ "@babel/helper-hoist-variables": "^7.18.6",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/parser": "^7.21.5",
+ "@babel/types": "^7.21.5",
"debug": "^4.1.0",
- "globals": "^11.1.0",
- "lodash": "^4.17.13"
+ "globals": "^11.1.0"
},
"dependencies": {
"debug": {
@@ -7686,13 +7864,13 @@
}
},
"@babel/types": {
- "version": "7.9.6",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz",
- "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==",
+ "version": "7.21.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz",
+ "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.9.5",
- "lodash": "^4.17.13",
+ "@babel/helper-string-parser": "^7.21.5",
+ "@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0"
}
},
@@ -7702,6 +7880,27 @@
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
"dev": true
},
+ "@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "dependencies": {
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ }
+ }
+ },
"@eslint/eslintrc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
@@ -7915,25 +8114,26 @@
}
},
"@openpgp/jsdoc": {
- "version": "3.6.4",
- "resolved": "https://registry.npmjs.org/@openpgp/jsdoc/-/jsdoc-3.6.4.tgz",
- "integrity": "sha512-PR4NtdOVev7wbUYe4/T0CeLDAr0qxDthBqUrqngKIHn6h+m9fgRz20vH5OBalIVYaDeHcUcxdwGbEFRT30/WSg==",
+ "version": "3.6.11",
+ "resolved": "https://registry.npmjs.org/@openpgp/jsdoc/-/jsdoc-3.6.11.tgz",
+ "integrity": "sha512-mwvKQrW9raTU4CM3Oa93deRPh3TknFL0PUaGJWXwk3Inqf5nT8x4Z867ctqKYPekqw9FdDGyTaGb4rkbyPl9fA==",
"dev": true,
"requires": {
"@babel/parser": "^7.9.4",
+ "@types/markdown-it": "^12.2.3",
"bluebird": "^3.7.2",
- "catharsis": "^0.8.11",
+ "catharsis": "^0.9.0",
"escape-string-regexp": "^2.0.0",
- "js2xmlparser": "^4.0.1",
+ "js2xmlparser": "^4.0.2",
"klaw": "^3.0.0",
- "markdown-it": "^10.0.0",
- "markdown-it-anchor": "^5.2.7",
- "marked": "^0.8.2",
+ "markdown-it": "^12.3.2",
+ "markdown-it-anchor": "^8.4.1",
+ "marked": "^4.0.10",
"mkdirp": "^1.0.4",
"requizzle": "^0.2.3",
"strip-json-comments": "^3.1.0",
"taffydb": "2.6.2",
- "underscore": "~1.10.2"
+ "underscore": "~1.13.2"
},
"dependencies": {
"escape-string-regexp": {
@@ -7972,91 +8172,156 @@
"dev": true
},
"@openpgp/web-stream-tools": {
- "version": "0.0.13",
- "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.13.tgz",
- "integrity": "sha512-VQ0O0lUcD9ilLcMLQMJMgPhp8fDgMd4copd+UhSBGjud0vbI1ONQ3ffAhixEMml/AApLJtqCpd7PJcccPliFSA==",
+ "version": "0.0.14",
+ "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.14.tgz",
+ "integrity": "sha512-6btCNVf6YSsmlyIS7yw+IbzXeXCEcJxeSpxvSxkDuZj9B/ekt4fXkZj4oOaIxG4SKTftIK1svnlVroJ1cCMT4g==",
"dev": true,
"requires": {}
},
+ "@rollup/plugin-alias": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.0.0.tgz",
+ "integrity": "sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==",
+ "dev": true,
+ "requires": {
+ "slash": "^4.0.0"
+ }
+ },
"@rollup/plugin-commonjs": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.1.0.tgz",
- "integrity": "sha512-Ycr12N3ZPN96Fw2STurD21jMqzKwL9QuFhms3SD7KKRK7oaXUsBU9Zt0jL/rOPHiPYisI21/rXGO3jr9BnLHUA==",
+ "version": "24.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz",
+ "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==",
"dev": true,
"requires": {
- "@rollup/pluginutils": "^3.0.8",
+ "@rollup/pluginutils": "^5.0.1",
"commondir": "^1.0.1",
- "estree-walker": "^1.0.1",
- "glob": "^7.1.2",
- "is-reference": "^1.1.2",
- "magic-string": "^0.25.2",
- "resolve": "^1.11.0"
+ "estree-walker": "^2.0.2",
+ "glob": "^8.0.3",
+ "is-reference": "1.2.1",
+ "magic-string": "^0.27.0"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ }
+ },
+ "minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ }
}
},
"@rollup/plugin-node-resolve": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
- "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==",
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz",
+ "integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==",
"dev": true,
"requires": {
- "@rollup/pluginutils": "^3.0.8",
- "@types/resolve": "0.0.8",
- "builtin-modules": "^3.1.0",
+ "@rollup/pluginutils": "^5.0.1",
+ "@types/resolve": "1.20.2",
+ "deepmerge": "^4.2.2",
+ "is-builtin-module": "^3.2.1",
"is-module": "^1.0.0",
- "resolve": "^1.14.2"
+ "resolve": "^1.22.1"
},
"dependencies": {
"builtin-modules": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
- "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"dev": true
+ },
+ "is-builtin-module": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+ "dev": true,
+ "requires": {
+ "builtin-modules": "^3.3.0"
+ }
}
}
},
"@rollup/plugin-replace": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.2.tgz",
- "integrity": "sha512-KEEL7V2tMNOsbAoNMKg91l1sNXBDoiP31GFlqXVOuV5691VQKzKBh91+OKKOG4uQWYqcFskcjFyh1d5YnZd0Zw==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz",
+ "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==",
"dev": true,
"requires": {
- "@rollup/pluginutils": "^3.0.8",
- "magic-string": "^0.25.5"
+ "@rollup/pluginutils": "^5.0.1",
+ "magic-string": "^0.27.0"
+ }
+ },
+ "@rollup/plugin-terser": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.1.tgz",
+ "integrity": "sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==",
+ "dev": true,
+ "requires": {
+ "serialize-javascript": "^6.0.0",
+ "smob": "^0.0.6",
+ "terser": "^5.15.1"
+ },
+ "dependencies": {
+ "serialize-javascript": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
+ "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ }
}
},
"@rollup/plugin-wasm": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.1.2.tgz",
- "integrity": "sha512-YdrQ7zfnZ54Y+6raCev3tR1PrhQGxYKSTajGylhyP0oBacouuNo6KcNCk+pYKw9M98jxRWLFFca/udi76IDXzg==",
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-wasm/-/plugin-wasm-6.1.3.tgz",
+ "integrity": "sha512-7ItTTeyauE6lwdDtQWceEHZ9+txbi4RRy0mYPFn9BW7rD7YdgBDu7HTHsLtHrRzJc313RM/1m6GKgV3np/aEaw==",
"dev": true,
"requires": {}
},
"@rollup/pluginutils": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.9.tgz",
- "integrity": "sha512-TLZavlfPAZYI7v33wQh4mTP6zojne14yok3DNSLcjoG/Hirxfkonn6icP5rrNWRn8nZsirJBFFpijVOJzkUHDg==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
+ "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
"dev": true,
"requires": {
- "@types/estree": "0.0.39",
- "estree-walker": "^1.0.1",
- "micromatch": "^4.0.2"
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^2.3.1"
}
},
"@sinonjs/commons": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz",
- "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==",
+ "version": "1.8.6",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
+ "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
- },
- "dependencies": {
- "type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true
- }
}
},
"@sinonjs/formatio": {
@@ -8080,9 +8345,9 @@
}
},
"@sinonjs/text-encoding": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
- "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
+ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==",
"dev": true
},
"@socket.io/component-emitter": {
@@ -8091,10 +8356,34 @@
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==",
"dev": true
},
+ "@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
+ "dev": true
+ },
"@types/chai": {
- "version": "4.2.14",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz",
- "integrity": "sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==",
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
+ "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==",
"dev": true
},
"@types/cookie": {
@@ -8113,9 +8402,9 @@
}
},
"@types/estree": {
- "version": "0.0.39",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
- "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
+ "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
"dev": true
},
"@types/json5": {
@@ -8124,6 +8413,28 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
+ "@types/linkify-it": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
+ "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
+ "dev": true
+ },
+ "@types/markdown-it": {
+ "version": "12.2.3",
+ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
+ "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==",
+ "dev": true,
+ "requires": {
+ "@types/linkify-it": "*",
+ "@types/mdurl": "*"
+ }
+ },
+ "@types/mdurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
+ "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
+ "dev": true
+ },
"@types/node": {
"version": "13.13.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz",
@@ -8131,18 +8442,9 @@
"dev": true
},
"@types/resolve": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
- "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "@ungap/promise-all-settled": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
- "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"dev": true
},
"accepts": {
@@ -8168,6 +8470,12 @@
"dev": true,
"requires": {}
},
+ "acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true
+ },
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
@@ -8222,9 +8530,9 @@
}
},
"anymatch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
- "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@@ -8246,6 +8554,12 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
"argon2id": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/argon2id/-/argon2id-1.0.1.tgz",
@@ -8275,7 +8589,7 @@
"array-from": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
- "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=",
+ "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==",
"dev": true
},
"array-includes": {
@@ -8595,23 +8909,23 @@
"dev": true
},
"catharsis": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
- "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+ "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
"dev": true,
"requires": {
- "lodash": "^4.17.14"
+ "lodash": "^4.17.15"
}
},
"chai": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
- "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+ "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
"dev": true,
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
- "deep-eql": "^3.0.1",
+ "deep-eql": "^4.1.2",
"get-func-name": "^2.0.0",
"loupe": "^2.3.1",
"pathval": "^1.1.1",
@@ -8640,23 +8954,23 @@
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
- "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
"dev": true
},
"chokidar": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
- "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"requires": {
- "anymatch": "~3.1.1",
+ "anymatch": "~3.1.2",
"braces": "~3.0.2",
- "fsevents": "~2.3.1",
- "glob-parent": "~5.1.0",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
- "readdirp": "~3.5.0"
+ "readdirp": "~3.6.0"
}
},
"ci-info": {
@@ -8812,6 +9126,12 @@
}
}
},
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -8869,9 +9189,9 @@
"dev": true
},
"deep-eql": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
- "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+ "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
"dev": true,
"requires": {
"type-detect": "^4.0.0"
@@ -8883,6 +9203,12 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
+ "deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true
+ },
"default-require-extensions": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
@@ -9019,9 +9345,9 @@
"dev": true
},
"entities": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
- "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
"dev": true
},
"error-ex": {
@@ -9535,12 +9861,6 @@
}
}
},
- "esm": {
- "version": "3.2.25",
- "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
- "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
- "dev": true
- },
"espree": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
@@ -9591,9 +9911,9 @@
"dev": true
},
"estree-walker": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
- "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"esutils": {
@@ -9912,7 +10232,7 @@
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true
},
"get-intrinsic": {
@@ -9994,12 +10314,6 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
- "growl": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
- "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
- "dev": true
- },
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -10381,12 +10695,12 @@
"dev": true
},
"is-reference": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz",
- "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+ "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dev": true,
"requires": {
- "@types/estree": "0.0.39"
+ "@types/estree": "*"
}
},
"is-regex": {
@@ -10438,6 +10752,12 @@
"has-symbols": "^1.0.2"
}
},
+ "is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true
+ },
"is-weakref": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
@@ -10456,6 +10776,12 @@
"is-docker": "^2.0.0"
}
},
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+ "dev": true
+ },
"isbinaryfile": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz",
@@ -10582,17 +10908,6 @@
"html-escaper": "^2.0.0"
}
},
- "jest-worker": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
- "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
- "dev": true,
- "requires": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^7.0.0"
- }
- },
"js-sdsl": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
@@ -10600,11 +10915,10 @@
"dev": true
},
"js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true,
- "peer": true
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
},
"js-yaml": {
"version": "3.13.1",
@@ -10617,12 +10931,12 @@
}
},
"js2xmlparser": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz",
- "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+ "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
"dev": true,
"requires": {
- "xmlcreate": "^2.0.3"
+ "xmlcreate": "^2.0.4"
}
},
"jsesc": {
@@ -10679,6 +10993,12 @@
"object.assign": "^4.1.3"
}
},
+ "just-extend": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
+ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==",
+ "dev": true
+ },
"karma": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz",
@@ -10968,9 +11288,9 @@
}
},
"linkify-it": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
- "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
"dev": true,
"requires": {
"uc.micro": "^1.0.1"
@@ -11000,7 +11320,7 @@
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
"dev": true
},
"lodash.merge": {
@@ -11080,9 +11400,9 @@
}
},
"lolex": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz",
- "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==",
+ "version": "2.7.5",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz",
+ "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==",
"dev": true
},
"loose-envify": {
@@ -11096,21 +11416,21 @@
}
},
"loupe": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
- "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==",
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+ "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
"dev": true,
"requires": {
"get-func-name": "^2.0.0"
}
},
"magic-string": {
- "version": "0.25.7",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
- "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
+ "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==",
"dev": true,
"requires": {
- "sourcemap-codec": "^1.4.4"
+ "@jridgewell/sourcemap-codec": "^1.4.13"
}
},
"make-dir": {
@@ -11137,6 +11457,12 @@
}
}
},
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
"map-stream": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
@@ -11144,35 +11470,43 @@
"dev": true
},
"markdown-it": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
- "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"dev": true,
"requires": {
- "argparse": "^1.0.7",
- "entities": "~2.0.0",
- "linkify-it": "^2.0.0",
+ "argparse": "^2.0.1",
+ "entities": "~2.1.0",
+ "linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
+ },
+ "dependencies": {
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ }
}
},
"markdown-it-anchor": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz",
- "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==",
+ "version": "8.6.7",
+ "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
+ "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
"dev": true,
"requires": {}
},
"marked": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
- "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true
},
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
- "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
"dev": true
},
"media-typer": {
@@ -11198,22 +11532,6 @@
}
}
},
- "merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
- },
- "micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "dev": true,
- "requires": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- }
- },
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
@@ -11271,33 +11589,29 @@
}
},
"mocha": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
- "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+ "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
"dev": true,
"requires": {
- "@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
- "chokidar": "3.5.1",
- "debug": "4.3.1",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
- "glob": "7.1.6",
- "growl": "1.10.5",
+ "glob": "7.2.0",
"he": "1.2.0",
- "js-yaml": "4.0.0",
- "log-symbols": "4.0.0",
- "minimatch": "3.0.4",
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
"ms": "2.1.3",
- "nanoid": "3.1.20",
- "serialize-javascript": "5.0.1",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
- "which": "2.0.2",
- "wide-align": "1.1.3",
- "workerpool": "6.1.0",
+ "workerpool": "6.2.1",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
@@ -11321,9 +11635,9 @@
}
},
"debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
@@ -11356,9 +11670,9 @@
"dev": true
},
"glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -11393,21 +11707,42 @@
"dev": true
},
"js-yaml": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
- "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
"argparse": "^2.0.1"
}
},
"log-symbols": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
- "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ }
+ },
+ "minimatch": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"dev": true,
"requires": {
- "chalk": "^4.0.0"
+ "brace-expansion": "^2.0.1"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ }
}
},
"ms": {
@@ -11417,9 +11752,9 @@
"dev": true
},
"serialize-javascript": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
- "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
@@ -11445,15 +11780,6 @@
"has-flag": "^4.0.0"
}
},
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -11501,9 +11827,9 @@
"dev": true
},
"nanoid": {
- "version": "3.1.20",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
- "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"dev": true
},
"natural-compare": {
@@ -11547,12 +11873,6 @@
"@sinonjs/samsam": "^3.1.0"
}
},
- "just-extend": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz",
- "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==",
- "dev": true
- },
"lolex": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz",
@@ -11872,20 +12192,12 @@
"dev": true
},
"path-to-regexp": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
- "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dev": true,
"requires": {
"isarray": "0.0.1"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- }
}
},
"pathval": {
@@ -11904,9 +12216,9 @@
}
},
"picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
},
"platform": {
@@ -12070,9 +12382,9 @@
"peer": true
},
"readdirp": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
- "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
@@ -12177,87 +12489,12 @@
}
},
"rollup": {
- "version": "2.38.5",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.38.5.tgz",
- "integrity": "sha512-VoWt8DysFGDVRGWuHTqZzT02J0ASgjVq/hPs9QcBOGMd7B+jfTr/iqMVEyOi901rE3xq+Deq66GzIT1yt7sGwQ==",
- "dev": true,
- "requires": {
- "fsevents": "~2.3.1"
- }
- },
- "rollup-plugin-terser": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
- "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
+ "version": "2.79.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
+ "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.10.4",
- "jest-worker": "^26.2.1",
- "serialize-javascript": "^4.0.0",
- "terser": "^5.0.0"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
- "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.14.5"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
- "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
- "dev": true
- },
- "@babel/highlight": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
- "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.5",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
+ "fsevents": "~2.3.2"
}
},
"run-parallel": {
@@ -12310,15 +12547,6 @@
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
},
- "serialize-javascript": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
- "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
- "dev": true,
- "requires": {
- "randombytes": "^2.1.0"
- }
- },
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -12364,9 +12592,9 @@
"dev": true
},
"sinon": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.3.0.tgz",
- "integrity": "sha512-pmf05hFgEZUS52AGJcsVjOjqAyJW2yo14cOwVYvzCyw7+inv06YXkLyW75WG6X6p951lzkoKh51L2sNbR9CDvw==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz",
+ "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==",
"dev": true,
"requires": {
"@sinonjs/formatio": "^2.0.0",
@@ -12379,9 +12607,9 @@
},
"dependencies": {
"supports-color": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz",
- "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==",
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
@@ -12389,6 +12617,18 @@
}
}
},
+ "slash": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+ "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+ "dev": true
+ },
+ "smob": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/smob/-/smob-0.0.6.tgz",
+ "integrity": "sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==",
+ "dev": true
+ },
"socket.io": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.0.tgz",
@@ -12456,12 +12696,6 @@
}
}
},
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
@@ -12480,12 +12714,6 @@
}
}
},
- "sourcemap-codec": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
- "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
- "dev": true
- },
"spawn-wrap": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz",
@@ -12901,6 +13129,35 @@
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"dev": true
},
+ "ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "dependencies": {
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ }
+ }
+ },
"tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -12923,9 +13180,9 @@
}
},
"type-detect": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz",
- "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true
},
"type-fest": {
@@ -12975,9 +13232,9 @@
}
},
"underscore": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
- "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==",
+ "version": "1.13.6",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
+ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
"dev": true
},
"union": {
@@ -13028,6 +13285,12 @@
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
},
+ "v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
"validate-npm-package-license": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
@@ -13104,42 +13367,6 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
- "wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "dev": true,
- "requires": {
- "string-width": "^1.0.2 || 2"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- }
- }
- },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -13147,9 +13374,9 @@
"dev": true
},
"workerpool": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz",
- "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
"dev": true
},
"wrap-ansi": {
@@ -13203,9 +13430,9 @@
"requires": {}
},
"xmlcreate": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz",
- "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
"dev": true
},
"y18n": {
@@ -13325,6 +13552,12 @@
}
}
},
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true
+ },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index b48b07fcc..a24d4c414 100644
--- a/package.json
+++ b/package.json
@@ -13,13 +13,26 @@
"gpg",
"openpgp"
],
- "main": "dist/node/openpgp.min.js",
+ "main": "dist/node/openpgp.min.cjs",
"module": "dist/node/openpgp.min.mjs",
"browser": {
- "./dist/node/openpgp.min.js": "./dist/openpgp.min.js",
+ "./dist/node/openpgp.min.cjs": "./dist/openpgp.min.js",
"./dist/node/openpgp.min.mjs": "./dist/openpgp.min.mjs"
},
+ "exports": {
+ ".": {
+ "types": "./openpgp.d.ts",
+ "import": "./dist/node/openpgp.mjs",
+ "require": "./dist/node/openpgp.min.cjs",
+ "browser": "./dist/openpgp.min.mjs"
+ },
+ "./lightweight": {
+ "types": "../openpgp.d.ts",
+ "browser": "./dist/lightweight/openpgp.min.mjs"
+ }
+ },
"types": "openpgp.d.ts",
+ "type": "module",
"directories": {
"lib": "src"
},
@@ -28,27 +41,22 @@
"lightweight/",
"openpgp.d.ts"
],
- "esm": {
- "cjs": {
- "dedefault": true
- }
- },
"scripts": {
"build": "rollup --config",
"build-test": "npm run build --build-only=test",
"prepare": "npm run build",
- "test": "mocha --require esm --timeout 120000 test/unittests.js",
- "test-type-definitions": "tsc test/typescript/definitions.ts && node test/typescript/definitions.js",
+ "test": "mocha --timeout 120000 test/unittests.js",
+ "test-type-definitions": "ts-node --esm test/typescript/definitions.ts",
"benchmark-time": "node test/benchmarks/time.js",
- "benchmark-memory-usage": "node --require esm test/benchmarks/memory_usage.js",
+ "benchmark-memory-usage": "node test/benchmarks/memory_usage.js",
"start": "http-server",
"prebrowsertest": "npm run build-test",
"browsertest": "npm start -- -o test/unittests.html",
- "test-browser": "karma start test/karma.conf.js",
- "test-browserstack": "karma start test/karma.conf.js --browsers bs_safari_latest,bs_ios_14,bs_safari_13_1",
+ "test-browser": "karma start test/karma.conf.cjs",
+ "test-browserstack": "karma start test/karma.conf.cjs --browsers bs_safari_latest,bs_ios_14,bs_safari_13_1",
"coverage": "nyc npm test",
"lint": "eslint .",
- "docs": "jsdoc --configure .jsdocrc.js --destination docs --recurse README.md src && printf '%s' 'docs.openpgpjs.org' > docs/CNAME",
+ "docs": "jsdoc --configure .jsdocrc.cjs --destination docs --recurse README.md src && printf '%s' 'docs.openpgpjs.org' > docs/CNAME",
"preversion": "rm -rf dist docs node_modules && npm ci && npm test",
"version": "npm run docs && git add -A docs",
"postversion": "git push && git push --tags && npm publish"
@@ -56,20 +64,22 @@
"devDependencies": {
"@openpgp/asmcrypto.js": "^2.3.2",
"@openpgp/elliptic": "^6.5.1",
- "@openpgp/jsdoc": "^3.6.4",
+ "@openpgp/jsdoc": "^3.6.11",
"@openpgp/pako": "^1.0.12",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
- "@openpgp/web-stream-tools": "^0.0.13",
- "@rollup/plugin-commonjs": "^11.1.0",
- "@rollup/plugin-node-resolve": "^7.1.3",
- "@rollup/plugin-replace": "^2.3.2",
+ "@openpgp/web-stream-tools": "^0.0.14",
+ "@rollup/plugin-alias": "^5.0.0",
+ "@rollup/plugin-commonjs": "^24.0.1",
+ "@rollup/plugin-node-resolve": "^15.0.1",
+ "@rollup/plugin-replace": "^5.0.2",
+ "@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-wasm": "^6.1.2",
"@types/chai": "^4.2.14",
"argon2id": "^1.0.1",
"benchmark": "^2.1.4",
"bn.js": "^4.11.8",
- "chai": "^4.3.6",
+ "chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"email-addresses": "3.1.0",
"eslint": "^8.34.0",
@@ -77,7 +87,6 @@
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
- "esm": "^3.2.25",
"hash.js": "^1.1.3",
"http-server": "^14.1.1",
"karma": "^6.4.0",
@@ -87,12 +96,12 @@
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-webkit-launcher": "^2.1.0",
- "mocha": "^8.4.0",
+ "mocha": "^10.2.0",
"nyc": "^14.1.1",
"playwright": "^1.30.0",
- "rollup": "^2.38.5",
- "rollup-plugin-terser": "^7.0.2",
+ "rollup": "^2.79.1",
"sinon": "^4.3.0",
+ "ts-node": "^10.9.1",
"typescript": "^4.1.2",
"web-streams-polyfill": "^3.2.0"
},
diff --git a/rollup.config.js b/rollup.config.js
index 97656497f..1d723d6f8 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -2,16 +2,18 @@
import { builtinModules } from 'module';
+import alias from '@rollup/plugin-alias';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
-import { terser } from 'rollup-plugin-terser';
+import terser from '@rollup/plugin-terser';
import { wasm } from '@rollup/plugin-wasm';
-
import pkg from './package.json';
const nodeDependencies = Object.keys(pkg.dependencies);
+const nodeBuiltinModules = builtinModules.concat(['module']);
+
const wasmOptions = {
node: { targetEnv: 'node' },
browser: { targetEnv: 'browser', maxFileSize: undefined } // always inlline (our wasm files are small)
@@ -47,6 +49,7 @@ const terserOptions = {
export default Object.assign([
{
input: 'src/index.js',
+ external: nodeBuiltinModules.concat(nodeDependencies),
output: [
{ file: 'dist/openpgp.js', format: 'iife', name: pkg.name, banner, intro },
{ file: 'dist/openpgp.min.js', format: 'iife', name: pkg.name, banner, intro, plugins: [terser(terserOptions)], sourcemap: true },
@@ -59,11 +62,11 @@ export default Object.assign([
browser: true
}),
commonjs({
- ignore: builtinModules.concat(nodeDependencies)
+ ignore: nodeBuiltinModules.concat(nodeDependencies)
}),
replace({
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
- 'require(': 'void(',
+ "import { createRequire } from 'module';": 'const createRequire = () => () => {}',
delimiters: ['', '']
}),
wasm(wasmOptions.browser)
@@ -72,10 +75,10 @@ export default Object.assign([
{
input: 'src/index.js',
inlineDynamicImports: true,
- external: builtinModules.concat(nodeDependencies),
+ external: nodeBuiltinModules.concat(nodeDependencies),
output: [
- { file: 'dist/node/openpgp.js', format: 'cjs', name: pkg.name, banner, intro },
- { file: 'dist/node/openpgp.min.js', format: 'cjs', name: pkg.name, banner, intro, plugins: [terser(terserOptions)], sourcemap: true },
+ { file: 'dist/node/openpgp.cjs', format: 'cjs', name: pkg.name, banner, intro },
+ { file: 'dist/node/openpgp.min.cjs', format: 'cjs', name: pkg.name, banner, intro, plugins: [terser(terserOptions)], sourcemap: true },
{ file: 'dist/node/openpgp.mjs', format: 'es', banner, intro },
{ file: 'dist/node/openpgp.min.mjs', format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
],
@@ -90,6 +93,7 @@ export default Object.assign([
},
{
input: 'src/index.js',
+ external: nodeBuiltinModules.concat(nodeDependencies),
output: [
{ dir: 'dist/lightweight', entryFileNames: 'openpgp.mjs', chunkFileNames: chunkInfo => getChunkFileName(chunkInfo, 'mjs'), format: 'es', banner, intro },
{ dir: 'dist/lightweight', entryFileNames: 'openpgp.min.mjs', chunkFileNames: chunkInfo => getChunkFileName(chunkInfo, 'min.mjs'), format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
@@ -100,11 +104,11 @@ export default Object.assign([
browser: true
}),
commonjs({
- ignore: builtinModules.concat(nodeDependencies)
+ ignore: nodeBuiltinModules.concat(nodeDependencies)
}),
replace({
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
- 'require(': 'void(',
+ "import { createRequire } from 'module';": 'const createRequire = () => () => {}',
delimiters: ['', '']
}),
wasm(wasmOptions.browser)
@@ -116,17 +120,22 @@ export default Object.assign([
{ file: 'test/lib/unittests-bundle.js', format: 'es', intro, sourcemap: true }
],
inlineDynamicImports: true,
- external: ['../..', '../../..'],
+ external: nodeBuiltinModules.concat(nodeDependencies),
plugins: [
+ alias({
+ entries: {
+ openpgp: `./dist/${process.env.npm_config_lightweight ? 'lightweight/' : ''}openpgp.mjs`
+ }
+ }),
resolve({
browser: true
}),
commonjs({
- ignore: builtinModules.concat(nodeDependencies)
+ ignore: nodeBuiltinModules.concat(nodeDependencies),
+ requireReturnsDefault: 'preferred'
}),
replace({
- "import openpgpjs from '../../..';": `import * as openpgpjs from '/dist/${process.env.npm_config_lightweight ? 'lightweight/' : ''}openpgp.mjs'; window.openpgp = openpgpjs;`,
- 'require(': 'void(',
+ "import { createRequire } from 'module';": 'const createRequire = () => () => {}',
delimiters: ['', '']
}),
wasm(wasmOptions.browser)
diff --git a/src/crypto/cmac.js b/src/crypto/cmac.js
index c183a70a3..e838bd6f0 100644
--- a/src/crypto/cmac.js
+++ b/src/crypto/cmac.js
@@ -2,7 +2,6 @@
* @fileoverview This module implements AES-CMAC on top of
* native AES-CBC using either the WebCrypto API or Node.js' crypto API.
* @module crypto/cmac
- * @private
*/
import { AES_CBC } from '@openpgp/asmcrypto.js/dist_es8/aes/cbc';
diff --git a/src/crypto/mode/eax.js b/src/crypto/mode/eax.js
index 2dfff46e6..4917ba1cf 100644
--- a/src/crypto/mode/eax.js
+++ b/src/crypto/mode/eax.js
@@ -19,7 +19,6 @@
* @fileoverview This module implements AES-EAX en/decryption on top of
* native AES-CTR using either the WebCrypto API or Node.js' crypto API.
* @module crypto/mode/eax
- * @private
*/
import { AES_CTR } from '@openpgp/asmcrypto.js/dist_es8/aes/ctr';
diff --git a/src/crypto/mode/index.js b/src/crypto/mode/index.js
index c1ae364fa..beeeca552 100644
--- a/src/crypto/mode/index.js
+++ b/src/crypto/mode/index.js
@@ -1,7 +1,6 @@
/**
* @fileoverview Cipher modes
* @module crypto/mode
- * @private
*/
import * as cfb from './cfb';
diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js
index 285c40f3b..a11e49c23 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -280,7 +280,7 @@ async function nodeVerify(curve, hashAlgo, { r, s }, message, publicKey) {
/* eslint-disable no-invalid-this */
-const asn1 = nodeCrypto ? require('asn1.js') : undefined;
+const asn1 = nodeCrypto ? util.nodeRequire('asn1.js') : undefined;
const ECDSASignature = nodeCrypto ?
asn1.define('ECDSASignature', function() {
diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js
index bdbf36c38..2b24a152c 100644
--- a/src/crypto/public_key/rsa.js
+++ b/src/crypto/public_key/rsa.js
@@ -30,7 +30,7 @@ import enums from '../../enums';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
-const asn1 = nodeCrypto ? require('asn1.js') : undefined;
+const asn1 = nodeCrypto ? util.nodeRequire('asn1.js') : undefined;
/* eslint-disable no-invalid-this */
const RSAPrivateKey = nodeCrypto ? asn1.define('RSAPrivateKey', function () {
diff --git a/src/key/subkey.js b/src/key/subkey.js
index 57e34a0bf..130155a7b 100644
--- a/src/key/subkey.js
+++ b/src/key/subkey.js
@@ -1,6 +1,5 @@
/**
* @module key/Subkey
- * @private
*/
import enums from '../enums';
diff --git a/src/util.js b/src/util.js
index c720d596c..255d020f5 100644
--- a/src/util.js
+++ b/src/util.js
@@ -24,6 +24,7 @@
*/
import * as stream from '@openpgp/web-stream-tools';
+import { createRequire } from 'module'; // Must be stripped in browser built
import { getBigInteger } from './biginteger';
import enums from './enums';
@@ -39,6 +40,8 @@ const util = {
return typeof data === 'string' || data instanceof String;
},
+ nodeRequire: createRequire(import.meta.url),
+
isArray: function(data) {
return data instanceof Array;
},
@@ -396,11 +399,11 @@ const util = {
* @returns {Object} The crypto module or 'undefined'.
*/
getNodeCrypto: function() {
- return require('crypto');
+ return this.nodeRequire('crypto');
},
getNodeZlib: function() {
- return require('zlib');
+ return this.nodeRequire('zlib');
},
/**
@@ -409,7 +412,7 @@ const util = {
* @returns {Function} The Buffer constructor or 'undefined'.
*/
getNodeBuffer: function() {
- return (require('buffer') || {}).Buffer;
+ return (this.nodeRequire('buffer') || {}).Buffer;
},
getHardwareConcurrency: function() {
@@ -417,7 +420,7 @@ const util = {
return navigator.hardwareConcurrency || 1;
}
- const os = require('os'); // Assume we're on Node.js.
+ const os = this.nodeRequire('os'); // Assume we're on Node.js.
return os.cpus().length;
},
diff --git a/test/benchmarks/memory_usage.js b/test/benchmarks/memory_usage.js
index 58166105e..e50873e4f 100644
--- a/test/benchmarks/memory_usage.js
+++ b/test/benchmarks/memory_usage.js
@@ -1,9 +1,10 @@
/* eslint-disable no-console */
-const assert = require('assert');
-const path = require('path');
-const { writeFileSync, unlinkSync } = require('fs');
-const { fork } = require('child_process');
-const openpgp = require('../..');
+import assert from 'assert';
+import path from 'path';
+import { writeFileSync, unlinkSync } from 'fs';
+import { fork } from 'child_process';
+import { fileURLToPath } from 'url';
+import * as openpgp from 'openpgp';
/**
* Benchmark max memory usage recorded during execution of the given function.
@@ -12,11 +13,12 @@ const openpgp = require('../..');
* @returns {NodeJS.MemoryUsage} memory usage snapshot with max RSS (sizes in bytes)
*/
const benchmark = async function(fn) {
- const tmpFileName = path.join(__dirname, 'tmp.js');
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
+ const tmpFileName = path.join(__dirname, 'tmp.cjs');
// the code to execute must be written to a file
writeFileSync(tmpFileName, `
const assert = require('assert');
-const openpgp = require('../..');
+const openpgp = require('openpgp');
let maxMemoryComsumption;
let activeSampling = false;
diff --git a/test/benchmarks/time.js b/test/benchmarks/time.js
index e2a322415..e86340f79 100644
--- a/test/benchmarks/time.js
+++ b/test/benchmarks/time.js
@@ -1,5 +1,5 @@
-const Benchmark = require('benchmark');
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+import Benchmark from 'benchmark';
+import * as openpgp from 'openpgp';
const wrapAsync = func => ({
fn: async deferred => {
diff --git a/test/crypto/aes_kw.js b/test/crypto/aes_kw.js
index 130cfc5e8..1a3b04c47 100644
--- a/test/crypto/aes_kw.js
+++ b/test/crypto/aes_kw.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const aesKW = require('../../src/crypto/aes_kw');
-const util = require('../../src/util');
+import * as aesKW from '../../src/crypto/aes_kw.js';
+import util from '../../src/util.js';
-module.exports = () => describe('AES Key Wrap and Unwrap', function () {
+export default () => describe('AES Key Wrap and Unwrap', function () {
const test_vectors = [
[
'128 bits of Key Data with a 128-bit KEK',
diff --git a/test/crypto/cipher/aes.js b/test/crypto/cipher/aes.js
index 798e86620..6ec39863d 100644
--- a/test/crypto/cipher/aes.js
+++ b/test/crypto/cipher/aes.js
@@ -1,8 +1,8 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const { aes128: AES128 } = require('../../../src/crypto/cipher');
+import { aes128 as AES128 } from '../../../src/crypto/cipher';
-module.exports = () => describe('AES Rijndael cipher test with test vectors from ecb_tbl.txt', function() {
+export default () => describe('AES Rijndael cipher test with test vectors from ecb_tbl.txt', function() {
function test_aes(input, key, output) {
const aes = new AES128(new Uint8Array(key));
diff --git a/test/crypto/cipher/blowfish.js b/test/crypto/cipher/blowfish.js
index fc31fe892..f1e7477f2 100644
--- a/test/crypto/cipher/blowfish.js
+++ b/test/crypto/cipher/blowfish.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const BF = require('../../../src/crypto/cipher/blowfish');
-const util = require('../../../src/util');
+import BF from '../../../src/crypto/cipher/blowfish';
+import util from '../../../src/util.js';
-module.exports = () => it('Blowfish cipher test with test vectors from https://www.schneier.com/code/vectors.txt', function(done) {
+export default () => it('Blowfish cipher test with test vectors from https://www.schneier.com/code/vectors.txt', function(done) {
function test_bf(input, key, output) {
const blowfish = new BF(util.uint8ArrayToString(key));
const result = blowfish.encrypt(input);
diff --git a/test/crypto/cipher/cast5.js b/test/crypto/cipher/cast5.js
index c68ab094c..cde718c3a 100644
--- a/test/crypto/cipher/cast5.js
+++ b/test/crypto/cipher/cast5.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const CAST5 = require('../../../src/crypto/cipher/cast5');
-const util = require('../../../src/util');
+import CAST5 from '../../../src/crypto/cipher/cast5.js';
+import util from '../../../src/util.js';
-module.exports = () => it('CAST-128 cipher test with test vectors from RFC2144', function (done) {
+export default () => it('CAST-128 cipher test with test vectors from RFC2144', function (done) {
function test_cast(input, key, output) {
const cast5 = new CAST5(key);
const result = cast5.encrypt(input);
diff --git a/test/crypto/cipher/des.js b/test/crypto/cipher/des.js
index 72dbd5941..e3a002858 100644
--- a/test/crypto/cipher/des.js
+++ b/test/crypto/cipher/des.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const { DES, TripleDES } = require('../../../src/crypto/cipher/des');
-const util = require('../../../src/util');
+import { DES, TripleDES } from '../../../src/crypto/cipher/des.js';
+import util from '../../../src/util.js';
-module.exports = () => describe('TripleDES (EDE) cipher test with test vectors from NIST SP 800-20', function() {
+export default () => describe('TripleDES (EDE) cipher test with test vectors from NIST SP 800-20', function() {
// see https://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf
const key = new Uint8Array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
const testvectors = [[[0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00]],
diff --git a/test/crypto/cipher/index.js b/test/crypto/cipher/index.js
index 35770ed8b..7f852f20a 100644
--- a/test/crypto/cipher/index.js
+++ b/test/crypto/cipher/index.js
@@ -1,7 +1,13 @@
-module.exports = () => describe('Cipher', function () {
- require('./aes')();
- require('./blowfish')();
- require('./cast5')();
- require('./des')();
- require('./twofish')();
+import testAES from './aes';
+import testBlowfish from './blowfish';
+import testCAST5 from './cast5';
+import testDES from './des';
+import testTwofish from './twofish';
+
+export default () => describe('Cipher', function () {
+ testAES();
+ testBlowfish();
+ testCAST5();
+ testDES();
+ testTwofish();
});
diff --git a/test/crypto/cipher/twofish.js b/test/crypto/cipher/twofish.js
index 6a0e1445b..f66d105ab 100644
--- a/test/crypto/cipher/twofish.js
+++ b/test/crypto/cipher/twofish.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const TF = require('../../../src/crypto/cipher/twofish');
-const util = require('../../../src/util');
+import TF from '../../../src/crypto/cipher/twofish.js';
+import util from '../../../src/util.js';
-module.exports = () => it('Twofish with test vectors from https://www.schneier.com/code/ecb_ival.txt', function(done) {
+export default () => it('Twofish with test vectors from https://www.schneier.com/code/ecb_ival.txt', function(done) {
function tfencrypt(block, key) {
const tf = new TF(util.stringToUint8Array(key));
diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js
index 8c5417bce..5f2f7b31a 100644
--- a/test/crypto/crypto.js
+++ b/test/crypto/crypto.js
@@ -1,12 +1,13 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const sandbox = require('sinon/lib/sinon/sandbox');
-const crypto = require('../../src/crypto');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import sandbox from 'sinon/lib/sinon/sandbox';
+import crypto from '../../src/crypto';
+import util from '../../src/util.js';
-module.exports = () => describe('API functional testing', function() {
+export default () => describe('API functional testing', function() {
const RSAPublicKeyMaterial = util.concatUint8Array([
new Uint8Array([0x08,0x00,0xac,0x15,0xb3,0xd6,0xd2,0x0f,0xf0,0x7a,0xdd,0x21,0xb7,
0xbf,0x61,0xfa,0xca,0x93,0x86,0xc8,0x55,0x5a,0x4b,0xa6,0xa4,0x1a,
diff --git a/test/crypto/eax.js b/test/crypto/eax.js
index 2c7e7625e..5c8e535d7 100644
--- a/test/crypto/eax.js
+++ b/test/crypto/eax.js
@@ -1,13 +1,14 @@
// Modified by ProtonTech AG
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
-const sandbox = require('sinon/lib/sinon/sandbox');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import sandbox from 'sinon/lib/sinon/sandbox';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const EAX = require('../../src/crypto/mode/eax');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import EAX from '../../src/crypto/mode/eax.js';
+import util from '../../src/util.js';
function testAESEAX() {
it('Passes all test vectors', async function() {
@@ -124,7 +125,7 @@ function testAESEAX() {
}
/* eslint-disable no-invalid-this */
-module.exports = () => describe('Symmetric AES-EAX', function() {
+export default () => describe('Symmetric AES-EAX', function() {
let sinonSandbox;
let getWebCryptoStub;
let getNodeCryptoStub;
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index d9e3d824a..fc0edb19c 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -1,18 +1,19 @@
-const sandbox = require('sinon/lib/sinon/sandbox');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
-
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const OID = require('../../src/type/oid');
-const KDFParams = require('../../src/type/kdf_params');
-const elliptic_curves = require('../../src/crypto/public_key/elliptic');
-const util = require('../../src/util');
-const elliptic_data = require('./elliptic_data');
-const random = require('../../src/crypto/random');
+import sandbox from 'sinon/lib/sinon/sandbox';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
+
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import OID from '../../src/type/oid.js';
+import KDFParams from '../../src/type/kdf_params.js';
+import * as elliptic_curves from '../../src/crypto/public_key/elliptic';
+import util from '../../src/util.js';
+import elliptic_data from './elliptic_data.js';
+import * as random from '../../src/crypto/random.js';
const key_data = elliptic_data.key_data;
/* eslint-disable no-invalid-this */
-module.exports = () => describe('ECDH key exchange @lightweight', function () {
+export default () => describe('ECDH key exchange @lightweight', function () {
const decrypt_message = function (oid, hash, cipher, priv, pub, ephemeral, data, fingerprint) {
if (util.isString(data)) {
data = util.stringToUint8Array(data);
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index f1a52a861..6072ae44f 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -1,18 +1,19 @@
-const sandbox = require('sinon/lib/sinon/sandbox');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import sandbox from 'sinon/lib/sinon/sandbox';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const elliptic_curves = require('../../src/crypto/public_key/elliptic');
-const hashMod = require('../../src/crypto/hash');
-const config = require('../../src/config');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import * as elliptic_curves from '../../src/crypto/public_key/elliptic';
+import hashMod from '../../src/crypto/hash';
+import config from '../../src/config';
+import util from '../../src/util.js';
-const elliptic_data = require('./elliptic_data');
+import elliptic_data from './elliptic_data';
const key_data = elliptic_data.key_data;
/* eslint-disable no-invalid-this */
-module.exports = () => describe('Elliptic Curve Cryptography @lightweight', function () {
+export default () => describe('Elliptic Curve Cryptography @lightweight', function () {
const signature_data = {
priv: new Uint8Array([
0x14, 0x2B, 0xE2, 0xB7, 0x4D, 0xBD, 0x1B, 0x22,
diff --git a/test/crypto/elliptic_data.js b/test/crypto/elliptic_data.js
index c6cd83c10..61eba7d97 100644
--- a/test/crypto/elliptic_data.js
+++ b/test/crypto/elliptic_data.js
@@ -99,4 +99,4 @@ const elliptic_data = {
}
};
-module.exports = elliptic_data;
+export default elliptic_data;
diff --git a/test/crypto/gcm.js b/test/crypto/gcm.js
index d3b0f01b1..4e06806e4 100644
--- a/test/crypto/gcm.js
+++ b/test/crypto/gcm.js
@@ -1,13 +1,14 @@
-const sandbox = require('sinon/lib/sinon/sandbox');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import sandbox from 'sinon/lib/sinon/sandbox';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const crypto = require('../../src/crypto');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import crypto from '../../src/crypto';
+import util from '../../src/util.js';
-module.exports = () => describe('Symmetric AES-GCM (experimental)', function() {
+export default () => describe('Symmetric AES-GCM (experimental)', function() {
let sinonSandbox;
let getWebCryptoStub;
let getNodeCryptoStub;
diff --git a/test/crypto/hash/index.js b/test/crypto/hash/index.js
index c0b01f8ce..533661778 100644
--- a/test/crypto/hash/index.js
+++ b/test/crypto/hash/index.js
@@ -1,5 +1,9 @@
-module.exports = () => describe('Hash', function () {
- require('./md5')();
- require('./ripemd')();
- require('./sha')();
+import testMD5 from './md5';
+import testRipeMD from './ripemd';
+import testSHA from './sha';
+
+export default () => describe('Hash', function () {
+ testMD5();
+ testRipeMD();
+ testSHA();
});
diff --git a/test/crypto/hash/md5.js b/test/crypto/hash/md5.js
index 078f6c1b9..0825e4213 100644
--- a/test/crypto/hash/md5.js
+++ b/test/crypto/hash/md5.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const md5 = require('../../../src/crypto/hash/md5');
-const util = require('../../../src/util');
+import md5 from '../../../src/crypto/hash/md5.js';
+import util from '../../../src/util.js';
-module.exports = () => it('MD5 with test vectors from RFC 1321', async function() {
+export default () => it('MD5 with test vectors from RFC 1321', async function() {
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('')), 'MD5("") = d41d8cd98f00b204e9800998ecf8427e')).to.equal('d41d8cd98f00b204e9800998ecf8427e');
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('abc')), 'MD5("a") = 0cc175b9c0f1b6a831c399e269772661')).to.equal('900150983cd24fb0d6963f7d28e17f72');
expect(util.uint8ArrayToHex(await md5(util.stringToUint8Array('message digest')), 'MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0')).to.equal('f96b697d7cb7938d525a2f31aaf161d0');
diff --git a/test/crypto/hash/ripemd.js b/test/crypto/hash/ripemd.js
index e9d93d623..a1116c31c 100644
--- a/test/crypto/hash/ripemd.js
+++ b/test/crypto/hash/ripemd.js
@@ -1,11 +1,11 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const { ripemd: rmdString } = require('../../../src/crypto/hash');
-const util = require('../../../src/util');
+import hash from '../../../src/crypto/hash';
+import util from '../../../src/util.js';
-module.exports = () => it('RIPE-MD 160 bits with test vectors from https://homes.esat.kuleuven.be/~bosselae/ripemd160.html', async function() {
- expect(util.uint8ArrayToHex(await rmdString(util.stringToUint8Array('')), 'RMDstring("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31')).to.equal('9c1185a5c5e9fc54612808977ee8f548b2258d31');
- expect(util.uint8ArrayToHex(await rmdString(util.stringToUint8Array('a')), 'RMDstring("a") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe')).to.equal('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe');
- expect(util.uint8ArrayToHex(await rmdString(util.stringToUint8Array('abc')), 'RMDstring("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc')).to.equal('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc');
- expect(util.uint8ArrayToHex(await rmdString(util.stringToUint8Array('message digest')), 'RMDstring("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36')).to.equal('5d0689ef49d2fae572b881b123a85ffa21595f36');
+export default () => it('RIPE-MD 160 bits with test vectors from https://homes.esat.kuleuven.be/~bosselae/ripemd160.html', async function() {
+ expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('')), 'RMDstring("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31')).to.equal('9c1185a5c5e9fc54612808977ee8f548b2258d31');
+ expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('a')), 'RMDstring("a") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe')).to.equal('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe');
+ expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('abc')), 'RMDstring("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc')).to.equal('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc');
+ expect(util.uint8ArrayToHex(await hash.ripemd(util.stringToUint8Array('message digest')), 'RMDstring("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36')).to.equal('5d0689ef49d2fae572b881b123a85ffa21595f36');
});
diff --git a/test/crypto/hash/sha.js b/test/crypto/hash/sha.js
index fc81b29f0..dc5284f08 100644
--- a/test/crypto/hash/sha.js
+++ b/test/crypto/hash/sha.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const hash = require('../../../src/crypto/hash');
-const util = require('../../../src/util');
+import hash from '../../../src/crypto/hash';
+import util from '../../../src/util.js';
-module.exports = () => it('SHA* with test vectors from NIST FIPS 180-2', async function() {
+export default () => it('SHA* with test vectors from NIST FIPS 180-2', async function() {
expect(util.uint8ArrayToHex(await hash.sha1(util.stringToUint8Array('abc')), 'hash.sha1("abc") = a9993e364706816aba3e25717850c26c9cd0d89d')).to.equal('a9993e364706816aba3e25717850c26c9cd0d89d');
expect(util.uint8ArrayToHex(await hash.sha1(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 84983e441c3bd26ebaae4aa1f95129e5e54670f1')).to.equal('84983e441c3bd26ebaae4aa1f95129e5e54670f1');
expect(util.uint8ArrayToHex(await hash.sha224(util.stringToUint8Array('abc')), 'hash.sha224("abc") = 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7')).to.equal('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7');
diff --git a/test/crypto/hkdf.js b/test/crypto/hkdf.js
index b2b880236..de048e1a0 100644
--- a/test/crypto/hkdf.js
+++ b/test/crypto/hkdf.js
@@ -1,13 +1,10 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const computeHKDF = require('../../src/crypto/hkdf');
-const enums = require('../../src/enums');
-const util = require('../../src/util');
+import computeHKDF from '../../src/crypto/hkdf';
+import enums from '../../src/enums';
+import util from '../../src/util';
-// WebCrypto implements HKDF natively, no need to test it
-const maybeDescribe = util.getNodeCrypto() ? describe : describe;
-
-module.exports = () => maybeDescribe('HKDF test vectors', function() {
+export default () => describe('HKDF test vectors', function() {
// Vectors from https://www.rfc-editor.org/rfc/rfc5869#appendix-A
it('Test Case 1', async function() {
const inputKey = util.hexToUint8Array('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b');
diff --git a/test/crypto/index.js b/test/crypto/index.js
index 932dd1d84..205b98669 100644
--- a/test/crypto/index.js
+++ b/test/crypto/index.js
@@ -1,15 +1,29 @@
-module.exports = () => describe('Crypto', function () {
- require('./cipher')();
- require('./hash')();
- require('./crypto')();
- require('./elliptic')();
- require('./ecdh')();
- require('./pkcs5')();
- require('./aes_kw')();
- require('./hkdf')();
- require('./gcm')();
- require('./eax')();
- require('./ocb')();
- require('./rsa')();
- require('./validate')();
+import testCipher from './cipher';
+import testHash from './hash';
+import testCrypto from './crypto';
+import testElliptic from './elliptic';
+import testECDH from './ecdh';
+import testPKCS5 from './pkcs5';
+import testAESKW from './aes_kw';
+import testHKDF from './hkdf';
+import testGCM from './gcm';
+import testEAX from './eax';
+import testOCB from './ocb';
+import testRSA from './rsa';
+import testValidate from './validate';
+
+export default () => describe('Crypto', function () {
+ testCipher();
+ testHash();
+ testCrypto();
+ testElliptic();
+ testECDH();
+ testPKCS5();
+ testAESKW();
+ testHKDF();
+ testGCM();
+ testEAX();
+ testOCB();
+ testRSA();
+ testValidate();
});
diff --git a/test/crypto/ocb.js b/test/crypto/ocb.js
index c97beb273..67bea1750 100644
--- a/test/crypto/ocb.js
+++ b/test/crypto/ocb.js
@@ -1,14 +1,15 @@
// Modified by ProtonTech AG
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const OCB = require('../../src/crypto/mode/ocb');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import OCB from '../../src/crypto/mode/ocb.js';
+import util from '../../src/util.js';
-module.exports = () => describe('Symmetric AES-OCB', function() {
+export default () => describe('Symmetric AES-OCB', function() {
it('Passes all test vectors', async function() {
const K = '000102030405060708090A0B0C0D0E0F';
const keyBytes = util.hexToUint8Array(K);
diff --git a/test/crypto/pkcs5.js b/test/crypto/pkcs5.js
index c051206e1..30d666a63 100644
--- a/test/crypto/pkcs5.js
+++ b/test/crypto/pkcs5.js
@@ -1,8 +1,8 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const pkcs5 = require('../../src/crypto/pkcs5');
+import * as pkcs5 from '../../src/crypto/pkcs5.js';
-module.exports = () => describe('PKCS5 padding', function() {
+export default () => describe('PKCS5 padding', function() {
it('Add and remove padding', function () {
const m = new Uint8Array([0,1,2,3,4,5,6,7,8]);
const padded = pkcs5.encode(m);
diff --git a/test/crypto/rsa.js b/test/crypto/rsa.js
index 37f7e1e54..4aa24d61f 100644
--- a/test/crypto/rsa.js
+++ b/test/crypto/rsa.js
@@ -1,14 +1,15 @@
-const sandbox = require('sinon/lib/sinon/sandbox');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import sandbox from 'sinon/lib/sinon/sandbox';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const crypto = require('../../src/crypto');
-const random = require('../../src/crypto/random');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import crypto from '../../src/crypto';
+import * as random from '../../src/crypto/random.js';
+import util from '../../src/util.js';
/* eslint-disable no-invalid-this */
-module.exports = () => describe('basic RSA cryptography', function () {
+export default () => describe('basic RSA cryptography', function () {
let sinonSandbox;
let getWebCryptoStub;
let getNodeCryptoStub;
diff --git a/test/crypto/validate.js b/test/crypto/validate.js
index 5e3115320..610728b5c 100644
--- a/test/crypto/validate.js
+++ b/test/crypto/validate.js
@@ -1,8 +1,9 @@
-const BN = require('bn.js');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import BN from 'bn.js';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
const armoredDSAKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
@@ -86,7 +87,7 @@ async function generatePrivateKeyObject(options) {
}
/* eslint-disable no-invalid-this */
-module.exports = () => {
+export default () => {
describe('EdDSA parameter validation (legacy format)', function() {
let eddsaKey;
before(async () => {
diff --git a/test/general/armor.js b/test/general/armor.js
index 3ec400a31..53119f2bd 100644
--- a/test/general/armor.js
+++ b/test/general/armor.js
@@ -1,9 +1,8 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
-
-module.exports = () => describe('ASCII armor', function() {
+export default () => describe('ASCII armor', function() {
function getArmor(headers, signatureHeaders) {
return ['-----BEGIN PGP SIGNED MESSAGE-----']
diff --git a/test/general/biginteger.js b/test/general/biginteger.js
index 10dd8446e..142b5026c 100644
--- a/test/general/biginteger.js
+++ b/test/general/biginteger.js
@@ -1,9 +1,10 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const BN = require('bn.js');
-const random = require('../../src/crypto/random');
-const util = require('../../src/util');
+import BN from 'bn.js';
+import * as random from '../../src/crypto/random.js';
+import util from '../../src/util.js';
let BigInteger;
@@ -18,7 +19,7 @@ async function getRandomBN(min, max) {
return r.mod(modulus).add(min);
}
-module.exports = () => describe('BigInteger interface', function() {
+export default () => describe('BigInteger interface', function() {
before(async () => {
BigInteger = await util.getBigInteger();
});
diff --git a/test/general/brainpool.js b/test/general/brainpool.js
index fbcc9b940..ce662ca67 100644
--- a/test/general/brainpool.js
+++ b/test/general/brainpool.js
@@ -1,14 +1,15 @@
/* globals tryTests */
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import util from '../../src/util.js';
-const input = require('./testInputs');
+import * as input from './testInputs.js';
-module.exports = () => (openpgp.config.ci ? describe.skip : describe)('Brainpool Cryptography @lightweight', function () {
+export default () => (openpgp.config.ci ? describe.skip : describe)('Brainpool Cryptography @lightweight', function () {
let rejectCurvesVal;
before(function() {
//only x25519 crypto is fully functional in lightbuild
diff --git a/test/general/config.js b/test/general/config.js
index 10ba476b1..b86b1eb71 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -1,8 +1,8 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
-module.exports = () => describe('Custom configuration', function() {
+export default () => describe('Custom configuration', function() {
it('openpgp.readMessage', async function() {
const armoredMessage = await openpgp.encrypt({ message: await openpgp.createMessage({ text:'hello world' }), passwords: 'password' });
const message = await openpgp.readMessage({ armoredMessage });
diff --git a/test/general/decompression.js b/test/general/decompression.js
index d6ebbc6a8..844bd2594 100644
--- a/test/general/decompression.js
+++ b/test/general/decompression.js
@@ -1,7 +1,8 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
const password = 'I am a password';
@@ -38,7 +39,7 @@ Xg==
}
};
-module.exports = () => describe('Decrypt and decompress message tests', function () {
+export default () => describe('Decrypt and decompress message tests', function () {
function runTest(key, test) {
it(`Decrypts message compressed with ${key}`, async function () {
diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js
index 06287a688..93234716b 100644
--- a/test/general/ecc_nist.js
+++ b/test/general/ecc_nist.js
@@ -1,13 +1,14 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
-const util = require('../../src/util');
+import util from '../../src/util.js';
-const input = require('./testInputs');
+import * as input from './testInputs.js';
-module.exports = () => describe('Elliptic Curve Cryptography for NIST P-256,P-384,P-521 curves @lightweight', function () {
+export default () => describe('Elliptic Curve Cryptography for NIST P-256,P-384,P-521 curves @lightweight', function () {
function omnibus() {
it('Omnibus NIST P-256 Test', async function () {
const testData = input.createSomeMessage();
diff --git a/test/general/ecc_secp256k1.js b/test/general/ecc_secp256k1.js
index a8d637410..f539a3ad9 100644
--- a/test/general/ecc_secp256k1.js
+++ b/test/general/ecc_secp256k1.js
@@ -1,10 +1,11 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import util from '../../src/util.js';
-module.exports = () => describe('Elliptic Curve Cryptography for secp256k1 curve @lightweight', function () {
+export default () => describe('Elliptic Curve Cryptography for secp256k1 curve @lightweight', function () {
if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
before(function() {
this.skip(); // eslint-disable-line no-invalid-this
diff --git a/test/general/index.js b/test/general/index.js
index 01a81a866..2ddf0794d 100644
--- a/test/general/index.js
+++ b/test/general/index.js
@@ -1,18 +1,33 @@
-module.exports = () => describe('General', function () {
- require('./util')();
- require('./biginteger')();
- require('./armor')();
- require('./packet')();
- require('./signature')();
- require('./key')();
- require('./openpgp')();
- require('./config')();
- require('./oid')();
- require('./ecc_nist')();
- require('./ecc_secp256k1')();
- require('./x25519')();
- require('./brainpool')();
- require('./decompression')();
- require('./streaming')();
-});
+import testX25519 from './x25519.js';
+import testUtil from './util.js';
+import testBigInteger from './biginteger.js';
+import testArmor from './armor.js';
+import testPacket from './packet.js';
+import testSignature from './signature.js';
+import testKey from './key.js';
+import testOpenPGP from './openpgp.js';
+import testConfig from './config.js';
+import testOID from './oid.js';
+import testNistECC from './ecc_nist.js';
+import testSecp256k1 from './ecc_secp256k1.js';
+import testBrainpool from './brainpool.js';
+import testDecompression from './decompression.js';
+import testStreaming from './streaming.js';
+export default () => describe('General', function () {
+ testX25519();
+ testUtil();
+ testBigInteger();
+ testArmor();
+ testPacket();
+ testSignature();
+ testKey();
+ testOpenPGP();
+ testConfig();
+ testOID();
+ testNistECC();
+ testSecp256k1();
+ testBrainpool();
+ testDecompression();
+ testStreaming();
+});
diff --git a/test/general/key.js b/test/general/key.js
index 7bf66805d..3024b9335 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -1,12 +1,13 @@
/* eslint-disable max-lines */
/* globals tryTests */
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const util = require('../../src/util');
-const { isAEADSupported, getPreferredAlgo } = require('../../src/key');
-const KeyID = require('../../src/type/keyid');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import util from '../../src/util.js';
+import { isAEADSupported, getPreferredAlgo } from '../../src/key';
+import KeyID from '../../src/type/keyid.js';
const priv_key_arm2 =
@@ -2892,7 +2893,7 @@ function versionSpecificTests() {
});
}
-module.exports = () => describe('Key', function() {
+export default () => describe('Key', function() {
let v5KeysVal;
let aeadProtectVal;
diff --git a/test/general/oid.js b/test/general/oid.js
index 8e500c415..b351cfc55 100644
--- a/test/general/oid.js
+++ b/test/general/oid.js
@@ -1,9 +1,9 @@
-const { expect } = require('chai');
+import { expect } from 'chai';
-const OID = require('../../src/type/oid');
-const util = require('../../src/util');
+import OID from '../../src/type/oid.js';
+import util from '../../src/util.js';
-module.exports = () => describe('Oid tests', function() {
+export default () => describe('Oid tests', function() {
const p256_oid = new Uint8Array([0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07]);
const p384_oid = new Uint8Array([0x2B, 0x81, 0x04, 0x00, 0x22]);
const p521_oid = new Uint8Array([0x2B, 0x81, 0x04, 0x00, 0x23]);
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index f03f13b5e..5f41ba5f2 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1,18 +1,19 @@
/* eslint-disable max-lines */
/* globals tryTests, loadStreamsPolyfill */
-const spy = require('sinon/lib/sinon/spy');
-const stream = require('@openpgp/web-stream-tools');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import spy from 'sinon/lib/sinon/spy';
+import * as stream from '@openpgp/web-stream-tools';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const crypto = require('../../src/crypto');
-const random = require('../../src/crypto/random');
-const util = require('../../src/util');
-const keyIDType = require('../../src/type/keyid');
-const { isAEADSupported } = require('../../src/key');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import crypto from '../../src/crypto';
+import * as random from '../../src/crypto/random.js';
+import util from '../../src/util.js';
+import keyIDType from '../../src/type/keyid.js';
+import { isAEADSupported } from '../../src/key';
-const input = require('./testInputs');
+import * as input from './testInputs.js';
const detectNode = () => typeof globalThis.process === 'object' && typeof globalThis.process.versions === 'object';
const detectBrowser = () => typeof navigator === 'object';
@@ -895,7 +896,7 @@ function withCompression(tests) {
});
}
-module.exports = () => describe('OpenPGP.js public api tests', function() {
+export default () => describe('OpenPGP.js public api tests', function() {
describe('readKey(s) and readPrivateKey(s) - unit tests', function() {
it('readKey and readPrivateKey should create equal private keys', async function() {
const key = await openpgp.readKey({ armoredKey: priv_key });
@@ -3064,7 +3065,7 @@ XfA3pqV4mTzF
throw new Error('Was not able to successfully modify checksum');
}
const badBodyEncrypted = data.replace(/\n=([a-zA-Z0-9/+]{4})/, 'aaa\n=$1');
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
try {
for (const allowStreaming of [true, false]) {
openpgp.config.allowUnauthenticatedStream = allowStreaming;
@@ -3329,9 +3330,9 @@ XfA3pqV4mTzF
const plaintext = [];
let i = 0;
const useNativeStream = (() => { try { new global.ReadableStream(); return true; } catch (e) { return false; } })(); // eslint-disable-line no-new
- loadStreamsPolyfill();
- const ReadableStream = useNativeStream ? global.ReadableStream : stream.ReadableStream;
- const data = new ReadableStream({
+ await loadStreamsPolyfill();
+ const GenericReadableStream = useNativeStream ? global.ReadableStream : ReadableStream;
+ const data = new GenericReadableStream({
pull(controller) {
if (i++ < 4) {
const randomBytes = random.getRandomBytes(10);
diff --git a/test/general/packet.js b/test/general/packet.js
index 8fd963ac1..ba229dbbd 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -1,14 +1,15 @@
/* eslint-disable max-lines */
-const stream = require('@openpgp/web-stream-tools');
-const stub = require('sinon/lib/sinon/stub');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import * as stream from '@openpgp/web-stream-tools';
+import stub from 'sinon/lib/sinon/stub';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const crypto = require('../../src/crypto');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import crypto from '../../src/crypto';
+import util from '../../src/util.js';
-const input = require('./testInputs');
+import * as input from './testInputs.js';
function stringify(array) {
if (stream.isStream(array)) {
@@ -26,7 +27,7 @@ function stringify(array) {
return result.join('');
}
-module.exports = () => describe('Packet', function() {
+export default () => describe('Packet', function() {
const allAllowedPackets = util.constructAllowedPackets([...Object.values(openpgp).filter(packetClass => !!packetClass.tag)]);
const armored_key =
diff --git a/test/general/signature.js b/test/general/signature.js
index 75468fb86..a4d8e31ed 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1,14 +1,15 @@
/* eslint-disable max-lines */
/* globals tryTests, loadStreamsPolyfill */
-const stream = require('@openpgp/web-stream-tools');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import * as stream from '@openpgp/web-stream-tools';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
-const util = require('../../src/util');
+import util from '../../src/util.js';
-module.exports = () => describe('Signature', function() {
+export default () => describe('Signature', function() {
const priv_key_arm1 =
['-----BEGIN PGP PRIVATE KEY BLOCK-----',
'Version: GnuPG v1.4.11 (GNU/Linux)',
@@ -900,7 +901,7 @@ AkLaG/AkATpuH+DMkYDmKbDLGgD+N4yuxXBJmBfC2IBe4J1S2Gg=
date: key.keyPacket.created,
format: 'object'
});
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey,
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
@@ -931,7 +932,7 @@ aMsUdQBgnPAcSGVsbG8gV29ybGQgOik=
date: key.keyPacket.created,
format: 'object'
});
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey,
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
@@ -961,7 +962,7 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
date: key.keyPacket.created,
format: 'object'
});
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
const { signatures: [sigInfo] } = await openpgp.verify({
verificationKeys: expiredKey,
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
@@ -1454,7 +1455,7 @@ yYDnCgA=
-----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
const message = await openpgp.readMessage({
armoredMessage: new ReadableStream({
async pull(controller) {
@@ -1520,7 +1521,7 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
-----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
const message = await openpgp.readMessage({
armoredMessage: new ReadableStream({
async pull(controller) {
diff --git a/test/general/streaming.js b/test/general/streaming.js
index 41b73dc90..b26db0497 100644
--- a/test/general/streaming.js
+++ b/test/general/streaming.js
@@ -1,15 +1,16 @@
/* eslint-disable max-lines */
/* globals loadStreamsPolyfill */
-const stream = require('@openpgp/web-stream-tools');
-const stub = require('sinon/lib/sinon/stub');
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import * as stream from '@openpgp/web-stream-tools';
+import stub from 'sinon/lib/sinon/stub';
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const random = require('../../src/crypto/random');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import * as random from '../../src/crypto/random.js';
+import util from '../../src/util.js';
-const input = require('./testInputs');
+import * as input from './testInputs.js';
const useNativeStream = (() => { try { new global.ReadableStream(); return true; } catch (e) { return false; } })(); // eslint-disable-line no-new
const NodeReadableStream = useNativeStream ? undefined : require('stream').Readable;
@@ -890,7 +891,7 @@ function tests() {
it("Don't pull entire input stream when we're not pulling decrypted stream (AEAD)", async function() {
let coresStub;
if (detectNode()) {
- coresStub = stub(require('os'), 'cpus');
+ coresStub = stub(util.nodeRequire('os'), 'cpus');
coresStub.returns(new Array(2));
// Object.defineProperty(require('os'), 'cpus', { value: () => [,], configurable: true });
} else {
@@ -947,7 +948,7 @@ function tests() {
});
}
-module.exports = () => describe('Streaming', function() {
+export default () => describe('Streaming', function() {
let currentTest = 0;
before(async function() {
@@ -957,7 +958,7 @@ module.exports = () => describe('Streaming', function() {
passphrase: 'hello world'
});
- loadStreamsPolyfill();
+ await loadStreamsPolyfill();
});
beforeEach(function() {
@@ -1013,7 +1014,9 @@ module.exports = () => describe('Streaming', function() {
tests();
if (detectNode()) {
- const fs = require('fs');
+ const fs = util.nodeRequire('fs');
+ const { fileURLToPath } = util.nodeRequire('url');
+ const __filename = fileURLToPath(import.meta.url);
it('Node: Encrypt and decrypt text message roundtrip', async function() {
dataArrived(); // Do not wait until data arrived.
diff --git a/test/general/testInputs.js b/test/general/testInputs.js
index 5879321bb..44d59d328 100644
--- a/test/general/testInputs.js
+++ b/test/general/testInputs.js
@@ -12,6 +12,6 @@ function createSomeMessage() {
return ' \t' + String.fromCodePoint(...arr).replace(/[\r\u2028\u2029]/g, '\n') + ' \t\n한국어/조선말';
}
-module.exports = {
- createSomeMessage: createSomeMessage
+export {
+ createSomeMessage
};
diff --git a/test/general/util.js b/test/general/util.js
index d4833af21..25dab192c 100644
--- a/test/general/util.js
+++ b/test/general/util.js
@@ -1,8 +1,7 @@
-const { expect } = require('chai');
-const util = require('../../src/util');
+import { expect } from 'chai';
+import util from '../../src/util';
-
-module.exports = () => describe('Util unit tests', function() {
+export default () => describe('Util unit tests', function() {
describe('isString', function() {
it('should return true for type "string"', function() {
diff --git a/test/general/x25519.js b/test/general/x25519.js
index 0a465b835..0cf9e2e30 100644
--- a/test/general/x25519.js
+++ b/test/general/x25519.js
@@ -1,17 +1,19 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const nacl = require('@openpgp/tweetnacl');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const elliptic = require('../../src/crypto/public_key/elliptic');
-const signature = require('../../src/crypto/signature');
-const OID = require('../../src/type/oid');
-const util = require('../../src/util');
+import nacl from '@openpgp/tweetnacl';
-const input = require('./testInputs');
+import * as elliptic from '../../src/crypto/public_key/elliptic';
+import * as signature from '../../src/crypto/signature';
+import OID from '../../src/type/oid';
+import util from '../../src/util';
-module.exports = () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cryptography (legacy format)', function () {
+import * as input from './testInputs';
+
+export default () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cryptography (legacy format)', function () {
const data = {
light: {
id: '1ecdf026c0245830',
diff --git a/test/karma.conf.js b/test/karma.conf.cjs
similarity index 100%
rename from test/karma.conf.js
rename to test/karma.conf.cjs
diff --git a/test/security/index.js b/test/security/index.js
index a83ecc21a..6c227fc3d 100644
--- a/test/security/index.js
+++ b/test/security/index.js
@@ -1,6 +1,11 @@
-module.exports = () => describe('Security', function () {
- require('./message_signature_bypass')();
- require('./unsigned_subpackets')();
- require('./subkey_trust')();
- require('./preferred_algo_mismatch')();
+import testMessageSignatureBypess from './message_signature_bypass';
+import testUnsignedSubpackets from './unsigned_subpackets';
+import testSubkeyTrust from './subkey_trust';
+import testPreferredAlgoMismatch from './preferred_algo_mismatch';
+
+export default () => describe('Security', function () {
+ testMessageSignatureBypess();
+ testUnsignedSubpackets();
+ testSubkeyTrust();
+ testPreferredAlgoMismatch();
});
diff --git a/test/security/message_signature_bypass.js b/test/security/message_signature_bypass.js
index 0a6276a9f..28f7879f4 100644
--- a/test/security/message_signature_bypass.js
+++ b/test/security/message_signature_bypass.js
@@ -1,8 +1,9 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
-const util = require('../../src/util');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import util from '../../src/util.js';
const { readKey, readCleartextMessage, SignaturePacket } = openpgp;
@@ -101,4 +102,4 @@ async function fakeSignature() {
expect(signatures).to.have.length(0);
}
-module.exports = () => it('Does not accept non-binary/text signatures', fakeSignature);
+export default () => it('Does not accept non-binary/text signatures', fakeSignature);
diff --git a/test/security/preferred_algo_mismatch.js b/test/security/preferred_algo_mismatch.js
index e53c710ee..4277eb48f 100644
--- a/test/security/preferred_algo_mismatch.js
+++ b/test/security/preferred_algo_mismatch.js
@@ -1,7 +1,8 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
const armoredMessage = `-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js VERSION
@@ -38,7 +39,7 @@ EnxUPL95HuMKoVkf4w==
=oopr
-----END PGP PRIVATE KEY BLOCK-----`;
-module.exports = () => it('Does not accept message encrypted with algo not mentioned in preferred algorithms', async function() {
+export default () => it('Does not accept message encrypted with algo not mentioned in preferred algorithms', async function() {
const message = await openpgp.readMessage({ armoredMessage });
const privKey = await openpgp.readKey({ armoredKey: privateKeyArmor });
await expect(openpgp.decrypt({ message, decryptionKeys: [privKey] })).to.be.rejectedWith('A non-preferred symmetric algorithm was used.');
diff --git a/test/security/subkey_trust.js b/test/security/subkey_trust.js
index 3aec75886..54dcca563 100644
--- a/test/security/subkey_trust.js
+++ b/test/security/subkey_trust.js
@@ -1,7 +1,9 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+chaiUse(chaiAsPromised);
+
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
const { readKey, PublicKey, readCleartextMessage, createCleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
@@ -33,7 +35,7 @@ async function generateTestData() {
};
}
-module.exports = () => it('Does not trust subkeys without Primary Key Binding Signature', async function() {
+export default () => it('Does not trust subkeys without Primary Key Binding Signature', async function() {
// attacker only has his own private key,
// the victim's public key and a signed message
const { victimPubKey, attackerPrivKey, signed } = await generateTestData();
diff --git a/test/security/unsigned_subpackets.js b/test/security/unsigned_subpackets.js
index cc559bc47..68ca86cac 100644
--- a/test/security/unsigned_subpackets.js
+++ b/test/security/unsigned_subpackets.js
@@ -1,7 +1,9 @@
-const { use: chaiUse, expect } = require('chai');
-chaiUse(require('chai-as-promised'));
+import { use as chaiUse, expect } from 'chai';
+import chaiAsPromised from 'chai-as-promised';
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
+chaiUse(chaiAsPromised);
+
+const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
const { readKey, PrivateKey, createMessage, enums, PacketList, SignaturePacket } = openpgp;
@@ -89,4 +91,4 @@ async function makeKeyValid() {
expect(await encryptFails(modifiedkey)).to.be.true;
}
-module.exports = () => it('Does not accept unsigned subpackets', makeKeyValid);
+export default () => it('Does not accept unsigned subpackets', makeKeyValid);
diff --git a/test/typescript/definitions.ts b/test/typescript/definitions.ts
index 5d61f9c60..c3513ef4e 100644
--- a/test/typescript/definitions.ts
+++ b/test/typescript/definitions.ts
@@ -16,7 +16,7 @@ import {
generateSessionKey, encryptSessionKey, decryptSessionKeys,
LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket, CleartextMessage,
WebStream, NodeStream,
-} from '../..';
+} from 'openpgp';
(async () => {
diff --git a/test/unittests.js b/test/unittests.js
index 4bf00069e..a94608176 100644
--- a/test/unittests.js
+++ b/test/unittests.js
@@ -1,4 +1,6 @@
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('..');
+import * as openpgp from 'openpgp';
+if (typeof window !== 'undefined' && !window.openpgp) { window.openpgp = openpgp }
+
(typeof window !== 'undefined' ? window : global).globalThis = (typeof window !== 'undefined' ? window : global);
@@ -27,9 +29,14 @@ globalThis.tryTests = function(name, tests, options) {
};
globalThis.loadStreamsPolyfill = function() {
- require('web-streams-polyfill/es2018'); // eslint-disable-line import/no-unassigned-import
+ return import('web-streams-polyfill');
};
+import runWorkerTests from './worker';
+import runCryptoTests from './crypto';
+import runGeneralTests from './general';
+import runSecurityTests from './security';
+
describe('Unit Tests', function () {
openpgp.config.s2kIterationCountByte = 0;
@@ -59,8 +66,8 @@ describe('Unit Tests', function () {
});
}
- require('./worker')();
- require('./crypto')();
- require('./general')();
- require('./security')();
+ runWorkerTests();
+ runCryptoTests();
+ runGeneralTests();
+ runSecurityTests();
});
diff --git a/test/worker/application_worker.js b/test/worker/application_worker.js
index cbd1fa941..1ffdc5589 100644
--- a/test/worker/application_worker.js
+++ b/test/worker/application_worker.js
@@ -1,9 +1,8 @@
/* globals tryTests */
-const { expect } = require('chai');
+import { expect } from 'chai';
-/* eslint-disable no-invalid-this */
-module.exports = () => tryTests('Application Worker', tests, {
+export default () => tryTests('Application Worker', tests, {
if: typeof window !== 'undefined' && window.Worker && window.MessageChannel
});
diff --git a/test/worker/index.js b/test/worker/index.js
index 8d1b8b722..2654cac61 100644
--- a/test/worker/index.js
+++ b/test/worker/index.js
@@ -1,4 +1,6 @@
-module.exports = () => describe('Web Worker', function () {
- require('./application_worker')();
+import testApplicationWorker from './application_worker.js';
+
+export default () => describe('Web Worker', function () {
+ testApplicationWorker();
});
diff --git a/tsconfig.json b/tsconfig.json
index 60f1e0658..a41b561be 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,8 +1,12 @@
{
- "exclude": [
- "./build/"
- ],
"compilerOptions": {
- "strict": true
+ "strict": true,
+ "target": "es2021",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "allowJs": true,
+ "paths": {
+ "openpgp": [ "." ]
+ },
}
}
From ae4ed1fbf3794ddc48f24438f9306807c29f4efe Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Fri, 2 Jun 2023 14:12:14 +0200
Subject: [PATCH 009/224] Tests: explicitly share openpgp instance used in
tests
Also, init config before any code is run in tests
---
.eslintrc.js | 1 +
test/crypto/crypto.js | 4 ++--
test/crypto/eax.js | 4 ++--
test/crypto/ecdh.js | 4 ++--
test/crypto/elliptic.js | 4 ++--
test/crypto/gcm.js | 4 ++--
test/crypto/ocb.js | 4 ++--
test/crypto/rsa.js | 4 ++--
test/crypto/validate.js | 4 ++--
test/general/armor.js | 2 +-
test/general/biginteger.js | 2 +-
test/general/brainpool.js | 4 ++--
test/general/config.js | 2 +-
test/general/decompression.js | 4 ++--
test/general/ecc_nist.js | 4 ++--
test/general/ecc_secp256k1.js | 4 ++--
test/general/key.js | 4 ++--
test/general/openpgp.js | 4 ++--
test/general/packet.js | 4 ++--
test/general/signature.js | 4 ++--
test/general/streaming.js | 4 ++--
test/general/x25519.js | 5 ++---
test/initOpenpgp.js | 14 ++++++++++++++
test/security/message_signature_bypass.js | 4 ++--
test/security/preferred_algo_mismatch.js | 4 ++--
test/security/subkey_trust.js | 5 ++---
test/security/unsigned_subpackets.js | 5 ++---
test/unittests.js | 7 +------
28 files changed, 63 insertions(+), 56 deletions(-)
create mode 100644 test/initOpenpgp.js
diff --git a/.eslintrc.js b/.eslintrc.js
index 6a58bb27a..93758d151 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -96,6 +96,7 @@ module.exports = {
// eslint-plugin-import rules:
'import/named': 'error',
'import/extensions': 'error',
+ 'import/first': 'off',
'import/no-extraneous-dependencies': ['error', { 'devDependencies': true, 'optionalDependencies': false, 'peerDependencies': false }],
'import/no-unassigned-import': 'error',
'import/prefer-default-export': 'off',
diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js
index 5f2f7b31a..05d898807 100644
--- a/test/crypto/crypto.js
+++ b/test/crypto/crypto.js
@@ -1,9 +1,9 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
import sandbox from 'sinon/lib/sinon/sandbox';
+import openpgp from '../initOpenpgp.js';
import crypto from '../../src/crypto';
import util from '../../src/util.js';
diff --git a/test/crypto/eax.js b/test/crypto/eax.js
index 5c8e535d7..54023f46c 100644
--- a/test/crypto/eax.js
+++ b/test/crypto/eax.js
@@ -3,10 +3,10 @@
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
import sandbox from 'sinon/lib/sinon/sandbox';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import EAX from '../../src/crypto/mode/eax.js';
import util from '../../src/util.js';
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index fc0edb19c..35ae5c3ad 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -1,9 +1,9 @@
import sandbox from 'sinon/lib/sinon/sandbox';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import OID from '../../src/type/oid.js';
import KDFParams from '../../src/type/kdf_params.js';
import * as elliptic_curves from '../../src/crypto/public_key/elliptic';
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index 6072ae44f..c92102b1b 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -1,9 +1,9 @@
import sandbox from 'sinon/lib/sinon/sandbox';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import * as elliptic_curves from '../../src/crypto/public_key/elliptic';
import hashMod from '../../src/crypto/hash';
import config from '../../src/config';
diff --git a/test/crypto/gcm.js b/test/crypto/gcm.js
index 4e06806e4..441d6f9c4 100644
--- a/test/crypto/gcm.js
+++ b/test/crypto/gcm.js
@@ -1,9 +1,9 @@
import sandbox from 'sinon/lib/sinon/sandbox';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import crypto from '../../src/crypto';
import util from '../../src/util.js';
diff --git a/test/crypto/ocb.js b/test/crypto/ocb.js
index 67bea1750..ef80a96b9 100644
--- a/test/crypto/ocb.js
+++ b/test/crypto/ocb.js
@@ -2,10 +2,10 @@
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import OCB from '../../src/crypto/mode/ocb.js';
import util from '../../src/util.js';
diff --git a/test/crypto/rsa.js b/test/crypto/rsa.js
index 4aa24d61f..1be4a1271 100644
--- a/test/crypto/rsa.js
+++ b/test/crypto/rsa.js
@@ -1,9 +1,9 @@
import sandbox from 'sinon/lib/sinon/sandbox';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import crypto from '../../src/crypto';
import * as random from '../../src/crypto/random.js';
import util from '../../src/util.js';
diff --git a/test/crypto/validate.js b/test/crypto/validate.js
index 610728b5c..54d79ca38 100644
--- a/test/crypto/validate.js
+++ b/test/crypto/validate.js
@@ -1,9 +1,9 @@
import BN from 'bn.js';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
const armoredDSAKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
diff --git a/test/general/armor.js b/test/general/armor.js
index 53119f2bd..10624ee2a 100644
--- a/test/general/armor.js
+++ b/test/general/armor.js
@@ -1,6 +1,6 @@
import { expect } from 'chai';
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
export default () => describe('ASCII armor', function() {
diff --git a/test/general/biginteger.js b/test/general/biginteger.js
index 142b5026c..90fd0d38a 100644
--- a/test/general/biginteger.js
+++ b/test/general/biginteger.js
@@ -1,5 +1,5 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
import BN from 'bn.js';
diff --git a/test/general/brainpool.js b/test/general/brainpool.js
index ce662ca67..e22dae587 100644
--- a/test/general/brainpool.js
+++ b/test/general/brainpool.js
@@ -1,9 +1,9 @@
/* globals tryTests */
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
import * as input from './testInputs.js';
diff --git a/test/general/config.js b/test/general/config.js
index b86b1eb71..038e72f56 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -1,6 +1,6 @@
import { expect } from 'chai';
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
export default () => describe('Custom configuration', function() {
it('openpgp.readMessage', async function() {
diff --git a/test/general/decompression.js b/test/general/decompression.js
index 844bd2594..7680a73d2 100644
--- a/test/general/decompression.js
+++ b/test/general/decompression.js
@@ -1,8 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
const password = 'I am a password';
diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js
index 93234716b..1838e031b 100644
--- a/test/general/ecc_nist.js
+++ b/test/general/ecc_nist.js
@@ -1,8 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
diff --git a/test/general/ecc_secp256k1.js b/test/general/ecc_secp256k1.js
index f539a3ad9..da4576401 100644
--- a/test/general/ecc_secp256k1.js
+++ b/test/general/ecc_secp256k1.js
@@ -1,8 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
export default () => describe('Elliptic Curve Cryptography for secp256k1 curve @lightweight', function () {
diff --git a/test/general/key.js b/test/general/key.js
index 3024b9335..661f19047 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -1,10 +1,10 @@
/* eslint-disable max-lines */
/* globals tryTests */
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
import { isAEADSupported, getPreferredAlgo } from '../../src/key';
import KeyID from '../../src/type/keyid.js';
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 5f41ba5f2..1d435d605 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -3,10 +3,10 @@
import spy from 'sinon/lib/sinon/spy';
import * as stream from '@openpgp/web-stream-tools';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import crypto from '../../src/crypto';
import * as random from '../../src/crypto/random.js';
import util from '../../src/util.js';
diff --git a/test/general/packet.js b/test/general/packet.js
index ba229dbbd..5590e6cd9 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -2,10 +2,10 @@
import * as stream from '@openpgp/web-stream-tools';
import stub from 'sinon/lib/sinon/stub';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import crypto from '../../src/crypto';
import util from '../../src/util.js';
diff --git a/test/general/signature.js b/test/general/signature.js
index a4d8e31ed..1c123f751 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -2,10 +2,10 @@
/* globals tryTests, loadStreamsPolyfill */
import * as stream from '@openpgp/web-stream-tools';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
diff --git a/test/general/streaming.js b/test/general/streaming.js
index b26db0497..1a1ad5fbb 100644
--- a/test/general/streaming.js
+++ b/test/general/streaming.js
@@ -3,10 +3,10 @@
import * as stream from '@openpgp/web-stream-tools';
import stub from 'sinon/lib/sinon/stub';
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import * as random from '../../src/crypto/random.js';
import util from '../../src/util.js';
diff --git a/test/general/x25519.js b/test/general/x25519.js
index 0cf9e2e30..52bd19c26 100644
--- a/test/general/x25519.js
+++ b/test/general/x25519.js
@@ -1,10 +1,9 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
-
import nacl from '@openpgp/tweetnacl';
+import openpgp from '../initOpenpgp.js';
import * as elliptic from '../../src/crypto/public_key/elliptic';
import * as signature from '../../src/crypto/signature';
diff --git a/test/initOpenpgp.js b/test/initOpenpgp.js
new file mode 100644
index 000000000..4fd4a360e
--- /dev/null
+++ b/test/initOpenpgp.js
@@ -0,0 +1,14 @@
+/**
+ * This module centralises the openpgp import and ensures that the module is initialised
+ * at the top of the test bundle, and that the config is initialised before the tests code runs (incl. that outside of `describe`).
+ */
+
+import * as openpgp from 'openpgp';
+
+if (typeof window !== 'undefined') {
+ window.openpgp = openpgp;
+}
+
+openpgp.config.s2kIterationCountByte = 0;
+
+export default openpgp;
diff --git a/test/security/message_signature_bypass.js b/test/security/message_signature_bypass.js
index 28f7879f4..614d5c05c 100644
--- a/test/security/message_signature_bypass.js
+++ b/test/security/message_signature_bypass.js
@@ -1,8 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
const { readKey, readCleartextMessage, SignaturePacket } = openpgp;
diff --git a/test/security/preferred_algo_mismatch.js b/test/security/preferred_algo_mismatch.js
index 4277eb48f..c000d9d7c 100644
--- a/test/security/preferred_algo_mismatch.js
+++ b/test/security/preferred_algo_mismatch.js
@@ -1,8 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
const armoredMessage = `-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js VERSION
diff --git a/test/security/subkey_trust.js b/test/security/subkey_trust.js
index 54dcca563..e8aee45bf 100644
--- a/test/security/subkey_trust.js
+++ b/test/security/subkey_trust.js
@@ -1,9 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
const { readKey, PublicKey, readCleartextMessage, createCleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
diff --git a/test/security/unsigned_subpackets.js b/test/security/unsigned_subpackets.js
index 68ca86cac..827211030 100644
--- a/test/security/unsigned_subpackets.js
+++ b/test/security/unsigned_subpackets.js
@@ -1,9 +1,8 @@
import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-
+import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
+import openpgp from '../initOpenpgp.js';
const { readKey, PrivateKey, createMessage, enums, PacketList, SignaturePacket } = openpgp;
diff --git a/test/unittests.js b/test/unittests.js
index a94608176..54f63c3c6 100644
--- a/test/unittests.js
+++ b/test/unittests.js
@@ -1,6 +1,4 @@
-import * as openpgp from 'openpgp';
-if (typeof window !== 'undefined' && !window.openpgp) { window.openpgp = openpgp }
-
+import openpgp from './initOpenpgp.js';
(typeof window !== 'undefined' ? window : global).globalThis = (typeof window !== 'undefined' ? window : global);
@@ -38,9 +36,6 @@ import runGeneralTests from './general';
import runSecurityTests from './security';
describe('Unit Tests', function () {
-
- openpgp.config.s2kIterationCountByte = 0;
-
if (typeof window !== 'undefined') {
// Safari 14.1.*, 15.* and 16.* seem to have issues handling rejections when their native TransformStream implementation is involved,
// so for now we ignore unhandled rejections for those browser versions.
From b094274d98104e368a9236b8536fdd2503b58b08 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 17 May 2023 13:42:25 +0200
Subject: [PATCH 010/224] Remove @private JSDoc directives interfering with TS
---
src/crypto/aes_kw.js | 1 -
src/crypto/cipher/index.js | 1 -
src/crypto/crypto.js | 1 -
src/crypto/hash/index.js | 1 -
src/crypto/hkdf.js | 1 -
src/crypto/index.js | 1 -
src/crypto/mode/cfb.js | 1 -
src/crypto/mode/gcm.js | 1 -
src/crypto/mode/ocb.js | 1 -
src/crypto/pkcs1.js | 1 -
src/crypto/public_key/dsa.js | 1 -
src/crypto/public_key/elgamal.js | 1 -
src/crypto/public_key/elliptic/ecdh.js | 1 -
src/crypto/public_key/elliptic/ecdh_x.js | 1 -
src/crypto/public_key/elliptic/ecdsa.js | 1 -
src/crypto/public_key/elliptic/eddsa.js | 1 -
src/crypto/public_key/elliptic/eddsa_legacy.js | 1 -
src/crypto/public_key/elliptic/index.js | 1 -
src/crypto/public_key/elliptic/indutnyKey.js | 1 -
src/crypto/public_key/elliptic/oid_curves.js | 1 -
src/crypto/public_key/index.js | 1 -
src/crypto/public_key/prime.js | 1 -
src/crypto/public_key/rsa.js | 1 -
src/crypto/random.js | 1 -
src/crypto/signature.js | 1 -
src/encoding/base64.js | 1 -
src/key/helper.js | 1 -
src/key/user.js | 1 -
src/packet/packet.js | 1 -
src/type/ecdh_symkey.js | 1 -
src/type/keyid.js | 1 -
src/type/oid.js | 1 -
src/type/s2k/generic.js | 1 -
src/util.js | 1 -
34 files changed, 34 deletions(-)
diff --git a/src/crypto/aes_kw.js b/src/crypto/aes_kw.js
index d9bbbb3e6..e747ecc38 100644
--- a/src/crypto/aes_kw.js
+++ b/src/crypto/aes_kw.js
@@ -19,7 +19,6 @@
* @fileoverview Implementation of RFC 3394 AES Key Wrap & Key Unwrap funcions
* @see module:crypto/public_key/elliptic/ecdh
* @module crypto/aes_kw
- * @private
*/
import * as cipher from './cipher';
diff --git a/src/crypto/cipher/index.js b/src/crypto/cipher/index.js
index 4f96ef38b..d40c8e086 100644
--- a/src/crypto/cipher/index.js
+++ b/src/crypto/cipher/index.js
@@ -1,7 +1,6 @@
/**
* @fileoverview Symmetric cryptography functions
* @module crypto/cipher
- * @private
*/
import aes from './aes';
diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js
index 0cb86be1b..aa6e6f345 100644
--- a/src/crypto/crypto.js
+++ b/src/crypto/crypto.js
@@ -21,7 +21,6 @@
* @fileoverview Provides functions for asymmetric encryption and decryption as
* well as key generation and parameter handling for all public-key cryptosystems.
* @module crypto/crypto
- * @private
*/
import publicKey from './public_key';
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index 0765881ed..d5752841a 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -3,7 +3,6 @@
* @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto}
* @see {@link https://github.com/indutny/hash.js|hash.js}
* @module crypto/hash
- * @private
*/
import { Sha1 } from '@openpgp/asmcrypto.js/dist_es8/hash/sha1/sha1';
diff --git a/src/crypto/hkdf.js b/src/crypto/hkdf.js
index a14d751c8..cf531aed2 100644
--- a/src/crypto/hkdf.js
+++ b/src/crypto/hkdf.js
@@ -1,7 +1,6 @@
/**
* @fileoverview This module implements HKDF using either the WebCrypto API or Node.js' crypto API.
* @module crypto/hkdf
- * @private
*/
import enums from '../enums';
diff --git a/src/crypto/index.js b/src/crypto/index.js
index ab6b166af..460140c12 100644
--- a/src/crypto/index.js
+++ b/src/crypto/index.js
@@ -7,7 +7,6 @@
* @see module:crypto/random
* @see module:crypto/hash
* @module crypto
- * @private
*/
import * as cipher from './cipher';
diff --git a/src/crypto/mode/cfb.js b/src/crypto/mode/cfb.js
index e16f88b6a..a1bdb5260 100644
--- a/src/crypto/mode/cfb.js
+++ b/src/crypto/mode/cfb.js
@@ -19,7 +19,6 @@
/**
* @module crypto/mode/cfb
- * @private
*/
import { AES_CFB } from '@openpgp/asmcrypto.js/dist_es8/aes/cfb';
diff --git a/src/crypto/mode/gcm.js b/src/crypto/mode/gcm.js
index 25c7a0598..c5b5e332d 100644
--- a/src/crypto/mode/gcm.js
+++ b/src/crypto/mode/gcm.js
@@ -19,7 +19,6 @@
* @fileoverview This module wraps native AES-GCM en/decryption for both
* the WebCrypto api as well as node.js' crypto api.
* @module crypto/mode/gcm
- * @private
*/
import { AES_GCM } from '@openpgp/asmcrypto.js/dist_es8/aes/gcm';
diff --git a/src/crypto/mode/ocb.js b/src/crypto/mode/ocb.js
index 868b0ebc2..3cd1926cb 100644
--- a/src/crypto/mode/ocb.js
+++ b/src/crypto/mode/ocb.js
@@ -18,7 +18,6 @@
/**
* @fileoverview This module implements AES-OCB en/decryption.
* @module crypto/mode/ocb
- * @private
*/
import * as ciphers from '../cipher';
diff --git a/src/crypto/pkcs1.js b/src/crypto/pkcs1.js
index db981322d..229081e8b 100644
--- a/src/crypto/pkcs1.js
+++ b/src/crypto/pkcs1.js
@@ -21,7 +21,6 @@
* @see module:crypto/public_key/elliptic/ecdh
* @see PublicKeyEncryptedSessionKeyPacket
* @module crypto/pkcs1
- * @private
*/
import { getRandomBytes } from './random';
diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js
index 7fa696494..286adb649 100644
--- a/src/crypto/public_key/dsa.js
+++ b/src/crypto/public_key/dsa.js
@@ -18,7 +18,6 @@
/**
* @fileoverview A Digital signature algorithm implementation
* @module crypto/public_key/dsa
- * @private
*/
import { getRandomBigInteger } from '../random';
import util from '../../util';
diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js
index bcd41efec..2f69e6f0b 100644
--- a/src/crypto/public_key/elgamal.js
+++ b/src/crypto/public_key/elgamal.js
@@ -18,7 +18,6 @@
/**
* @fileoverview ElGamal implementation
* @module crypto/public_key/elgamal
- * @private
*/
import util from '../../util';
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index 11238f710..e37fb6334 100644
--- a/src/crypto/public_key/elliptic/ecdh.js
+++ b/src/crypto/public_key/elliptic/ecdh.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Key encryption and decryption for RFC 6637 ECDH
* @module crypto/public_key/elliptic/ecdh
- * @private
*/
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
diff --git a/src/crypto/public_key/elliptic/ecdh_x.js b/src/crypto/public_key/elliptic/ecdh_x.js
index 3b66c0c0a..1e0b38611 100644
--- a/src/crypto/public_key/elliptic/ecdh_x.js
+++ b/src/crypto/public_key/elliptic/ecdh_x.js
@@ -1,7 +1,6 @@
/**
* @fileoverview Key encryption and decryption for RFC 6637 ECDH
* @module crypto/public_key/elliptic/ecdh
- * @private
*/
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js
index a11e49c23..19412aa10 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Implementation of ECDSA following RFC6637 for Openpgpjs
* @module crypto/public_key/elliptic/ecdsa
- * @private
*/
import enums from '../../../enums';
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index e38cbb96f..413f967f9 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Implementation of EdDSA following RFC4880bis-03 for OpenPGP
* @module crypto/public_key/elliptic/eddsa
- * @private
*/
import sha512 from 'hash.js/lib/hash/sha/512';
diff --git a/src/crypto/public_key/elliptic/eddsa_legacy.js b/src/crypto/public_key/elliptic/eddsa_legacy.js
index 63929ea7c..726d7ce01 100644
--- a/src/crypto/public_key/elliptic/eddsa_legacy.js
+++ b/src/crypto/public_key/elliptic/eddsa_legacy.js
@@ -19,7 +19,6 @@
* @fileoverview Implementation of legacy EdDSA following RFC4880bis-03 for OpenPGP.
* This key type has been deprecated by the crypto-refresh RFC.
* @module crypto/public_key/elliptic/eddsa_legacy
- * @private
*/
import sha512 from 'hash.js/lib/hash/sha/512';
diff --git a/src/crypto/public_key/elliptic/index.js b/src/crypto/public_key/elliptic/index.js
index 562918b94..61a75a235 100644
--- a/src/crypto/public_key/elliptic/index.js
+++ b/src/crypto/public_key/elliptic/index.js
@@ -22,7 +22,6 @@
* @see module:crypto/public_key/elliptic/ecdsa
* @see module:crypto/public_key/elliptic/eddsa
* @module crypto/public_key/elliptic
- * @private
*/
import { CurveWithOID, generate, getPreferredHashAlgo } from './oid_curves';
diff --git a/src/crypto/public_key/elliptic/indutnyKey.js b/src/crypto/public_key/elliptic/indutnyKey.js
index aa7565c5c..ddfc6aa79 100644
--- a/src/crypto/public_key/elliptic/indutnyKey.js
+++ b/src/crypto/public_key/elliptic/indutnyKey.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Wrapper for a KeyPair of an curve from indutny/elliptic library
* @module crypto/public_key/elliptic/indutnyKey
- * @private
*/
import config from '../../../config';
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index e8d563efd..dab26436a 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Wrapper of an instance of an Elliptic Curve
* @module crypto/public_key/elliptic/curve
- * @private
*/
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
diff --git a/src/crypto/public_key/index.js b/src/crypto/public_key/index.js
index 94714eb46..ac34ab76f 100644
--- a/src/crypto/public_key/index.js
+++ b/src/crypto/public_key/index.js
@@ -1,7 +1,6 @@
/**
* @fileoverview Asymmetric cryptography functions
* @module crypto/public_key
- * @private
*/
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js
index 3755d08e7..a7b7cba0e 100644
--- a/src/crypto/public_key/prime.js
+++ b/src/crypto/public_key/prime.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Algorithms for probabilistic random prime generation
* @module crypto/public_key/prime
- * @private
*/
import util from '../../util';
diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js
index 2b24a152c..0a17ff061 100644
--- a/src/crypto/public_key/rsa.js
+++ b/src/crypto/public_key/rsa.js
@@ -18,7 +18,6 @@
/**
* @fileoverview RSA implementation
* @module crypto/public_key/rsa
- * @private
*/
import { randomProbablePrime } from './prime';
diff --git a/src/crypto/random.js b/src/crypto/random.js
index 022bb4aaa..ffef7d653 100644
--- a/src/crypto/random.js
+++ b/src/crypto/random.js
@@ -20,7 +20,6 @@
/**
* @fileoverview Provides tools for retrieving secure randomness from browsers or Node.js
* @module crypto/random
- * @private
*/
import util from '../util';
diff --git a/src/crypto/signature.js b/src/crypto/signature.js
index b4d2aed31..00c7086c1 100644
--- a/src/crypto/signature.js
+++ b/src/crypto/signature.js
@@ -1,7 +1,6 @@
/**
* @fileoverview Provides functions for asymmetric signing and signature verification
* @module crypto/signature
- * @private
*/
import publicKey from './public_key';
diff --git a/src/encoding/base64.js b/src/encoding/base64.js
index dfea632d9..ee95d56b6 100644
--- a/src/encoding/base64.js
+++ b/src/encoding/base64.js
@@ -13,7 +13,6 @@
/**
* @module encoding/base64
- * @private
*/
import * as stream from '@openpgp/web-stream-tools';
diff --git a/src/key/helper.js b/src/key/helper.js
index 05a83331c..a8bc7cf92 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -1,7 +1,6 @@
/**
* @fileoverview Provides helpers methods for key module
* @module key/helper
- * @private
*/
import {
diff --git a/src/key/user.js b/src/key/user.js
index c1e22eb00..49159c5af 100644
--- a/src/key/user.js
+++ b/src/key/user.js
@@ -1,6 +1,5 @@
/**
* @module key/User
- * @private
*/
import enums from '../enums';
diff --git a/src/packet/packet.js b/src/packet/packet.js
index b42e4edf3..c40082f59 100644
--- a/src/packet/packet.js
+++ b/src/packet/packet.js
@@ -18,7 +18,6 @@
/**
* @fileoverview Functions for reading and writing packets
* @module packet/packet
- * @private
*/
import * as stream from '@openpgp/web-stream-tools';
diff --git a/src/type/ecdh_symkey.js b/src/type/ecdh_symkey.js
index 71d05983b..e23fdd840 100644
--- a/src/type/ecdh_symkey.js
+++ b/src/type/ecdh_symkey.js
@@ -19,7 +19,6 @@
* Encoded symmetric key for ECDH (incl. legacy x25519)
*
* @module type/ecdh_symkey
- * @private
*/
import util from '../util';
diff --git a/src/type/keyid.js b/src/type/keyid.js
index 2abf6ae01..76da3e00f 100644
--- a/src/type/keyid.js
+++ b/src/type/keyid.js
@@ -17,7 +17,6 @@
/**
* @module type/keyid
- * @private
*/
import util from '../util';
diff --git a/src/type/oid.js b/src/type/oid.js
index 20278c8a8..370f583a2 100644
--- a/src/type/oid.js
+++ b/src/type/oid.js
@@ -30,7 +30,6 @@
* is constructed by omitting the first two octets. Only the truncated
* sequence of octets is the valid representation of a curve OID.
* @module type/oid
- * @private
*/
import util from '../util';
diff --git a/src/type/s2k/generic.js b/src/type/s2k/generic.js
index ab9b28556..76b81f5bb 100644
--- a/src/type/s2k/generic.js
+++ b/src/type/s2k/generic.js
@@ -25,7 +25,6 @@
* private keyring, and to convert passphrases to encryption keys for
* symmetrically encrypted messages.
* @module type/s2k
- * @private
*/
import defaultConfig from '../../config';
diff --git a/src/util.js b/src/util.js
index 255d020f5..47a02f956 100644
--- a/src/util.js
+++ b/src/util.js
@@ -20,7 +20,6 @@
/**
* This object contains utility functions
* @module util
- * @private
*/
import * as stream from '@openpgp/web-stream-tools';
From 1aefed960278cc59b87d962c6b86f93ac692a370 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 17 May 2023 19:20:22 +0200
Subject: [PATCH 011/224] Fix streaming tests for browser, drop
NodeReadableStream tests in Node.js
Unclear why the Node tests fails, but we're planning to drop support
---
test/general/openpgp.js | 22 +++++-------
test/general/streaming.js | 76 +++++----------------------------------
2 files changed, 16 insertions(+), 82 deletions(-)
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 1d435d605..1039e78de 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -3329,10 +3329,8 @@ XfA3pqV4mTzF
it('Streaming encrypt and decrypt small message roundtrip', async function() {
const plaintext = [];
let i = 0;
- const useNativeStream = (() => { try { new global.ReadableStream(); return true; } catch (e) { return false; } })(); // eslint-disable-line no-new
await loadStreamsPolyfill();
- const GenericReadableStream = useNativeStream ? global.ReadableStream : ReadableStream;
- const data = new GenericReadableStream({
+ const data = new globalThis.ReadableStream({
pull(controller) {
if (i++ < 4) {
const randomBytes = random.getRandomBytes(10);
@@ -3347,7 +3345,7 @@ XfA3pqV4mTzF
message: await openpgp.createMessage({ binary: data }),
passwords: ['test']
}));
- expect(stream.isStream(encrypted)).to.equal(useNativeStream ? 'web' : 'web-like');
+ expect(stream.isStream(encrypted)).to.equal('web');
const message = await openpgp.readMessage({ armoredMessage: encrypted });
const decrypted = await openpgp.decrypt({
@@ -3355,7 +3353,7 @@ XfA3pqV4mTzF
message,
format: 'binary'
});
- expect(stream.isStream(decrypted.data)).to.equal(useNativeStream ? 'web' : 'web-like');
+ expect(stream.isStream(decrypted.data)).to.equal('web');
expect(await stream.readToEnd(decrypted.data)).to.deep.equal(util.concatUint8Array(plaintext));
});
});
@@ -3658,17 +3656,13 @@ XfA3pqV4mTzF
it('should streaming sign and verify binary data without one-pass signature', async function () {
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
- const dataStream = global.ReadableStream ? new global.ReadableStream({
+ const dataStream = new globalThis.ReadableStream({
start(controller) {
controller.enqueue(data);
controller.close();
}
- }) : new (require('stream').Readable)({
- read() {
- this.push(data);
- this.push(null);
- }
});
+
const signOpt = {
message: await openpgp.createMessage({ binary: dataStream }),
signingKeys: privateKey,
@@ -3679,7 +3673,7 @@ XfA3pqV4mTzF
format: 'binary'
};
return openpgp.sign(signOpt).then(async function (signed) {
- expect(stream.isStream(signed)).to.equal(global.ReadableStream ? 'web' : 'node');
+ expect(stream.isStream(signed)).to.equal('web');
const message = await openpgp.readMessage({ binaryMessage: signed });
message.packets.push(...await stream.readToEnd(message.packets.stream, _ => _));
const packets = new openpgp.PacketList();
@@ -3687,12 +3681,12 @@ XfA3pqV4mTzF
packets.push(message.packets.findPacket(openpgp.enums.packet.literalData));
verifyOpt.message = await openpgp.readMessage({
binaryMessage: stream[
- global.ReadableStream ? 'toStream' : 'webToNode'
+ globalThis.ReadableStream ? 'toStream' : 'webToNode'
](packets.write())
});
return openpgp.verify(verifyOpt);
}).then(async function (verified) {
- expect(stream.isStream(verified.data)).to.equal(global.ReadableStream ? 'web' : 'node');
+ expect(stream.isStream(verified.data)).to.equal('web');
expect([].slice.call(await stream.readToEnd(verified.data))).to.deep.equal([].slice.call(data));
expect(await verified.signatures[0].verified).to.be.true;
expect(await privateKey.getSigningKey(verified.signatures[0].keyID))
diff --git a/test/general/streaming.js b/test/general/streaming.js
index 1a1ad5fbb..e4dd91b79 100644
--- a/test/general/streaming.js
+++ b/test/general/streaming.js
@@ -12,9 +12,6 @@ import util from '../../src/util.js';
import * as input from './testInputs.js';
-const useNativeStream = (() => { try { new global.ReadableStream(); return true; } catch (e) { return false; } })(); // eslint-disable-line no-new
-const NodeReadableStream = useNativeStream ? undefined : require('stream').Readable;
-
const detectNode = () => typeof globalThis.process === 'object' && typeof globalThis.process.versions === 'object';
const pub_key = [
@@ -180,18 +177,12 @@ let dataArrived;
function tests() {
it('Encrypt small message', async function() {
dataArrived(); // Do not wait until data arrived.
- const data = global.ReadableStream ? new global.ReadableStream({
+ const data = new globalThis.ReadableStream({
start(controller) {
controller.enqueue(util.stringToUint8Array('hello '));
controller.enqueue(util.stringToUint8Array('world'));
controller.close();
}
- }) : new NodeReadableStream({
- read() {
- this.push(util.stringToUint8Array('hello '));
- this.push(util.stringToUint8Array('world'));
- this.push(null);
- }
});
const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ binary: data }),
@@ -657,18 +648,12 @@ function tests() {
it('Detached sign small message', async function() {
dataArrived(); // Do not wait until data arrived.
- const data = global.ReadableStream ? new global.ReadableStream({
+ const data = new globalThis.ReadableStream({
start(controller) {
controller.enqueue(util.stringToUint8Array('hello '));
controller.enqueue(util.stringToUint8Array('world'));
controller.close();
}
- }) : new NodeReadableStream({
- read() {
- this.push(util.stringToUint8Array('hello '));
- this.push(util.stringToUint8Array('world'));
- this.push(null);
- }
});
const signed = await openpgp.sign({
message: await openpgp.createMessage({ binary: data }),
@@ -692,18 +677,12 @@ function tests() {
it('Detached sign small message using brainpool curve keys', async function() {
dataArrived(); // Do not wait until data arrived.
- const data = global.ReadableStream ? new global.ReadableStream({
+ const data = new globalThis.ReadableStream({
start(controller) {
controller.enqueue(util.stringToUint8Array('hello '));
controller.enqueue(util.stringToUint8Array('world'));
controller.close();
}
- }) : new NodeReadableStream({
- read() {
- this.push(util.stringToUint8Array('hello '));
- this.push(util.stringToUint8Array('world'));
- this.push(null);
- }
});
const pub = await openpgp.readKey({ armoredKey: brainpoolPub });
const priv = await openpgp.decryptKey({
@@ -734,18 +713,12 @@ function tests() {
it('Detached sign small message using curve25519 keys (legacy format)', async function() {
dataArrived(); // Do not wait until data arrived.
- const data = global.ReadableStream ? new global.ReadableStream({
+ const data = new globalThis.ReadableStream({
async start(controller) {
controller.enqueue(util.stringToUint8Array('hello '));
controller.enqueue(util.stringToUint8Array('world'));
controller.close();
}
- }) : new NodeReadableStream({
- read() {
- this.push(util.stringToUint8Array('hello '));
- this.push(util.stringToUint8Array('world'));
- this.push(null);
- }
});
const pub = await openpgp.readKey({ armoredKey: xPub });
const priv = await openpgp.decryptKey({
@@ -843,7 +816,7 @@ function tests() {
const plaintext = [];
let i = 0;
- const data = global.ReadableStream ? new global.ReadableStream({
+ const data = new globalThis.ReadableStream({
async pull(controller) {
await new Promise(resolve => { setTimeout(resolve, 10); });
if (i++ < 10) {
@@ -854,20 +827,6 @@ function tests() {
controller.close();
}
}
- }) : new NodeReadableStream({
- encoding: 'utf8',
- async read() {
- while (true) {
- await new Promise(resolve => { setTimeout(resolve, 10); });
- if (i++ < 10) {
- const randomData = input.createSomeMessage();
- plaintext.push(randomData);
- if (!this.push(randomData)) break;
- } else {
- return this.push(null);
- }
- }
- }
});
const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: data }),
@@ -970,7 +929,7 @@ export default () => describe('Streaming', function() {
plaintext = [];
i = 0;
canceled = false;
- data = global.ReadableStream ? new global.ReadableStream({
+ data = new globalThis.ReadableStream({
async pull(controller) {
await new Promise(setTimeout);
if (test === currentTest && i < (expectedType === 'web' ? 100 : 500)) {
@@ -988,27 +947,8 @@ export default () => describe('Streaming', function() {
}
}, new ByteLengthQueuingStrategy({
highWaterMark: 1024
- })) : new NodeReadableStream({
- highWaterMark: 1024,
- async read() {
- while (true) {
- await new Promise(setTimeout);
- if (test === currentTest && i < (expectedType === 'web' ? 100 : 500)) {
- i++;
- if (i === 4) await dataArrivedPromise;
- const randomBytes = random.getRandomBytes(1024);
- plaintext.push(randomBytes);
- if (!this.push(randomBytes)) break;
- } else {
- return this.push(null);
- }
- }
- },
- destroy() {
- canceled = true;
- }
- });
- expectedType = global.ReadableStream ? 'web' : 'node';
+ }));
+ expectedType = 'web';
});
tests();
From 0b2767fe4c485783e065f88defcbd55aacb76321 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 31 May 2023 15:47:36 +0200
Subject: [PATCH 012/224] Replace pako with fflate as compression lib
fflate already supports ESM and is actively maintained
---
package-lock.json | 26 +++++++--------
package.json | 2 +-
src/packet/compressed_data.js | 63 ++++++++++++++++++++++++-----------
3 files changed, 58 insertions(+), 33 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 676a4bb7f..31e521eed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,6 @@
"@openpgp/asmcrypto.js": "^2.3.2",
"@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
- "@openpgp/pako": "^1.0.12",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
"@openpgp/web-stream-tools": "^0.0.14",
@@ -37,6 +36,7 @@
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
+ "fflate": "^0.7.4",
"hash.js": "^1.1.3",
"http-server": "^14.1.1",
"karma": "^6.4.0",
@@ -660,12 +660,6 @@
"node": ">=10"
}
},
- "node_modules/@openpgp/pako": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/@openpgp/pako/-/pako-1.0.12.tgz",
- "integrity": "sha512-r3+UotSXn4j2snQIuIYjsvA9xzx/5hEPi4vAqHhjhtQ+Q/XyLxYwfJpeIAdJvud6dKp57h48lDQpMkGda4MBQw==",
- "dev": true
- },
"node_modules/@openpgp/seek-bzip": {
"version": "1.0.5-git",
"resolved": "https://registry.npmjs.org/@openpgp/seek-bzip/-/seek-bzip-1.0.5-git.tgz",
@@ -2996,6 +2990,12 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "dev": true
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -8150,12 +8150,6 @@
}
}
},
- "@openpgp/pako": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/@openpgp/pako/-/pako-1.0.12.tgz",
- "integrity": "sha512-r3+UotSXn4j2snQIuIYjsvA9xzx/5hEPi4vAqHhjhtQ+Q/XyLxYwfJpeIAdJvud6dKp57h48lDQpMkGda4MBQw==",
- "dev": true
- },
"@openpgp/seek-bzip": {
"version": "1.0.5-git",
"resolved": "https://registry.npmjs.org/@openpgp/seek-bzip/-/seek-bzip-1.0.5-git.tgz",
@@ -9976,6 +9970,12 @@
"reusify": "^1.0.4"
}
},
+ "fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "dev": true
+ },
"file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
diff --git a/package.json b/package.json
index a24d4c414..96ff8a059 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,6 @@
"@openpgp/asmcrypto.js": "^2.3.2",
"@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
- "@openpgp/pako": "^1.0.12",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
"@openpgp/web-stream-tools": "^0.0.14",
@@ -87,6 +86,7 @@
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
+ "fflate": "^0.7.4",
"hash.js": "^1.1.3",
"http-server": "^14.1.1",
"karma": "^6.4.0",
diff --git a/src/packet/compressed_data.js b/src/packet/compressed_data.js
index e924a46cf..778027e7b 100644
--- a/src/packet/compressed_data.js
+++ b/src/packet/compressed_data.js
@@ -15,9 +15,7 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-import { Deflate } from '@openpgp/pako/lib/deflate';
-import { Inflate } from '@openpgp/pako/lib/inflate';
-import { Z_SYNC_FLUSH, Z_FINISH } from '@openpgp/pako/lib/zlib/constants';
+import { Inflate, Deflate, Zlib, Unzlib } from 'fflate';
import { decode as BunzipDecode } from '@openpgp/seek-bzip';
import * as stream from '@openpgp/web-stream-tools';
import enums from '../enums';
@@ -168,18 +166,45 @@ function node_zlib(func, create, options = {}) {
};
}
-function pako_zlib(constructor, options = {}) {
- return function(data) {
- const obj = new constructor(options);
- return stream.transform(data, value => {
- if (value.length) {
- obj.push(value, Z_SYNC_FLUSH);
- return obj.result;
- }
- }, () => {
- if (constructor === Deflate) {
- obj.push([], Z_FINISH);
- return obj.result;
+function fflate_zlib(ZlibStreamedConstructor, options) {
+ return data => {
+ if (!util.isStream(data) || stream.isArrayStream(data)) {
+ return stream.fromAsync(() => stream.readToEnd(data).then(inputData => {
+ return new Promise((resolve, reject) => {
+ const zlibStream = new ZlibStreamedConstructor(options);
+ zlibStream.ondata = processedData => {
+ resolve(processedData);
+ };
+ try {
+ zlibStream.push(inputData, true); // only one chunk to push
+ } catch (err) {
+ reject(err);
+ }
+ });
+ }));
+ }
+
+ const inputReader = data.getReader();
+ const zlibStream = new ZlibStreamedConstructor(options);
+
+ return new ReadableStream({
+ async start(controller) {
+ zlibStream.ondata = async (value, isLast) => {
+ controller.enqueue(value);
+ if (isLast) {
+ controller.close();
+ }
+ };
+
+ while (true) {
+ const { done, value } = await inputReader.read();
+ if (done) {
+ zlibStream.push(new Uint8Array(), true);
+ return;
+ } else if (value.length) {
+ zlibStream.push(value);
+ }
+ }
}
});
};
@@ -195,8 +220,8 @@ const compress_fns = nodeZlib ? {
zip: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.deflateRaw, nodeZlib.createDeflateRaw, { level })(compressed),
zlib: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.deflate, nodeZlib.createDeflate, { level })(compressed)
} : {
- zip: /*#__PURE__*/ (compressed, level) => pako_zlib(Deflate, { raw: true, level })(compressed),
- zlib: /*#__PURE__*/ (compressed, level) => pako_zlib(Deflate, { level })(compressed)
+ zip: /*#__PURE__*/ (compressed, level) => fflate_zlib(Deflate, { level })(compressed),
+ zlib: /*#__PURE__*/ (compressed, level) => fflate_zlib(Zlib, { level })(compressed)
};
const decompress_fns = nodeZlib ? {
@@ -206,8 +231,8 @@ const decompress_fns = nodeZlib ? {
bzip2: /*#__PURE__*/ bzip2(BunzipDecode)
} : {
uncompressed: uncompressed,
- zip: /*#__PURE__*/ pako_zlib(Inflate, { raw: true }),
- zlib: /*#__PURE__*/ pako_zlib(Inflate),
+ zip: /*#__PURE__*/ fflate_zlib(Inflate),
+ zlib: /*#__PURE__*/ fflate_zlib(Unzlib),
bzip2: /*#__PURE__*/ bzip2(BunzipDecode)
};
From 21a6d83ec81524c87d16382d21b4f75a0ba33493 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 30 May 2023 18:14:01 +0200
Subject: [PATCH 013/224] Update asmcrypto.js, use for AES only (move to
noble-hashes for sha1, sha256)
---
.eslintrc.js => .eslintrc.cjs | 0
package-lock.json | 59 ++++++++++++++++++++++++++++++-----
package.json | 3 +-
src/crypto/cipher/aes.js | 2 +-
src/crypto/cmac.js | 2 +-
src/crypto/hash/index.js | 18 +++++------
src/crypto/mode/cfb.js | 2 +-
src/crypto/mode/eax.js | 2 +-
src/crypto/mode/gcm.js | 2 +-
9 files changed, 68 insertions(+), 22 deletions(-)
rename .eslintrc.js => .eslintrc.cjs (100%)
diff --git a/.eslintrc.js b/.eslintrc.cjs
similarity index 100%
rename from .eslintrc.js
rename to .eslintrc.cjs
diff --git a/package-lock.json b/package-lock.json
index 31e521eed..db59ef68d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,9 +12,10 @@
"asn1.js": "^5.0.0"
},
"devDependencies": {
- "@openpgp/asmcrypto.js": "^2.3.2",
+ "@openpgp/asmcrypto.js": "^3.0.0",
"@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
+ "@openpgp/noble-hashes": "^1.3.2-1",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
"@openpgp/web-stream-tools": "^0.0.14",
@@ -590,9 +591,9 @@
}
},
"node_modules/@openpgp/asmcrypto.js": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@openpgp/asmcrypto.js/-/asmcrypto.js-2.3.2.tgz",
- "integrity": "sha512-CEb3I/Tqg+i5NgEnhYj3fi6XsT5JTuvYdwbMq+STGxlZ8uYSWmYFmVyz9vQgtNwCll/FbB6eR1opa4hoeHGceQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@openpgp/asmcrypto.js/-/asmcrypto.js-3.0.0.tgz",
+ "integrity": "sha512-X/DPYy7uHe+dlY2Botb99uXwb2kXR6HTv0hQOnnI0TVEqOIMQyzCDWAzlX00AacsYryDAphuOndg6mk6wtJCNg==",
"dev": true
},
"node_modules/@openpgp/elliptic": {
@@ -660,6 +661,22 @@
"node": ">=10"
}
},
+ "node_modules/@openpgp/noble-hashes": {
+ "version": "1.3.2-1",
+ "resolved": "https://registry.npmjs.org/@openpgp/noble-hashes/-/noble-hashes-1.3.2-1.tgz",
+ "integrity": "sha512-4pmVh5O+bq1vO4xIAQXh0m7AxasEidFmHA1zm3Fk46IsLObz8pI43EyuLdwqs/6cmL6vAUCde/Xh2MYrVZd5bw==",
+ "dev": true,
+ "dependencies": {
+ "@types/bn.js": "^4.11.6",
+ "bn.js": "^4.11.8"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/@openpgp/seek-bzip": {
"version": "1.0.5-git",
"resolved": "https://registry.npmjs.org/@openpgp/seek-bzip/-/seek-bzip-1.0.5-git.tgz",
@@ -986,6 +1003,15 @@
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
"dev": true
},
+ "node_modules/@types/bn.js": {
+ "version": "4.11.6",
+ "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz",
+ "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/chai": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
@@ -8093,9 +8119,9 @@
}
},
"@openpgp/asmcrypto.js": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@openpgp/asmcrypto.js/-/asmcrypto.js-2.3.2.tgz",
- "integrity": "sha512-CEb3I/Tqg+i5NgEnhYj3fi6XsT5JTuvYdwbMq+STGxlZ8uYSWmYFmVyz9vQgtNwCll/FbB6eR1opa4hoeHGceQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@openpgp/asmcrypto.js/-/asmcrypto.js-3.0.0.tgz",
+ "integrity": "sha512-X/DPYy7uHe+dlY2Botb99uXwb2kXR6HTv0hQOnnI0TVEqOIMQyzCDWAzlX00AacsYryDAphuOndg6mk6wtJCNg==",
"dev": true
},
"@openpgp/elliptic": {
@@ -8150,6 +8176,16 @@
}
}
},
+ "@openpgp/noble-hashes": {
+ "version": "1.3.2-1",
+ "resolved": "https://registry.npmjs.org/@openpgp/noble-hashes/-/noble-hashes-1.3.2-1.tgz",
+ "integrity": "sha512-4pmVh5O+bq1vO4xIAQXh0m7AxasEidFmHA1zm3Fk46IsLObz8pI43EyuLdwqs/6cmL6vAUCde/Xh2MYrVZd5bw==",
+ "dev": true,
+ "requires": {
+ "@types/bn.js": "^4.11.6",
+ "bn.js": "^4.11.8"
+ }
+ },
"@openpgp/seek-bzip": {
"version": "1.0.5-git",
"resolved": "https://registry.npmjs.org/@openpgp/seek-bzip/-/seek-bzip-1.0.5-git.tgz",
@@ -8374,6 +8410,15 @@
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
"dev": true
},
+ "@types/bn.js": {
+ "version": "4.11.6",
+ "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz",
+ "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/chai": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
diff --git a/package.json b/package.json
index 96ff8a059..b2dbd3478 100644
--- a/package.json
+++ b/package.json
@@ -62,9 +62,10 @@
"postversion": "git push && git push --tags && npm publish"
},
"devDependencies": {
- "@openpgp/asmcrypto.js": "^2.3.2",
+ "@openpgp/asmcrypto.js": "^3.0.0",
"@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
+ "@openpgp/noble-hashes": "^1.3.2-1",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
"@openpgp/web-stream-tools": "^0.0.14",
diff --git a/src/crypto/cipher/aes.js b/src/crypto/cipher/aes.js
index 8a985079c..0ef89041d 100644
--- a/src/crypto/cipher/aes.js
+++ b/src/crypto/cipher/aes.js
@@ -1,4 +1,4 @@
-import { AES_ECB } from '@openpgp/asmcrypto.js/dist_es8/aes/ecb';
+import { AES_ECB } from '@openpgp/asmcrypto.js/aes/ecb.js';
/**
* Javascript AES implementation.
diff --git a/src/crypto/cmac.js b/src/crypto/cmac.js
index e838bd6f0..8c20afc74 100644
--- a/src/crypto/cmac.js
+++ b/src/crypto/cmac.js
@@ -4,7 +4,7 @@
* @module crypto/cmac
*/
-import { AES_CBC } from '@openpgp/asmcrypto.js/dist_es8/aes/cbc';
+import { AES_CBC } from '@openpgp/asmcrypto.js/aes/cbc.js';
import util from '../util';
const webCrypto = util.getWebCrypto();
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index d5752841a..a3dc6972b 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -5,8 +5,8 @@
* @module crypto/hash
*/
-import { Sha1 } from '@openpgp/asmcrypto.js/dist_es8/hash/sha1/sha1';
-import { Sha256 } from '@openpgp/asmcrypto.js/dist_es8/hash/sha256/sha256';
+import { sha1 } from '@openpgp/noble-hashes/sha1';
+import { sha256 } from '@openpgp/noble-hashes/sha256';
import sha224 from 'hash.js/lib/hash/sha/224';
import sha384 from 'hash.js/lib/hash/sha/384';
import sha512 from 'hash.js/lib/hash/sha/512';
@@ -48,29 +48,29 @@ function hashjsHash(hash, webCryptoHash) {
};
}
-function asmcryptoHash(hash, webCryptoHash) {
+function nobleHash(hash, webCryptoHash) {
return async function(data, config = defaultConfig) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
if (util.isStream(data)) {
- const hashInstance = new hash();
+ const hashInstance = hash.create();
return stream.transform(data, value => {
- hashInstance.process(value);
- }, () => hashInstance.finish().result);
+ hashInstance.update(value);
+ }, () => hashInstance.digest());
} else if (webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
} else {
- return hash.bytes(data);
+ return hash(data);
}
};
}
const hashFunctions = {
md5: nodeHash('md5') || md5,
- sha1: nodeHash('sha1') || asmcryptoHash(Sha1, 'SHA-1'),
+ sha1: nodeHash('sha1') || nobleHash(sha1, 'SHA-1'),
sha224: nodeHash('sha224') || hashjsHash(sha224),
- sha256: nodeHash('sha256') || asmcryptoHash(Sha256, 'SHA-256'),
+ sha256: nodeHash('sha256') || nobleHash(sha256, 'SHA-256'),
sha384: nodeHash('sha384') || hashjsHash(sha384, 'SHA-384'),
sha512: nodeHash('sha512') || hashjsHash(sha512, 'SHA-512'), // asmcrypto sha512 is huge.
ripemd: nodeHash('ripemd160') || hashjsHash(ripemd160)
diff --git a/src/crypto/mode/cfb.js b/src/crypto/mode/cfb.js
index a1bdb5260..bca035639 100644
--- a/src/crypto/mode/cfb.js
+++ b/src/crypto/mode/cfb.js
@@ -21,7 +21,7 @@
* @module crypto/mode/cfb
*/
-import { AES_CFB } from '@openpgp/asmcrypto.js/dist_es8/aes/cfb';
+import { AES_CFB } from '@openpgp/asmcrypto.js/aes/cfb.js';
import * as stream from '@openpgp/web-stream-tools';
import getCipher from '../cipher/getCipher';
import util from '../../util';
diff --git a/src/crypto/mode/eax.js b/src/crypto/mode/eax.js
index 4917ba1cf..433d4485f 100644
--- a/src/crypto/mode/eax.js
+++ b/src/crypto/mode/eax.js
@@ -21,7 +21,7 @@
* @module crypto/mode/eax
*/
-import { AES_CTR } from '@openpgp/asmcrypto.js/dist_es8/aes/ctr';
+import { AES_CTR } from '@openpgp/asmcrypto.js/aes/ctr.js';
import CMAC from '../cmac';
import util from '../../util';
import enums from '../../enums';
diff --git a/src/crypto/mode/gcm.js b/src/crypto/mode/gcm.js
index c5b5e332d..0088b58b9 100644
--- a/src/crypto/mode/gcm.js
+++ b/src/crypto/mode/gcm.js
@@ -21,7 +21,7 @@
* @module crypto/mode/gcm
*/
-import { AES_GCM } from '@openpgp/asmcrypto.js/dist_es8/aes/gcm';
+import { AES_GCM } from '@openpgp/asmcrypto.js/aes/gcm.js';
import util from '../../util';
import enums from '../../enums';
From 2377b2958d297f553ae062aed50dc1c5d4a08b5f Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 30 May 2023 22:19:00 +0200
Subject: [PATCH 014/224] Use WebCrypto for streamed CFB encryption; for
CFB/GCM/EAX, fallback to asmcrypto only if key size is not supported
CFB decryption is too slow using WebCrypto (CBC mode), since every block needs to be decrypted separately
---
src/crypto/cmac.js | 25 ++++++--
src/crypto/mode/cfb.js | 141 ++++++++++++++++++++++++++++++++++-------
src/crypto/mode/eax.js | 28 +++++---
src/crypto/mode/gcm.js | 47 ++++++++------
4 files changed, 183 insertions(+), 58 deletions(-)
diff --git a/src/crypto/cmac.js b/src/crypto/cmac.js
index 8c20afc74..19d996a83 100644
--- a/src/crypto/cmac.js
+++ b/src/crypto/cmac.js
@@ -72,13 +72,6 @@ export default async function CMAC(key) {
}
async function CBC(key) {
- if (util.getWebCrypto() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
- key = await webCrypto.importKey('raw', key, { name: 'AES-CBC', length: key.length * 8 }, false, ['encrypt']);
- return async function(pt) {
- const ct = await webCrypto.encrypt({ name: 'AES-CBC', iv: zeroBlock, length: blockLength * 8 }, key, pt);
- return new Uint8Array(ct).subarray(0, ct.byteLength - blockLength);
- };
- }
if (util.getNodeCrypto()) { // Node crypto library
return async function(pt) {
const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-cbc', key, zeroBlock);
@@ -86,6 +79,24 @@ async function CBC(key) {
return new Uint8Array(ct);
};
}
+
+ if (util.getWebCrypto()) {
+ try {
+ key = await webCrypto.importKey('raw', key, { name: 'AES-CBC', length: key.length * 8 }, false, ['encrypt']);
+ return async function(pt) {
+ const ct = await webCrypto.encrypt({ name: 'AES-CBC', iv: zeroBlock, length: blockLength * 8 }, key, pt);
+ return new Uint8Array(ct).subarray(0, ct.byteLength - blockLength);
+ };
+ } catch (err) {
+ // no 192 bit support in Chromium, which throws `OperationError`, see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
+ if (err.name !== 'NotSupportedError' &&
+ !(key.length === 24 && err.name === 'OperationError')) {
+ throw err;
+ }
+ util.printDebugError('Browser did not support operation: ' + err.message);
+ }
+ }
+
// asm.js fallback
return async function(pt) {
return AES_CBC.encrypt(pt, key, false, zeroBlock);
diff --git a/src/crypto/mode/cfb.js b/src/crypto/mode/cfb.js
index bca035639..6fce90c1e 100644
--- a/src/crypto/mode/cfb.js
+++ b/src/crypto/mode/cfb.js
@@ -96,7 +96,7 @@ export async function encrypt(algo, key, plaintext, iv, config) {
*/
export async function decrypt(algo, key, ciphertext, iv) {
const algoName = enums.read(enums.symmetric, algo);
- if (util.getNodeCrypto() && nodeAlgos[algoName]) { // Node crypto library.
+ if (nodeCrypto && nodeAlgos[algoName]) { // Node crypto library.
return nodeDecrypt(algo, key, ciphertext, iv);
}
if (util.isAES(algo)) {
@@ -129,18 +129,122 @@ export async function decrypt(algo, key, ciphertext, iv) {
return stream.transform(ciphertext, process, process);
}
-function aesEncrypt(algo, key, pt, iv, config) {
- if (
- util.getWebCrypto() &&
- key.length !== 24 && // Chrome doesn't support 192 bit keys, see https://www.chromium.org/blink/webcrypto#TOC-AES-support
- !util.isStream(pt) &&
- pt.length >= 3000 * config.minBytesForWebCrypto // Default to a 3MB minimum. Chrome is pretty slow for small messages, see: https://bugs.chromium.org/p/chromium/issues/detail?id=701188#c2
- ) { // Web Crypto
- return webEncrypt(algo, key, pt, iv);
+class WebCryptoEncryptor {
+ constructor(algo, key, iv) {
+ const { blockSize } = getCipher(algo);
+ this.key = key;
+ this.prevBlock = iv;
+ this.nextBlock = new Uint8Array(blockSize);
+ this.i = 0; // pointer inside next block
+ this.blockSize = blockSize;
+ this.zeroBlock = new Uint8Array(this.blockSize);
+ }
+
+ static async isSupported(algo) {
+ const { keySize } = getCipher(algo);
+ return webCrypto.importKey('raw', new Uint8Array(keySize), 'aes-cbc', false, ['encrypt'])
+ .then(() => true, () => false);
+ }
+
+ async _runCBC(plaintext, nonZeroIV) {
+ const mode = 'AES-CBC';
+ this.keyRef = this.keyRef || await webCrypto.importKey('raw', this.key, mode, false, ['encrypt']);
+ const ciphertext = await webCrypto.encrypt(
+ { name: mode, iv: nonZeroIV || this.zeroBlock },
+ this.keyRef,
+ plaintext
+ );
+ return new Uint8Array(ciphertext).subarray(0, plaintext.length);
+ }
+
+ async encryptChunk(value) {
+ const missing = this.nextBlock.length - this.i;
+ const added = value.subarray(0, missing);
+ this.nextBlock.set(added, this.i);
+ if ((this.i + value.length) >= (2 * this.blockSize)) {
+ const leftover = (value.length - missing) % this.blockSize;
+ const plaintext = util.concatUint8Array([
+ this.nextBlock,
+ value.subarray(missing, value.length - leftover)
+ ]);
+ const toEncrypt = util.concatUint8Array([
+ this.prevBlock,
+ plaintext.subarray(0, plaintext.length - this.blockSize) // stop one block "early", since we only need to xor the plaintext and pass it over as prevBlock
+ ]);
+
+ const encryptedBlocks = await this._runCBC(toEncrypt);
+ xorMut(encryptedBlocks, plaintext);
+ this.prevBlock = encryptedBlocks.subarray(-this.blockSize).slice();
+
+ // take care of leftover data
+ if (leftover > 0) this.nextBlock.set(value.subarray(-leftover).slice());
+ this.i = leftover;
+
+ return encryptedBlocks;
+ }
+
+ this.i += added.length;
+ let encryptedBlock = new Uint8Array();
+ if (this.i === this.nextBlock.length) { // block ready to be encrypted
+ const curBlock = this.nextBlock;
+ encryptedBlock = await this._runCBC(this.prevBlock);
+ xorMut(encryptedBlock, curBlock);
+ this.prevBlock = encryptedBlock.slice();
+ this.i = 0;
+
+ const remaining = value.subarray(added.length);
+ this.nextBlock.set(remaining, this.i);
+ this.i += remaining.length;
+ }
+
+ return encryptedBlock;
+ }
+
+ async finish() {
+ let result;
+ if (this.i === 0) { // nothing more to encrypt
+ result = new Uint8Array();
+ } else {
+ this.nextBlock = this.nextBlock.subarray(0, this.i);
+ const curBlock = this.nextBlock;
+ const encryptedBlock = await this._runCBC(this.prevBlock);
+ xorMut(encryptedBlock, curBlock);
+ result = encryptedBlock.subarray(0, curBlock.length);
+ }
+
+ this.clearSensitiveData();
+ return result;
+ }
+
+ clearSensitiveData() {
+ this.nextBlock.fill(0);
+ this.prevBlock.fill(0);
+ this.keyRef = null;
+ this.key = null;
+ }
+
+ async encrypt(plaintext) {
+ // plaintext is internally padded to block length before encryption
+ const encryptedWithPadding = await this._runCBC(
+ util.concatUint8Array([new Uint8Array(this.blockSize), plaintext]),
+ this.iv
+ );
+ // drop encrypted padding
+ const ct = encryptedWithPadding.subarray(0, plaintext.length);
+ xorMut(ct, plaintext);
+ this.clearSensitiveData();
+ return ct;
+ }
+}
+
+async function aesEncrypt(algo, key, pt, iv) {
+ if (webCrypto && await WebCryptoEncryptor.isSupported(algo)) { // Chromium does not implement AES with 192-bit keys
+ const cfb = new WebCryptoEncryptor(algo, key, iv);
+ return util.isStream(pt) ? stream.transform(pt, value => cfb.encryptChunk(value), () => cfb.finish()) : cfb.encrypt(pt);
+ } else {
+ const cfb = new AES_CFB(key, iv);
+ return stream.transform(pt, value => cfb.aes.AES_Encrypt_process(value), () => cfb.aes.AES_Encrypt_finish());
}
- // asm.js fallback
- const cfb = new AES_CFB(key, iv);
- return stream.transform(pt, value => cfb.aes.AES_Encrypt_process(value), () => cfb.aes.AES_Encrypt_finish());
}
function aesDecrypt(algo, key, ct, iv) {
@@ -152,21 +256,12 @@ function aesDecrypt(algo, key, ct, iv) {
}
function xorMut(a, b) {
- for (let i = 0; i < a.length; i++) {
+ const aLength = Math.min(a.length, b.length);
+ for (let i = 0; i < aLength; i++) {
a[i] = a[i] ^ b[i];
}
}
-async function webEncrypt(algo, key, pt, iv) {
- const ALGO = 'AES-CBC';
- const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt']);
- const { blockSize } = getCipher(algo);
- const cbc_pt = util.concatUint8Array([new Uint8Array(blockSize), pt]);
- const ct = new Uint8Array(await webCrypto.encrypt({ name: ALGO, iv }, _key, cbc_pt)).subarray(0, pt.length);
- xorMut(ct, pt);
- return ct;
-}
-
function nodeEncrypt(algo, key, pt, iv) {
const algoName = enums.read(enums.symmetric, algo);
const cipherObj = new nodeCrypto.createCipheriv(nodeAlgos[algoName], key, iv);
diff --git a/src/crypto/mode/eax.js b/src/crypto/mode/eax.js
index 433d4485f..ab64ec6bd 100644
--- a/src/crypto/mode/eax.js
+++ b/src/crypto/mode/eax.js
@@ -47,16 +47,6 @@ async function OMAC(key) {
}
async function CTR(key) {
- if (
- util.getWebCrypto() &&
- key.length !== 24 // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
- ) {
- key = await webCrypto.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']);
- return async function(pt, iv) {
- const ct = await webCrypto.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength * 8 }, key, pt);
- return new Uint8Array(ct);
- };
- }
if (util.getNodeCrypto()) { // Node crypto library
return async function(pt, iv) {
const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-ctr', key, iv);
@@ -64,6 +54,24 @@ async function CTR(key) {
return new Uint8Array(ct);
};
}
+
+ if (util.getWebCrypto()) {
+ try {
+ const keyRef = await webCrypto.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']);
+ return async function(pt, iv) {
+ const ct = await webCrypto.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength * 8 }, keyRef, pt);
+ return new Uint8Array(ct);
+ };
+ } catch (err) {
+ // no 192 bit support in Chromium, which throws `OperationError`, see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
+ if (err.name !== 'NotSupportedError' &&
+ !(key.length === 24 && err.name === 'OperationError')) {
+ throw err;
+ }
+ util.printDebugError('Browser did not support operation: ' + err.message);
+ }
+ }
+
// asm.js fallback
return async function(pt, iv) {
return AES_CTR.encrypt(pt, key, iv);
diff --git a/src/crypto/mode/gcm.js b/src/crypto/mode/gcm.js
index 0088b58b9..a3cbd941c 100644
--- a/src/crypto/mode/gcm.js
+++ b/src/crypto/mode/gcm.js
@@ -65,26 +65,37 @@ async function GCM(cipher, key) {
};
}
- if (util.getWebCrypto() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
- const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt', 'decrypt']);
-
- return {
- encrypt: async function(pt, iv, adata = new Uint8Array()) {
- if (!pt.length) { // iOS does not support GCM-en/decrypting empty messages
- return AES_GCM.encrypt(pt, key, iv, adata);
+ if (util.getWebCrypto()) {
+ try {
+ const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt', 'decrypt']);
+ // Safari 13 and Safari iOS 14 does not support GCM-en/decrypting empty messages
+ const webcryptoEmptyMessagesUnsupported = navigator.userAgent.match(/Version\/13\.\d(\.\d)* Safari/) ||
+ navigator.userAgent.match(/Version\/(13|14)\.\d(\.\d)* Mobile\/\S* Safari/);
+ return {
+ encrypt: async function(pt, iv, adata = new Uint8Array()) {
+ if (webcryptoEmptyMessagesUnsupported && !pt.length) {
+ return AES_GCM.encrypt(pt, key, iv, adata);
+ }
+ const ct = await webCrypto.encrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength * 8 }, _key, pt);
+ return new Uint8Array(ct);
+ },
+
+ decrypt: async function(ct, iv, adata = new Uint8Array()) {
+ if (webcryptoEmptyMessagesUnsupported && ct.length === tagLength) {
+ return AES_GCM.decrypt(ct, key, iv, adata);
+ }
+ const pt = await webCrypto.decrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength * 8 }, _key, ct);
+ return new Uint8Array(pt);
}
- const ct = await webCrypto.encrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength * 8 }, _key, pt);
- return new Uint8Array(ct);
- },
-
- decrypt: async function(ct, iv, adata = new Uint8Array()) {
- if (ct.length === tagLength) { // iOS does not support GCM-en/decrypting empty messages
- return AES_GCM.decrypt(ct, key, iv, adata);
- }
- const pt = await webCrypto.decrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength * 8 }, _key, ct);
- return new Uint8Array(pt);
+ };
+ } catch (err) {
+ // no 192 bit support in Chromium, which throws `OperationError`, see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
+ if (err.name !== 'NotSupportedError' &&
+ !(key.length === 24 && err.name === 'OperationError')) {
+ throw err;
}
- };
+ util.printDebugError('Browser did not support operation: ' + err.message);
+ }
}
return {
From 6d477ea509a7022fb44e2a8f7381f47b9485f39b Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 31 May 2023 10:38:18 +0200
Subject: [PATCH 015/224] Add time benchmark test for streamed sign (testing
hashing performance)
---
test/benchmarks/time.js | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/test/benchmarks/time.js b/test/benchmarks/time.js
index e86340f79..24ba752ac 100644
--- a/test/benchmarks/time.js
+++ b/test/benchmarks/time.js
@@ -1,4 +1,5 @@
import Benchmark from 'benchmark';
+import { readToEnd } from '@openpgp/web-stream-tools';
import * as openpgp from 'openpgp';
const wrapAsync = func => ({
@@ -25,6 +26,22 @@ const onError = err => {
(async () => {
const suite = new Benchmark.Suite();
const { armoredKey, privateKey, publicKey, armoredEncryptedMessage, armoredSignedMessage } = await getTestData();
+ function* largeDataGenerator({ chunk, numberOfChunks }) {
+ for (let chunkNumber = 0; chunkNumber < numberOfChunks; chunkNumber++) {
+ yield chunk;
+ }
+ }
+
+ const streamFromGenerator = it => new ReadableStream({
+ pull: controller => {
+ const { value, done } = it.next();
+ if (done) {
+ controller.close();
+ } else {
+ controller.enqueue(value);
+ }
+ }
+ });
suite.add('openpgp.readKey', wrapAsync(async () => {
await openpgp.readKey({ armoredKey });
@@ -48,6 +65,14 @@ const onError = err => {
await openpgp.sign({ message, signingKeys: privateKey });
}));
+ suite.add('openpgp.sign (stream)', wrapAsync(async () => {
+ const inputStream = streamFromGenerator(largeDataGenerator({ chunk: new Uint8Array(10000), numberOfChunks: 10 }));
+ const message = await openpgp.createMessage({ binary: inputStream });
+ const signed = await openpgp.sign({ message, signingKeys: privateKey });
+
+ await readToEnd(signed);
+ }));
+
suite.add('openpgp.decrypt', wrapAsync(async () => {
const message = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
await openpgp.decrypt({ message, decryptionKeys: privateKey });
From b3574d6b3e641fb44a7e65b2e8c539d4910793e5 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 31 May 2023 16:31:52 +0200
Subject: [PATCH 016/224] CI: test all Node.js version even if some fail
---
.github/workflows/tests.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 4c55e9917..53feed35d 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -29,6 +29,7 @@ jobs:
node:
strategy:
+ fail-fast: false # if tests for one version fail, continue with the rest
matrix:
node-version: [16.x, 18.x, '20.x']
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
From b3ef95e60ebb53058141a3c06dbdea200192afb0 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 1 Jun 2023 16:28:45 +0200
Subject: [PATCH 017/224] Tests: update sinon
---
package-lock.json | 251 +++++++++++++++-----------------------
package.json | 2 +-
test/crypto/crypto.js | 14 ---
test/crypto/eax.js | 6 +-
test/crypto/ecdh.js | 4 +-
test/crypto/elliptic.js | 4 +-
test/crypto/gcm.js | 4 +-
test/crypto/rsa.js | 4 +-
test/general/openpgp.js | 6 +-
test/general/packet.js | 10 +-
test/general/streaming.js | 4 +-
11 files changed, 118 insertions(+), 191 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index db59ef68d..b3eb33102 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,7 +51,7 @@
"nyc": "^14.1.1",
"playwright": "^1.30.0",
"rollup": "^2.79.1",
- "sinon": "^4.3.0",
+ "sinon": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^4.1.2",
"web-streams-polyfill": "^3.2.0"
@@ -939,32 +939,41 @@
}
},
"node_modules/@sinonjs/commons": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
- "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
+ "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
"dev": true,
"dependencies": {
"type-detect": "4.0.8"
}
},
- "node_modules/@sinonjs/formatio": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
- "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==",
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.2.0.tgz",
+ "integrity": "sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg==",
"dev": true,
"dependencies": {
- "samsam": "1.3.0"
+ "@sinonjs/commons": "^3.0.0"
}
},
"node_modules/@sinonjs/samsam": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz",
- "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz",
+ "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==",
"dev": true,
"dependencies": {
- "@sinonjs/commons": "^1.3.0",
- "array-from": "^2.1.1",
- "lodash": "^4.17.15"
+ "@sinonjs/commons": "^2.0.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "4.0.8"
}
},
"node_modules/@sinonjs/text-encoding": {
@@ -1261,12 +1270,6 @@
"node": ">=6.0"
}
},
- "node_modules/array-from": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
- "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==",
- "dev": true
- },
"node_modules/array-includes": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
@@ -2090,9 +2093,9 @@
"dev": true
},
"node_modules/diff": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
- "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
+ "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
"dev": true,
"engines": {
"node": ">=0.3.1"
@@ -4863,12 +4866,6 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
- "node_modules/lolex": {
- "version": "2.7.5",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz",
- "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==",
- "dev": true
- },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5443,35 +5440,25 @@
"dev": true
},
"node_modules/nise": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz",
- "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz",
+ "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==",
"dev": true,
"dependencies": {
- "@sinonjs/formatio": "^3.2.1",
+ "@sinonjs/commons": "^2.0.0",
+ "@sinonjs/fake-timers": "^10.0.2",
"@sinonjs/text-encoding": "^0.7.1",
"just-extend": "^4.0.2",
- "lolex": "^5.0.1",
"path-to-regexp": "^1.7.0"
}
},
- "node_modules/nise/node_modules/@sinonjs/formatio": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz",
- "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==",
- "dev": true,
- "dependencies": {
- "@sinonjs/commons": "^1",
- "@sinonjs/samsam": "^3.1.0"
- }
- },
- "node_modules/nise/node_modules/lolex": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz",
- "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==",
+ "node_modules/nise/node_modules/@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
"dev": true,
"dependencies": {
- "@sinonjs/commons": "^1.7.0"
+ "type-detect": "4.0.8"
}
},
"node_modules/normalize-package-data": {
@@ -6355,13 +6342,6 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
- "node_modules/samsam": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz",
- "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==",
- "deprecated": "This package has been deprecated in favour of @sinonjs/samsam",
- "dev": true
- },
"node_modules/secure-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
@@ -6431,31 +6411,21 @@
"dev": true
},
"node_modules/sinon": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz",
- "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "@sinonjs/formatio": "^2.0.0",
- "diff": "^3.1.0",
- "lodash.get": "^4.4.2",
- "lolex": "^2.2.0",
- "nise": "^1.2.0",
- "supports-color": "^5.1.0",
- "type-detect": "^4.0.5"
- }
- },
- "node_modules/sinon/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.1.0.tgz",
+ "integrity": "sha512-cS5FgpDdE9/zx7no8bxROHymSlPLZzq0ChbbLk1DrxBfc+eTeBK3y8nIL+nu/0QeYydhhbLIr7ecHJpywjQaoQ==",
"dev": true,
"dependencies": {
- "has-flag": "^3.0.0"
+ "@sinonjs/commons": "^3.0.0",
+ "@sinonjs/fake-timers": "^10.2.0",
+ "@sinonjs/samsam": "^8.0.0",
+ "diff": "^5.1.0",
+ "nise": "^5.1.4",
+ "supports-color": "^7.2.0"
},
- "engines": {
- "node": ">=4"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/sinon"
}
},
"node_modules/slash": {
@@ -8346,32 +8316,43 @@
}
},
"@sinonjs/commons": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
- "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
+ "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
}
},
- "@sinonjs/formatio": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
- "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==",
+ "@sinonjs/fake-timers": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.2.0.tgz",
+ "integrity": "sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg==",
"dev": true,
"requires": {
- "samsam": "1.3.0"
+ "@sinonjs/commons": "^3.0.0"
}
},
"@sinonjs/samsam": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz",
- "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz",
+ "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==",
"dev": true,
"requires": {
- "@sinonjs/commons": "^1.3.0",
- "array-from": "^2.1.1",
- "lodash": "^4.17.15"
+ "@sinonjs/commons": "^2.0.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ },
+ "dependencies": {
+ "@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+ "dev": true,
+ "requires": {
+ "type-detect": "4.0.8"
+ }
+ }
}
},
"@sinonjs/text-encoding": {
@@ -8625,12 +8606,6 @@
"@babel/runtime-corejs3": "^7.10.2"
}
},
- "array-from": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
- "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==",
- "dev": true
- },
"array-includes": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
@@ -9280,9 +9255,9 @@
"dev": true
},
"diff": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
- "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
+ "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
"dev": true
},
"doctrine": {
@@ -11444,12 +11419,6 @@
}
}
},
- "lolex": {
- "version": "2.7.5",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz",
- "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==",
- "dev": true
- },
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -11896,35 +11865,25 @@
"dev": true
},
"nise": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz",
- "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz",
+ "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==",
"dev": true,
"requires": {
- "@sinonjs/formatio": "^3.2.1",
+ "@sinonjs/commons": "^2.0.0",
+ "@sinonjs/fake-timers": "^10.0.2",
"@sinonjs/text-encoding": "^0.7.1",
"just-extend": "^4.0.2",
- "lolex": "^5.0.1",
"path-to-regexp": "^1.7.0"
},
"dependencies": {
- "@sinonjs/formatio": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz",
- "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==",
- "dev": true,
- "requires": {
- "@sinonjs/commons": "^1",
- "@sinonjs/samsam": "^3.1.0"
- }
- },
- "lolex": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz",
- "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==",
+ "@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
"dev": true,
"requires": {
- "@sinonjs/commons": "^1.7.0"
+ "type-detect": "4.0.8"
}
}
}
@@ -12574,12 +12533,6 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
- "samsam": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz",
- "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==",
- "dev": true
- },
"secure-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
@@ -12637,29 +12590,17 @@
"dev": true
},
"sinon": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz",
- "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==",
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.1.0.tgz",
+ "integrity": "sha512-cS5FgpDdE9/zx7no8bxROHymSlPLZzq0ChbbLk1DrxBfc+eTeBK3y8nIL+nu/0QeYydhhbLIr7ecHJpywjQaoQ==",
"dev": true,
"requires": {
- "@sinonjs/formatio": "^2.0.0",
- "diff": "^3.1.0",
- "lodash.get": "^4.4.2",
- "lolex": "^2.2.0",
- "nise": "^1.2.0",
- "supports-color": "^5.1.0",
- "type-detect": "^4.0.5"
- },
- "dependencies": {
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
+ "@sinonjs/commons": "^3.0.0",
+ "@sinonjs/fake-timers": "^10.2.0",
+ "@sinonjs/samsam": "^8.0.0",
+ "diff": "^5.1.0",
+ "nise": "^5.1.4",
+ "supports-color": "^7.2.0"
}
},
"slash": {
diff --git a/package.json b/package.json
index b2dbd3478..5486f1948 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,7 @@
"nyc": "^14.1.1",
"playwright": "^1.30.0",
"rollup": "^2.79.1",
- "sinon": "^4.3.0",
+ "sinon": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^4.1.2",
"web-streams-polyfill": "^3.2.0"
diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js
index 05d898807..e5bbeaf92 100644
--- a/test/crypto/crypto.js
+++ b/test/crypto/crypto.js
@@ -2,7 +2,6 @@ import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
-import sandbox from 'sinon/lib/sinon/sandbox';
import openpgp from '../initOpenpgp.js';
import crypto from '../../src/crypto';
import util from '../../src/util.js';
@@ -253,19 +252,6 @@ export default () => describe('API functional testing', function() {
await testCFB('1234567');
await testCFB('foobarfoobar1234567890');
await testCFB('12345678901234567890123456789012345678901234567890');
- // test using webCrypto
- const sinonSandbox = sandbox.create();
- const webCrypto = util.getWebCrypto();
- if (webCrypto && !util.getNodeCrypto()) {
- const webCryptoSpy = sinonSandbox.spy(webCrypto, 'encrypt');
- try {
- await testCFB('12345678901234567890123456789012345678901234567890', { ...openpgp.config, minBytesForWebCrypto: 0 });
- } finally {
- expect(webCryptoSpy.called).to.be.true;
- sinonSandbox.restore();
- }
- }
-
});
it('Asymmetric using RSA with eme_pkcs1 padding', function () {
diff --git a/test/crypto/eax.js b/test/crypto/eax.js
index 54023f46c..d5191b376 100644
--- a/test/crypto/eax.js
+++ b/test/crypto/eax.js
@@ -1,7 +1,7 @@
// Modified by ProtonTech AG
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
-import sandbox from 'sinon/lib/sinon/sandbox';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -148,7 +148,7 @@ export default () => describe('Symmetric AES-EAX', function() {
});
beforeEach(function () {
- sinonSandbox = sandbox.create();
+ sinonSandbox = sinon.createSandbox();
enableNative();
});
@@ -161,7 +161,7 @@ export default () => describe('Symmetric AES-EAX', function() {
describe('Symmetric AES-EAX (asm.js fallback)', function() {
beforeEach(function () {
- sinonSandbox = sandbox.create();
+ sinonSandbox = sinon.createSandbox();
disableNative();
});
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index 35ae5c3ad..501f04814 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -1,4 +1,4 @@
-import sandbox from 'sinon/lib/sinon/sandbox';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -208,7 +208,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
let getNodeCryptoStub;
beforeEach(function () {
- sinonSandbox = sandbox.create();
+ sinonSandbox = sinon.createSandbox();
});
afterEach(function () {
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index c92102b1b..f34660e05 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -1,4 +1,4 @@
-import sandbox from 'sinon/lib/sinon/sandbox';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -104,7 +104,7 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
let getNodeCryptoStub;
beforeEach(function () {
- sinonSandbox = sandbox.create();
+ sinonSandbox = sinon.createSandbox();
});
afterEach(function () {
diff --git a/test/crypto/gcm.js b/test/crypto/gcm.js
index 441d6f9c4..f564c4007 100644
--- a/test/crypto/gcm.js
+++ b/test/crypto/gcm.js
@@ -1,4 +1,4 @@
-import sandbox from 'sinon/lib/sinon/sandbox';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -14,7 +14,7 @@ export default () => describe('Symmetric AES-GCM (experimental)', function() {
let getNodeCryptoStub;
beforeEach(function () {
- sinonSandbox = sandbox.create();
+ sinonSandbox = sinon.createSandbox();
enableNative();
});
diff --git a/test/crypto/rsa.js b/test/crypto/rsa.js
index 1be4a1271..21739fe58 100644
--- a/test/crypto/rsa.js
+++ b/test/crypto/rsa.js
@@ -1,4 +1,4 @@
-import sandbox from 'sinon/lib/sinon/sandbox';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -15,7 +15,7 @@ export default () => describe('basic RSA cryptography', function () {
let getNodeCryptoStub;
beforeEach(function () {
- sinonSandbox = sandbox.create();
+ sinonSandbox = sinon.createSandbox();
enableNative();
});
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 1039e78de..063265183 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1,6 +1,6 @@
/* eslint-disable max-lines */
/* globals tryTests, loadStreamsPolyfill */
-import spy from 'sinon/lib/sinon/spy';
+import sinon from 'sinon';
import * as stream from '@openpgp/web-stream-tools';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
@@ -865,8 +865,8 @@ function withCompression(tests) {
let decompressSpy;
beforeEach(function () {
- compressSpy = spy(openpgp.CompressedDataPacket.prototype, 'compress');
- decompressSpy = spy(openpgp.CompressedDataPacket.prototype, 'decompress');
+ compressSpy = sinon.spy(openpgp.CompressedDataPacket.prototype, 'compress');
+ decompressSpy = sinon.spy(openpgp.CompressedDataPacket.prototype, 'decompress');
});
afterEach(function () {
diff --git a/test/general/packet.js b/test/general/packet.js
index 5590e6cd9..ced7121cf 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -1,6 +1,6 @@
/* eslint-disable max-lines */
import * as stream from '@openpgp/web-stream-tools';
-import stub from 'sinon/lib/sinon/stub';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -183,7 +183,7 @@ export default () => describe('Packet', function() {
function cryptStub(webCrypto, method) {
const crypt = webCrypto[method];
- const cryptStub = stub(webCrypto, method);
+ const cryptStub = sinon.stub(webCrypto, method);
let cryptCallsActive = 0;
cryptStub.onCall(0).callsFake(async function() {
cryptCallsActive++;
@@ -265,7 +265,7 @@ export default () => describe('Packet', function() {
const msg2 = new openpgp.PacketList();
- const randomBytesStub = stub(nodeCrypto, 'randomBytes');
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
randomBytesStub.returns(iv);
try {
@@ -534,7 +534,7 @@ export default () => describe('Packet', function() {
const sessionIV = util.hexToUint8Array('bc 66 9e 34 e5 00 dc ae dc 5b 32 aa 2d ab 02 35'.replace(/\s+/g, ''));
const dataIV = util.hexToUint8Array('b7 32 37 9f 73 c4 92 8d e2 5f ac fe 65 17 ec 10'.replace(/\s+/g, ''));
- const randomBytesStub = stub(nodeCrypto, 'randomBytes');
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
randomBytesStub.onCall(0).returns(salt);
randomBytesStub.onCall(1).returns(sessionKey);
randomBytesStub.onCall(2).returns(sessionIV);
@@ -611,7 +611,7 @@ export default () => describe('Packet', function() {
const sessionIV = util.hexToUint8Array('99 e3 26 e5 40 0a 90 93 6c ef b4 e8 eb a0 8c'.replace(/\s+/g, ''));
const dataIV = util.hexToUint8Array('5e d2 bc 1e 47 0a be 8f 1d 64 4c 7a 6c 8a 56'.replace(/\s+/g, ''));
- const randomBytesStub = stub(nodeCrypto, 'randomBytes');
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
randomBytesStub.onCall(0).returns(salt);
randomBytesStub.onCall(1).returns(sessionKey);
randomBytesStub.onCall(2).returns(sessionIV);
diff --git a/test/general/streaming.js b/test/general/streaming.js
index e4dd91b79..e60a9f169 100644
--- a/test/general/streaming.js
+++ b/test/general/streaming.js
@@ -1,7 +1,7 @@
/* eslint-disable max-lines */
/* globals loadStreamsPolyfill */
import * as stream from '@openpgp/web-stream-tools';
-import stub from 'sinon/lib/sinon/stub';
+import sinon from 'sinon';
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
@@ -850,7 +850,7 @@ function tests() {
it("Don't pull entire input stream when we're not pulling decrypted stream (AEAD)", async function() {
let coresStub;
if (detectNode()) {
- coresStub = stub(util.nodeRequire('os'), 'cpus');
+ coresStub = sinon.stub(util.nodeRequire('os'), 'cpus');
coresStub.returns(new Array(2));
// Object.defineProperty(require('os'), 'cpus', { value: () => [,], configurable: true });
} else {
From 7c9549ce883e55f18d235a7637b2e96906c38790 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 20 Jun 2023 13:13:48 +0200
Subject: [PATCH 018/224] Drop `config.minBytesForWebCrypto`
WebCrypto performance is now on-par or better than non-native libs even for small messages
---
openpgp.d.ts | 1 -
src/config/config.js | 6 ------
src/crypto/hash/index.js | 9 ++++-----
3 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index c161efac0..e674c0177 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -335,7 +335,6 @@ interface Config {
s2kType: enums.s2k.iterated | enums.s2k.argon2;
s2kIterationCountByte: number;
s2kArgon2Params: { passes: number, parallelism: number; memoryExponent: number; };
- minBytesForWebCrypto: number;
maxUserIDLength: number;
knownNotations: string[];
useIndutnyElliptic: boolean;
diff --git a/src/config/config.js b/src/config/config.js
index 6f2baadb6..1e6bd3ef9 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -190,12 +190,6 @@ export default {
* @property {Set} constantTimePKCS1DecryptionSupportedSymmetricAlgorithms {@link module:enums.symmetric}
*/
constantTimePKCS1DecryptionSupportedSymmetricAlgorithms: new Set([enums.symmetric.aes128, enums.symmetric.aes192, enums.symmetric.aes256]),
-
- /**
- * @memberof module:config
- * @property {Integer} minBytesForWebCrypto The minimum amount of bytes for which to use native WebCrypto APIs when available
- */
- minBytesForWebCrypto: 1000,
/**
* @memberof module:config
* @property {Boolean} ignoreUnsupportedPackets Ignore unsupported/unrecognizable packets on parsing instead of throwing an error
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index a3dc6972b..50b66ad23 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -14,7 +14,6 @@ import { ripemd160 } from 'hash.js/lib/hash/ripemd';
import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5';
import util from '../../util';
-import defaultConfig from '../../config';
import enums from '../../enums';
const webCrypto = util.getWebCrypto();
@@ -34,11 +33,11 @@ function nodeHash(type) {
}
function hashjsHash(hash, webCryptoHash) {
- return async function(data, config = defaultConfig) {
+ return async function(data) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
- if (!util.isStream(data) && webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
+ if (!util.isStream(data) && webCrypto && webCryptoHash) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
}
const hashInstance = hash();
@@ -49,7 +48,7 @@ function hashjsHash(hash, webCryptoHash) {
}
function nobleHash(hash, webCryptoHash) {
- return async function(data, config = defaultConfig) {
+ return async function(data) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
@@ -58,7 +57,7 @@ function nobleHash(hash, webCryptoHash) {
return stream.transform(data, value => {
hashInstance.update(value);
}, () => hashInstance.digest());
- } else if (webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
+ } else if (webCrypto && webCryptoHash) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
} else {
return hash(data);
From e07a0c432ab2094c43b521e64c2b28055220483c Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 20 Jun 2023 13:44:23 +0200
Subject: [PATCH 019/224] Replace hash.js with noble-hashes
---
package-lock.json | 1 -
package.json | 1 -
src/crypto/hash/index.js | 37 ++++---------------
src/crypto/public_key/elliptic/eddsa.js | 4 +-
.../public_key/elliptic/eddsa_legacy.js | 4 +-
5 files changed, 11 insertions(+), 36 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index b3eb33102..3047d6447 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,7 +38,6 @@
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
"fflate": "^0.7.4",
- "hash.js": "^1.1.3",
"http-server": "^14.1.1",
"karma": "^6.4.0",
"karma-browserstack-launcher": "^1.6.0",
diff --git a/package.json b/package.json
index 5486f1948..afae2dddd 100644
--- a/package.json
+++ b/package.json
@@ -88,7 +88,6 @@
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
"fflate": "^0.7.4",
- "hash.js": "^1.1.3",
"http-server": "^14.1.1",
"karma": "^6.4.0",
"karma-browserstack-launcher": "^1.6.0",
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index 50b66ad23..bdf6d60bf 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -6,11 +6,9 @@
*/
import { sha1 } from '@openpgp/noble-hashes/sha1';
-import { sha256 } from '@openpgp/noble-hashes/sha256';
-import sha224 from 'hash.js/lib/hash/sha/224';
-import sha384 from 'hash.js/lib/hash/sha/384';
-import sha512 from 'hash.js/lib/hash/sha/512';
-import { ripemd160 } from 'hash.js/lib/hash/ripemd';
+import { sha224, sha256 } from '@openpgp/noble-hashes/sha256';
+import { sha384, sha512 } from '@openpgp/noble-hashes/sha512';
+import { ripemd160 } from '@openpgp/noble-hashes/ripemd160';
import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5';
import util from '../../util';
@@ -32,21 +30,6 @@ function nodeHash(type) {
};
}
-function hashjsHash(hash, webCryptoHash) {
- return async function(data) {
- if (stream.isArrayStream(data)) {
- data = await stream.readToEnd(data);
- }
- if (!util.isStream(data) && webCrypto && webCryptoHash) {
- return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
- }
- const hashInstance = hash();
- return stream.transform(data, value => {
- hashInstance.update(value);
- }, () => new Uint8Array(hashInstance.digest()));
- };
-}
-
function nobleHash(hash, webCryptoHash) {
return async function(data) {
if (stream.isArrayStream(data)) {
@@ -68,28 +51,22 @@ function nobleHash(hash, webCryptoHash) {
const hashFunctions = {
md5: nodeHash('md5') || md5,
sha1: nodeHash('sha1') || nobleHash(sha1, 'SHA-1'),
- sha224: nodeHash('sha224') || hashjsHash(sha224),
+ sha224: nodeHash('sha224') || nobleHash(sha224),
sha256: nodeHash('sha256') || nobleHash(sha256, 'SHA-256'),
- sha384: nodeHash('sha384') || hashjsHash(sha384, 'SHA-384'),
- sha512: nodeHash('sha512') || hashjsHash(sha512, 'SHA-512'), // asmcrypto sha512 is huge.
- ripemd: nodeHash('ripemd160') || hashjsHash(ripemd160)
+ sha384: nodeHash('sha384') || nobleHash(sha384, 'SHA-384'),
+ sha512: nodeHash('sha512') || nobleHash(sha512, 'SHA-512'),
+ ripemd: nodeHash('ripemd160') || nobleHash(ripemd160)
};
export default {
/** @see module:md5 */
md5: hashFunctions.md5,
- /** @see asmCrypto */
sha1: hashFunctions.sha1,
- /** @see hash.js */
sha224: hashFunctions.sha224,
- /** @see asmCrypto */
sha256: hashFunctions.sha256,
- /** @see hash.js */
sha384: hashFunctions.sha384,
- /** @see asmCrypto */
sha512: hashFunctions.sha512,
- /** @see hash.js */
ripemd: hashFunctions.ripemd,
/**
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index 413f967f9..002f3f294 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -20,14 +20,14 @@
* @module crypto/public_key/elliptic/eddsa
*/
-import sha512 from 'hash.js/lib/hash/sha/512';
+import { sha512 } from '@openpgp/noble-hashes/sha512';
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
import { getRandomBytes } from '../../random';
-nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest());
+nacl.hash = bytes => sha512(bytes);
/**
* Generate (non-legacy) EdDSA key
diff --git a/src/crypto/public_key/elliptic/eddsa_legacy.js b/src/crypto/public_key/elliptic/eddsa_legacy.js
index 726d7ce01..3de09ba40 100644
--- a/src/crypto/public_key/elliptic/eddsa_legacy.js
+++ b/src/crypto/public_key/elliptic/eddsa_legacy.js
@@ -21,13 +21,13 @@
* @module crypto/public_key/elliptic/eddsa_legacy
*/
-import sha512 from 'hash.js/lib/hash/sha/512';
+import { sha512 } from '@openpgp/noble-hashes/sha512';
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
-nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest());
+nacl.hash = bytes => sha512(bytes);
/**
* Sign a message using the provided legacy EdDSA key
From 6ef4392fb11af9dca75b6dca2a5ee0acda4f8425 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 20 Jun 2023 14:23:08 +0200
Subject: [PATCH 020/224] Lint: update config to support ESM imports
---
.eslintrc.cjs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 93758d151..7d077cba4 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -95,10 +95,14 @@ module.exports = {
// eslint-plugin-import rules:
'import/named': 'error',
- 'import/extensions': 'error',
+ 'import/extensions': 'off', // temporary: we use them in tests (ESM compliant), but not in the lib (to limit diff)
'import/first': 'off',
'import/no-extraneous-dependencies': ['error', { 'devDependencies': true, 'optionalDependencies': false, 'peerDependencies': false }],
'import/no-unassigned-import': 'error',
+ 'import/no-unresolved': ['error', {
+ // esm exports not supported: https://github.com/import-js/eslint-plugin-import/issues/1810
+ ignore: ['openpgp', '@openpgp/noble-hashes', '@openpgp/web-stream-tools', '@openpgp/asmcrypto.js']
+ }],
'import/prefer-default-export': 'off',
// Custom silencers:
From 97b73489d1e0a598262b6885145a5efa2ef47859 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 21 Jun 2023 11:55:44 +0200
Subject: [PATCH 021/224] Replace internal BigInteger code with that from
noble-hashes
The noble-hashes fork uses the same fallback implementation,
except BN.js is always imported (due to lib contraints), so a dynamic import is now superfluous
---
src/biginteger/bn.interface.js | 334 --------------
src/biginteger/index.js | 14 -
src/biginteger/native.interface.js | 453 -------------------
src/crypto/public_key/dsa.js | 50 +-
src/crypto/public_key/elgamal.js | 44 +-
src/crypto/public_key/elliptic/oid_curves.js | 8 +-
src/crypto/public_key/prime.js | 23 +-
src/crypto/public_key/rsa.js | 68 ++-
src/crypto/random.js | 5 +-
src/util.js | 10 -
test/general/biginteger.js | 161 -------
test/general/index.js | 2 -
12 files changed, 88 insertions(+), 1084 deletions(-)
delete mode 100644 src/biginteger/bn.interface.js
delete mode 100644 src/biginteger/index.js
delete mode 100644 src/biginteger/native.interface.js
delete mode 100644 test/general/biginteger.js
diff --git a/src/biginteger/bn.interface.js b/src/biginteger/bn.interface.js
deleted file mode 100644
index b8d5b79e1..000000000
--- a/src/biginteger/bn.interface.js
+++ /dev/null
@@ -1,334 +0,0 @@
-import BN from 'bn.js';
-
-/**
- * @fileoverview
- * BigInteger implementation of basic operations
- * Wrapper of bn.js library (wwww.github.com/indutny/bn.js)
- * @module biginteger/bn
- * @private
- */
-
-/**
- * @private
- */
-export default class BigInteger {
- /**
- * Get a BigInteger (input must be big endian for strings and arrays)
- * @param {Number|String|Uint8Array} n - Value to convert
- * @throws {Error} on undefined input
- */
- constructor(n) {
- if (n === undefined) {
- throw new Error('Invalid BigInteger input');
- }
-
- this.value = new BN(n);
- }
-
- clone() {
- const clone = new BigInteger(null);
- this.value.copy(clone.value);
- return clone;
- }
-
- /**
- * BigInteger increment in place
- */
- iinc() {
- this.value.iadd(new BN(1));
- return this;
- }
-
- /**
- * BigInteger increment
- * @returns {BigInteger} this + 1.
- */
- inc() {
- return this.clone().iinc();
- }
-
- /**
- * BigInteger decrement in place
- */
- idec() {
- this.value.isub(new BN(1));
- return this;
- }
-
- /**
- * BigInteger decrement
- * @returns {BigInteger} this - 1.
- */
- dec() {
- return this.clone().idec();
- }
-
-
- /**
- * BigInteger addition in place
- * @param {BigInteger} x - Value to add
- */
- iadd(x) {
- this.value.iadd(x.value);
- return this;
- }
-
- /**
- * BigInteger addition
- * @param {BigInteger} x - Value to add
- * @returns {BigInteger} this + x.
- */
- add(x) {
- return this.clone().iadd(x);
- }
-
- /**
- * BigInteger subtraction in place
- * @param {BigInteger} x - Value to subtract
- */
- isub(x) {
- this.value.isub(x.value);
- return this;
- }
-
- /**
- * BigInteger subtraction
- * @param {BigInteger} x - Value to subtract
- * @returns {BigInteger} this - x.
- */
- sub(x) {
- return this.clone().isub(x);
- }
-
- /**
- * BigInteger multiplication in place
- * @param {BigInteger} x - Value to multiply
- */
- imul(x) {
- this.value.imul(x.value);
- return this;
- }
-
- /**
- * BigInteger multiplication
- * @param {BigInteger} x - Value to multiply
- * @returns {BigInteger} this * x.
- */
- mul(x) {
- return this.clone().imul(x);
- }
-
- /**
- * Compute value modulo m, in place
- * @param {BigInteger} m - Modulo
- */
- imod(m) {
- this.value = this.value.umod(m.value);
- return this;
- }
-
- /**
- * Compute value modulo m
- * @param {BigInteger} m - Modulo
- * @returns {BigInteger} this mod m.
- */
- mod(m) {
- return this.clone().imod(m);
- }
-
- /**
- * Compute modular exponentiation
- * Much faster than this.exp(e).mod(n)
- * @param {BigInteger} e - Exponent
- * @param {BigInteger} n - Modulo
- * @returns {BigInteger} this ** e mod n.
- */
- modExp(e, n) {
- // We use either Montgomery or normal reduction context
- // Montgomery requires coprime n and R (montogmery multiplier)
- // bn.js picks R as power of 2, so n must be odd
- const nred = n.isEven() ? BN.red(n.value) : BN.mont(n.value);
- const x = this.clone();
- x.value = x.value.toRed(nred).redPow(e.value).fromRed();
- return x;
- }
-
- /**
- * Compute the inverse of this value modulo n
- * Note: this and and n must be relatively prime
- * @param {BigInteger} n - Modulo
- * @returns {BigInteger} x such that this*x = 1 mod n
- * @throws {Error} if the inverse does not exist
- */
- modInv(n) {
- // invm returns a wrong result if the inverse does not exist
- if (!this.gcd(n).isOne()) {
- throw new Error('Inverse does not exist');
- }
- return new BigInteger(this.value.invm(n.value));
- }
-
- /**
- * Compute greatest common divisor between this and n
- * @param {BigInteger} n - Operand
- * @returns {BigInteger} gcd
- */
- gcd(n) {
- return new BigInteger(this.value.gcd(n.value));
- }
-
- /**
- * Shift this to the left by x, in place
- * @param {BigInteger} x - Shift value
- */
- ileftShift(x) {
- this.value.ishln(x.value.toNumber());
- return this;
- }
-
- /**
- * Shift this to the left by x
- * @param {BigInteger} x - Shift value
- * @returns {BigInteger} this << x.
- */
- leftShift(x) {
- return this.clone().ileftShift(x);
- }
-
- /**
- * Shift this to the right by x, in place
- * @param {BigInteger} x - Shift value
- */
- irightShift(x) {
- this.value.ishrn(x.value.toNumber());
- return this;
- }
-
- /**
- * Shift this to the right by x
- * @param {BigInteger} x - Shift value
- * @returns {BigInteger} this >> x.
- */
- rightShift(x) {
- return this.clone().irightShift(x);
- }
-
- /**
- * Whether this value is equal to x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- equal(x) {
- return this.value.eq(x.value);
- }
-
- /**
- * Whether this value is less than x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- lt(x) {
- return this.value.lt(x.value);
- }
-
- /**
- * Whether this value is less than or equal to x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- lte(x) {
- return this.value.lte(x.value);
- }
-
- /**
- * Whether this value is greater than x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- gt(x) {
- return this.value.gt(x.value);
- }
-
- /**
- * Whether this value is greater than or equal to x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- gte(x) {
- return this.value.gte(x.value);
- }
-
- isZero() {
- return this.value.isZero();
- }
-
- isOne() {
- return this.value.eq(new BN(1));
- }
-
- isNegative() {
- return this.value.isNeg();
- }
-
- isEven() {
- return this.value.isEven();
- }
-
- abs() {
- const res = this.clone();
- res.value = res.value.abs();
- return res;
- }
-
- /**
- * Get this value as a string
- * @returns {String} this value.
- */
- toString() {
- return this.value.toString();
- }
-
- /**
- * Get this value as an exact Number (max 53 bits)
- * Fails if this value is too large
- * @returns {Number}
- */
- toNumber() {
- return this.value.toNumber();
- }
-
- /**
- * Get value of i-th bit
- * @param {Number} i - Bit index
- * @returns {Number} Bit value.
- */
- getBit(i) {
- return this.value.testn(i) ? 1 : 0;
- }
-
- /**
- * Compute bit length
- * @returns {Number} Bit length.
- */
- bitLength() {
- return this.value.bitLength();
- }
-
- /**
- * Compute byte length
- * @returns {Number} Byte length.
- */
- byteLength() {
- return this.value.byteLength();
- }
-
- /**
- * Get Uint8Array representation of this number
- * @param {String} endian - Endianess of output array (defaults to 'be')
- * @param {Number} length - Of output array
- * @returns {Uint8Array}
- */
- toUint8Array(endian = 'be', length) {
- return this.value.toArrayLike(Uint8Array, endian, length);
- }
-}
diff --git a/src/biginteger/index.js b/src/biginteger/index.js
deleted file mode 100644
index cf687b446..000000000
--- a/src/biginteger/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import BigInteger from './native.interface';
-
-const detectBigInt = () => typeof BigInt !== 'undefined';
-
-async function getBigInteger() {
- if (detectBigInt()) {
- return BigInteger;
- } else {
- const { default: BigInteger } = await import('./bn.interface');
- return BigInteger;
- }
-}
-
-export { getBigInteger };
diff --git a/src/biginteger/native.interface.js b/src/biginteger/native.interface.js
deleted file mode 100644
index a524006ce..000000000
--- a/src/biginteger/native.interface.js
+++ /dev/null
@@ -1,453 +0,0 @@
-/* eslint-disable new-cap */
-
-/**
- * @fileoverview
- * BigInteger implementation of basic operations
- * that wraps the native BigInt library.
- * Operations are not constant time,
- * but we try and limit timing leakage where we can
- * @module biginteger/native
- * @private
- */
-
-/**
- * @private
- */
-export default class BigInteger {
- /**
- * Get a BigInteger (input must be big endian for strings and arrays)
- * @param {Number|String|Uint8Array} n - Value to convert
- * @throws {Error} on null or undefined input
- */
- constructor(n) {
- if (n === undefined) {
- throw new Error('Invalid BigInteger input');
- }
-
- if (n instanceof Uint8Array) {
- const bytes = n;
- const hex = new Array(bytes.length);
- for (let i = 0; i < bytes.length; i++) {
- const hexByte = bytes[i].toString(16);
- hex[i] = (bytes[i] <= 0xF) ? ('0' + hexByte) : hexByte;
- }
- this.value = BigInt('0x0' + hex.join(''));
- } else {
- this.value = BigInt(n);
- }
- }
-
- clone() {
- return new BigInteger(this.value);
- }
-
- /**
- * BigInteger increment in place
- */
- iinc() {
- this.value++;
- return this;
- }
-
- /**
- * BigInteger increment
- * @returns {BigInteger} this + 1.
- */
- inc() {
- return this.clone().iinc();
- }
-
- /**
- * BigInteger decrement in place
- */
- idec() {
- this.value--;
- return this;
- }
-
- /**
- * BigInteger decrement
- * @returns {BigInteger} this - 1.
- */
- dec() {
- return this.clone().idec();
- }
-
- /**
- * BigInteger addition in place
- * @param {BigInteger} x - Value to add
- */
- iadd(x) {
- this.value += x.value;
- return this;
- }
-
- /**
- * BigInteger addition
- * @param {BigInteger} x - Value to add
- * @returns {BigInteger} this + x.
- */
- add(x) {
- return this.clone().iadd(x);
- }
-
- /**
- * BigInteger subtraction in place
- * @param {BigInteger} x - Value to subtract
- */
- isub(x) {
- this.value -= x.value;
- return this;
- }
-
- /**
- * BigInteger subtraction
- * @param {BigInteger} x - Value to subtract
- * @returns {BigInteger} this - x.
- */
- sub(x) {
- return this.clone().isub(x);
- }
-
- /**
- * BigInteger multiplication in place
- * @param {BigInteger} x - Value to multiply
- */
- imul(x) {
- this.value *= x.value;
- return this;
- }
-
- /**
- * BigInteger multiplication
- * @param {BigInteger} x - Value to multiply
- * @returns {BigInteger} this * x.
- */
- mul(x) {
- return this.clone().imul(x);
- }
-
- /**
- * Compute value modulo m, in place
- * @param {BigInteger} m - Modulo
- */
- imod(m) {
- this.value %= m.value;
- if (this.isNegative()) {
- this.iadd(m);
- }
- return this;
- }
-
- /**
- * Compute value modulo m
- * @param {BigInteger} m - Modulo
- * @returns {BigInteger} this mod m.
- */
- mod(m) {
- return this.clone().imod(m);
- }
-
- /**
- * Compute modular exponentiation using square and multiply
- * @param {BigInteger} e - Exponent
- * @param {BigInteger} n - Modulo
- * @returns {BigInteger} this ** e mod n.
- */
- modExp(e, n) {
- if (n.isZero()) throw Error('Modulo cannot be zero');
- if (n.isOne()) return new BigInteger(0);
- if (e.isNegative()) throw Error('Unsopported negative exponent');
-
- let exp = e.value;
- let x = this.value;
-
- x %= n.value;
- let r = BigInt(1);
- while (exp > BigInt(0)) {
- const lsb = exp & BigInt(1);
- exp >>= BigInt(1); // e / 2
- // Always compute multiplication step, to reduce timing leakage
- const rx = (r * x) % n.value;
- // Update r only if lsb is 1 (odd exponent)
- r = lsb ? rx : r;
- x = (x * x) % n.value; // Square
- }
- return new BigInteger(r);
- }
-
-
- /**
- * Compute the inverse of this value modulo n
- * Note: this and and n must be relatively prime
- * @param {BigInteger} n - Modulo
- * @returns {BigInteger} x such that this*x = 1 mod n
- * @throws {Error} if the inverse does not exist
- */
- modInv(n) {
- const { gcd, x } = this._egcd(n);
- if (!gcd.isOne()) {
- throw new Error('Inverse does not exist');
- }
- return x.add(n).mod(n);
- }
-
- /**
- * Extended Eucleadian algorithm (http://anh.cs.luc.edu/331/notes/xgcd.pdf)
- * Given a = this and b, compute (x, y) such that ax + by = gdc(a, b)
- * @param {BigInteger} b - Second operand
- * @returns {{ gcd, x, y: BigInteger }}
- */
- _egcd(b) {
- let x = BigInt(0);
- let y = BigInt(1);
- let xPrev = BigInt(1);
- let yPrev = BigInt(0);
-
- let a = this.value;
- b = b.value;
-
- while (b !== BigInt(0)) {
- const q = a / b;
- let tmp = x;
- x = xPrev - q * x;
- xPrev = tmp;
-
- tmp = y;
- y = yPrev - q * y;
- yPrev = tmp;
-
- tmp = b;
- b = a % b;
- a = tmp;
- }
-
- return {
- x: new BigInteger(xPrev),
- y: new BigInteger(yPrev),
- gcd: new BigInteger(a)
- };
- }
-
- /**
- * Compute greatest common divisor between this and n
- * @param {BigInteger} b - Operand
- * @returns {BigInteger} gcd
- */
- gcd(b) {
- let a = this.value;
- b = b.value;
- while (b !== BigInt(0)) {
- const tmp = b;
- b = a % b;
- a = tmp;
- }
- return new BigInteger(a);
- }
-
- /**
- * Shift this to the left by x, in place
- * @param {BigInteger} x - Shift value
- */
- ileftShift(x) {
- this.value <<= x.value;
- return this;
- }
-
- /**
- * Shift this to the left by x
- * @param {BigInteger} x - Shift value
- * @returns {BigInteger} this << x.
- */
- leftShift(x) {
- return this.clone().ileftShift(x);
- }
-
- /**
- * Shift this to the right by x, in place
- * @param {BigInteger} x - Shift value
- */
- irightShift(x) {
- this.value >>= x.value;
- return this;
- }
-
- /**
- * Shift this to the right by x
- * @param {BigInteger} x - Shift value
- * @returns {BigInteger} this >> x.
- */
- rightShift(x) {
- return this.clone().irightShift(x);
- }
-
- /**
- * Whether this value is equal to x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- equal(x) {
- return this.value === x.value;
- }
-
- /**
- * Whether this value is less than x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- lt(x) {
- return this.value < x.value;
- }
-
- /**
- * Whether this value is less than or equal to x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- lte(x) {
- return this.value <= x.value;
- }
-
- /**
- * Whether this value is greater than x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- gt(x) {
- return this.value > x.value;
- }
-
- /**
- * Whether this value is greater than or equal to x
- * @param {BigInteger} x
- * @returns {Boolean}
- */
- gte(x) {
- return this.value >= x.value;
- }
-
- isZero() {
- return this.value === BigInt(0);
- }
-
- isOne() {
- return this.value === BigInt(1);
- }
-
- isNegative() {
- return this.value < BigInt(0);
- }
-
- isEven() {
- return !(this.value & BigInt(1));
- }
-
- abs() {
- const res = this.clone();
- if (this.isNegative()) {
- res.value = -res.value;
- }
- return res;
- }
-
- /**
- * Get this value as a string
- * @returns {String} this value.
- */
- toString() {
- return this.value.toString();
- }
-
- /**
- * Get this value as an exact Number (max 53 bits)
- * Fails if this value is too large
- * @returns {Number}
- */
- toNumber() {
- const number = Number(this.value);
- if (number > Number.MAX_SAFE_INTEGER) {
- // We throw and error to conform with the bn.js implementation
- throw new Error('Number can only safely store up to 53 bits');
- }
- return number;
- }
-
- /**
- * Get value of i-th bit
- * @param {Number} i - Bit index
- * @returns {Number} Bit value.
- */
- getBit(i) {
- const bit = (this.value >> BigInt(i)) & BigInt(1);
- return (bit === BigInt(0)) ? 0 : 1;
- }
-
- /**
- * Compute bit length
- * @returns {Number} Bit length.
- */
- bitLength() {
- const zero = new BigInteger(0);
- const one = new BigInteger(1);
- const negOne = new BigInteger(-1);
-
- // -1n >> -1n is -1n
- // 1n >> 1n is 0n
- const target = this.isNegative() ? negOne : zero;
- let bitlen = 1;
- const tmp = this.clone();
- while (!tmp.irightShift(one).equal(target)) {
- bitlen++;
- }
- return bitlen;
- }
-
- /**
- * Compute byte length
- * @returns {Number} Byte length.
- */
- byteLength() {
- const zero = new BigInteger(0);
- const negOne = new BigInteger(-1);
-
- const target = this.isNegative() ? negOne : zero;
- const eight = new BigInteger(8);
- let len = 1;
- const tmp = this.clone();
- while (!tmp.irightShift(eight).equal(target)) {
- len++;
- }
- return len;
- }
-
- /**
- * Get Uint8Array representation of this number
- * @param {String} endian - Endianess of output array (defaults to 'be')
- * @param {Number} length - Of output array
- * @returns {Uint8Array}
- */
- toUint8Array(endian = 'be', length) {
- // we get and parse the hex string (https://coolaj86.com/articles/convert-js-bigints-to-typedarrays/)
- // this is faster than shift+mod iterations
- let hex = this.value.toString(16);
- if (hex.length % 2 === 1) {
- hex = '0' + hex;
- }
-
- const rawLength = hex.length / 2;
- const bytes = new Uint8Array(length || rawLength);
- // parse hex
- const offset = length ? (length - rawLength) : 0;
- let i = 0;
- while (i < rawLength) {
- bytes[i + offset] = parseInt(hex.slice(2 * i, 2 * i + 2), 16);
- i++;
- }
-
- if (endian !== 'be') {
- bytes.reverse();
- }
-
- return bytes;
- }
-}
diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js
index 286adb649..b48a4d972 100644
--- a/src/crypto/public_key/dsa.js
+++ b/src/crypto/public_key/dsa.js
@@ -19,6 +19,7 @@
* @fileoverview A Digital signature algorithm implementation
* @module crypto/public_key/dsa
*/
+import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
import util from '../../util';
import { isProbablePrime } from './prime';
@@ -41,12 +42,11 @@ import { isProbablePrime } from './prime';
* @async
*/
export async function sign(hashAlgo, hashed, g, p, q, x) {
- const BigInteger = await util.getBigInteger();
- const one = new BigInteger(1);
- p = new BigInteger(p);
- q = new BigInteger(q);
- g = new BigInteger(g);
- x = new BigInteger(x);
+ const one = BigInteger.new(1);
+ p = BigInteger.new(p);
+ q = BigInteger.new(q);
+ g = BigInteger.new(g);
+ x = BigInteger.new(x);
let k;
let r;
@@ -59,7 +59,7 @@ export async function sign(hashAlgo, hashed, g, p, q, x) {
// of leftmost bits equal to the number of bits of q. This (possibly
// truncated) hash function result is treated as a number and used
// directly in the DSA signature algorithm.
- const h = new BigInteger(hashed.subarray(0, q.byteLength())).mod(q);
+ const h = BigInteger.new(hashed.subarray(0, q.byteLength())).mod(q);
// FIPS-186-4, section 4.6:
// The values of r and s shall be checked to determine if r = 0 or s = 0.
// If either r = 0 or s = 0, a new value of k shall be generated, and the
@@ -100,22 +100,21 @@ export async function sign(hashAlgo, hashed, g, p, q, x) {
* @async
*/
export async function verify(hashAlgo, r, s, hashed, g, p, q, y) {
- const BigInteger = await util.getBigInteger();
- const zero = new BigInteger(0);
- r = new BigInteger(r);
- s = new BigInteger(s);
+ const zero = BigInteger.new(0);
+ r = BigInteger.new(r);
+ s = BigInteger.new(s);
- p = new BigInteger(p);
- q = new BigInteger(q);
- g = new BigInteger(g);
- y = new BigInteger(y);
+ p = BigInteger.new(p);
+ q = BigInteger.new(q);
+ g = BigInteger.new(g);
+ y = BigInteger.new(y);
if (r.lte(zero) || r.gte(q) ||
s.lte(zero) || s.gte(q)) {
util.printDebug('invalid DSA Signature');
return false;
}
- const h = new BigInteger(hashed.subarray(0, q.byteLength())).imod(q);
+ const h = BigInteger.new(hashed.subarray(0, q.byteLength())).imod(q);
const w = s.modInv(q); // s**-1 mod q
if (w.isZero()) {
util.printDebug('invalid DSA Signature');
@@ -143,12 +142,11 @@ export async function verify(hashAlgo, r, s, hashed, g, p, q, y) {
* @async
*/
export async function validateParams(p, q, g, y, x) {
- const BigInteger = await util.getBigInteger();
- p = new BigInteger(p);
- q = new BigInteger(q);
- g = new BigInteger(g);
- y = new BigInteger(y);
- const one = new BigInteger(1);
+ p = BigInteger.new(p);
+ q = BigInteger.new(q);
+ g = BigInteger.new(g);
+ y = BigInteger.new(y);
+ const one = BigInteger.new(1);
// Check that 1 < g < p
if (g.lte(one) || g.gte(p)) {
return false;
@@ -172,8 +170,8 @@ export async function validateParams(p, q, g, y, x) {
/**
* Check q is large and probably prime (we mainly want to avoid small factors)
*/
- const qSize = new BigInteger(q.bitLength());
- const n150 = new BigInteger(150);
+ const qSize = BigInteger.new(q.bitLength());
+ const n150 = BigInteger.new(150);
if (qSize.lt(n150) || !(await isProbablePrime(q, null, 32))) {
return false;
}
@@ -184,8 +182,8 @@ export async function validateParams(p, q, g, y, x) {
*
* Blinded exponentiation computes g**{rq + x} to compare to y
*/
- x = new BigInteger(x);
- const two = new BigInteger(2);
+ x = BigInteger.new(x);
+ const two = BigInteger.new(2);
const r = await getRandomBigInteger(two.leftShift(qSize.dec()), two.leftShift(qSize)); // draw r of same size as q
const rqx = q.mul(r).add(x);
if (!y.equal(g.modExp(rqx, p))) {
diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js
index 2f69e6f0b..e9d668657 100644
--- a/src/crypto/public_key/elgamal.js
+++ b/src/crypto/public_key/elgamal.js
@@ -19,8 +19,7 @@
* @fileoverview ElGamal implementation
* @module crypto/public_key/elgamal
*/
-
-import util from '../../util';
+import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
import { emeEncode, emeDecode } from '../pkcs1';
@@ -35,17 +34,16 @@ import { emeEncode, emeDecode } from '../pkcs1';
* @async
*/
export async function encrypt(data, p, g, y) {
- const BigInteger = await util.getBigInteger();
- p = new BigInteger(p);
- g = new BigInteger(g);
- y = new BigInteger(y);
+ p = BigInteger.new(p);
+ g = BigInteger.new(g);
+ y = BigInteger.new(y);
const padded = emeEncode(data, p.byteLength());
- const m = new BigInteger(padded);
+ const m = BigInteger.new(padded);
// OpenPGP uses a "special" version of ElGamal where g is generator of the full group Z/pZ*
// hence g has order p-1, and to avoid that k = 0 mod p-1, we need to pick k in [1, p-2]
- const k = await getRandomBigInteger(new BigInteger(1), p.dec());
+ const k = await getRandomBigInteger(BigInteger.new(1), p.dec());
return {
c1: g.modExp(k, p).toUint8Array(),
c2: y.modExp(k, p).imul(m).imod(p).toUint8Array()
@@ -65,11 +63,10 @@ export async function encrypt(data, p, g, y) {
* @async
*/
export async function decrypt(c1, c2, p, x, randomPayload) {
- const BigInteger = await util.getBigInteger();
- c1 = new BigInteger(c1);
- c2 = new BigInteger(c2);
- p = new BigInteger(p);
- x = new BigInteger(x);
+ c1 = BigInteger.new(c1);
+ c2 = BigInteger.new(c2);
+ p = BigInteger.new(p);
+ x = BigInteger.new(x);
const padded = c1.modExp(x, p).modInv(p).imul(c2).imod(p);
return emeDecode(padded.toUint8Array('be', p.byteLength()), randomPayload);
@@ -85,20 +82,19 @@ export async function decrypt(c1, c2, p, x, randomPayload) {
* @async
*/
export async function validateParams(p, g, y, x) {
- const BigInteger = await util.getBigInteger();
- p = new BigInteger(p);
- g = new BigInteger(g);
- y = new BigInteger(y);
+ p = BigInteger.new(p);
+ g = BigInteger.new(g);
+ y = BigInteger.new(y);
- const one = new BigInteger(1);
+ const one = BigInteger.new(1);
// Check that 1 < g < p
if (g.lte(one) || g.gte(p)) {
return false;
}
// Expect p-1 to be large
- const pSize = new BigInteger(p.bitLength());
- const n1023 = new BigInteger(1023);
+ const pSize = BigInteger.new(p.bitLength());
+ const n1023 = BigInteger.new(1023);
if (pSize.lt(n1023)) {
return false;
}
@@ -118,8 +114,8 @@ export async function validateParams(p, g, y, x) {
* We just check g**i != 1 for all i up to a threshold
*/
let res = g;
- const i = new BigInteger(1);
- const threshold = new BigInteger(2).leftShift(new BigInteger(17)); // we want order > threshold
+ const i = BigInteger.new(1);
+ const threshold = BigInteger.new(2).leftShift(BigInteger.new(17)); // we want order > threshold
while (i.lt(threshold)) {
res = res.mul(g).imod(p);
if (res.isOne()) {
@@ -134,8 +130,8 @@ export async function validateParams(p, g, y, x) {
*
* Blinded exponentiation computes g**{r(p-1) + x} to compare to y
*/
- x = new BigInteger(x);
- const two = new BigInteger(2);
+ x = BigInteger.new(x);
+ const two = BigInteger.new(2);
const r = await getRandomBigInteger(two.leftShift(pSize.dec()), two.leftShift(pSize)); // draw r of same size as p-1
const rqx = p.dec().imul(r).iadd(x);
if (!y.equal(g.modExp(rqx, p))) {
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index dab26436a..129ab22c7 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -19,7 +19,7 @@
* @fileoverview Wrapper of an instance of an Elliptic Curve
* @module crypto/public_key/elliptic/curve
*/
-
+import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
import { getRandomBytes } from '../../random';
import enums from '../../../enums';
@@ -205,12 +205,10 @@ class CurveWithOID {
}
async function generate(curve) {
- const BigInteger = await util.getBigInteger();
-
curve = new CurveWithOID(curve);
const keyPair = await curve.genKeyPair();
- const Q = new BigInteger(keyPair.publicKey).toUint8Array();
- const secret = new BigInteger(keyPair.privateKey).toUint8Array('be', curve.payloadSize);
+ const Q = BigInteger.new(keyPair.publicKey).toUint8Array();
+ const secret = BigInteger.new(keyPair.privateKey).toUint8Array('be', curve.payloadSize);
return {
oid: curve.oid,
Q,
diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js
index a7b7cba0e..8e0bd13d1 100644
--- a/src/crypto/public_key/prime.js
+++ b/src/crypto/public_key/prime.js
@@ -19,8 +19,7 @@
* @fileoverview Algorithms for probabilistic random prime generation
* @module crypto/public_key/prime
*/
-
-import util from '../../util';
+import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
/**
@@ -32,10 +31,9 @@ import { getRandomBigInteger } from '../random';
* @async
*/
export async function randomProbablePrime(bits, e, k) {
- const BigInteger = await util.getBigInteger();
- const one = new BigInteger(1);
- const min = one.leftShift(new BigInteger(bits - 1));
- const thirty = new BigInteger(30);
+ const one = BigInteger.new(1);
+ const min = one.leftShift(BigInteger.new(bits - 1));
+ const thirty = BigInteger.new(30);
/*
* We can avoid any multiples of 3 and 5 by looking at n mod 30
* n mod 30 = 0 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
@@ -48,7 +46,7 @@ export async function randomProbablePrime(bits, e, k) {
let i = n.mod(thirty).toNumber();
do {
- n.iadd(new BigInteger(adds[i]));
+ n.iadd(BigInteger.new(adds[i]));
i = (i + adds[i]) % adds.length;
// If reached the maximum, go back to the minimum.
if (n.bitLength() > bits) {
@@ -93,15 +91,13 @@ export async function isProbablePrime(n, e, k) {
* @returns {boolean}
*/
export async function fermat(n, b) {
- const BigInteger = await util.getBigInteger();
- b = b || new BigInteger(2);
+ b = b || BigInteger.new(2);
return b.modExp(n.dec(), n).isOne();
}
export async function divisionTest(n) {
- const BigInteger = await util.getBigInteger();
return smallPrimes.every(m => {
- return n.mod(new BigInteger(m)) !== 0;
+ return n.mod(BigInteger.new(m)) !== 0;
});
}
@@ -228,7 +224,6 @@ const smallPrimes = [
* @async
*/
export async function millerRabin(n, k, rand) {
- const BigInteger = await util.getBigInteger();
const len = n.bitLength();
if (!k) {
@@ -240,10 +235,10 @@ export async function millerRabin(n, k, rand) {
// Find d and s, (n - 1) = (2 ^ s) * d;
let s = 0;
while (!n1.getBit(s)) { s++; }
- const d = n.rightShift(new BigInteger(s));
+ const d = n.rightShift(BigInteger.new(s));
for (; k > 0; k--) {
- const a = rand ? rand() : await getRandomBigInteger(new BigInteger(2), n1);
+ const a = rand ? rand() : await getRandomBigInteger(BigInteger.new(2), n1);
let x = a.modExp(d, n);
if (x.isOne() || x.equal(n1)) {
diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js
index 0a17ff061..180a33263 100644
--- a/src/crypto/public_key/rsa.js
+++ b/src/crypto/public_key/rsa.js
@@ -19,7 +19,7 @@
* @fileoverview RSA implementation
* @module crypto/public_key/rsa
*/
-
+import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { randomProbablePrime } from './prime';
import { getRandomBigInteger } from '../random';
import util from '../../util';
@@ -159,9 +159,7 @@ export async function decrypt(data, n, e, d, p, q, u, randomPayload) {
* @async
*/
export async function generate(bits, e) {
- const BigInteger = await util.getBigInteger();
-
- e = new BigInteger(e);
+ e = BigInteger.new(e);
// Native RSA keygen using Web Crypto
if (util.getWebCrypto()) {
@@ -264,25 +262,24 @@ export async function generate(bits, e) {
* @async
*/
export async function validateParams(n, e, d, p, q, u) {
- const BigInteger = await util.getBigInteger();
- n = new BigInteger(n);
- p = new BigInteger(p);
- q = new BigInteger(q);
+ n = BigInteger.new(n);
+ p = BigInteger.new(p);
+ q = BigInteger.new(q);
// expect pq = n
if (!p.mul(q).equal(n)) {
return false;
}
- const two = new BigInteger(2);
+ const two = BigInteger.new(2);
// expect p*u = 1 mod q
- u = new BigInteger(u);
+ u = BigInteger.new(u);
if (!p.mul(u).mod(q).isOne()) {
return false;
}
- e = new BigInteger(e);
- d = new BigInteger(d);
+ e = BigInteger.new(e);
+ d = BigInteger.new(d);
/**
* In RSA pkcs#1 the exponents (d, e) are inverses modulo lcm(p-1, q-1)
* We check that [de = 1 mod (p-1)] and [de = 1 mod (q-1)]
@@ -290,7 +287,7 @@ export async function validateParams(n, e, d, p, q, u) {
*
* We blind the multiplication with r, and check that rde = r mod lcm(p-1, q-1)
*/
- const nSizeOver3 = new BigInteger(Math.floor(n.bitLength() / 3));
+ const nSizeOver3 = BigInteger.new(Math.floor(n.bitLength() / 3));
const r = await getRandomBigInteger(two, two.leftShift(nSizeOver3)); // r in [ 2, 2^{|n|/3} ) < p and q
const rde = r.mul(d).mul(e);
@@ -303,10 +300,9 @@ export async function validateParams(n, e, d, p, q, u) {
}
async function bnSign(hashAlgo, n, d, hashed) {
- const BigInteger = await util.getBigInteger();
- n = new BigInteger(n);
- const m = new BigInteger(await emsaEncode(hashAlgo, hashed, n.byteLength()));
- d = new BigInteger(d);
+ n = BigInteger.new(n);
+ const m = BigInteger.new(await emsaEncode(hashAlgo, hashed, n.byteLength()));
+ d = BigInteger.new(d);
if (m.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
}
@@ -364,10 +360,9 @@ async function nodeSign(hashAlgo, data, n, e, d, p, q, u) {
}
async function bnVerify(hashAlgo, s, n, e, hashed) {
- const BigInteger = await util.getBigInteger();
- n = new BigInteger(n);
- s = new BigInteger(s);
- e = new BigInteger(e);
+ n = BigInteger.new(n);
+ s = BigInteger.new(s);
+ e = BigInteger.new(e);
if (s.gte(n)) {
throw new Error('Signature size cannot exceed modulus size');
}
@@ -432,10 +427,9 @@ async function nodeEncrypt(data, n, e) {
}
async function bnEncrypt(data, n, e) {
- const BigInteger = await util.getBigInteger();
- n = new BigInteger(n);
- data = new BigInteger(emeEncode(data, n.byteLength()));
- e = new BigInteger(e);
+ n = BigInteger.new(n);
+ data = BigInteger.new(emeEncode(data, n.byteLength()));
+ e = BigInteger.new(e);
if (data.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
}
@@ -484,21 +478,20 @@ async function nodeDecrypt(data, n, e, d, p, q, u, randomPayload) {
}
async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
- const BigInteger = await util.getBigInteger();
- data = new BigInteger(data);
- n = new BigInteger(n);
- e = new BigInteger(e);
- d = new BigInteger(d);
- p = new BigInteger(p);
- q = new BigInteger(q);
- u = new BigInteger(u);
+ data = BigInteger.new(data);
+ n = BigInteger.new(n);
+ e = BigInteger.new(e);
+ d = BigInteger.new(d);
+ p = BigInteger.new(p);
+ q = BigInteger.new(q);
+ u = BigInteger.new(u);
if (data.gte(n)) {
throw new Error('Data too large.');
}
const dq = d.mod(q.dec()); // d mod (q-1)
const dp = d.mod(p.dec()); // d mod (p-1)
- const unblinder = (await getRandomBigInteger(new BigInteger(2), n)).mod(n);
+ const unblinder = (await getRandomBigInteger(BigInteger.new(2), n)).mod(n);
const blinder = unblinder.modInv(n).modExp(e, n);
data = data.mul(blinder).mod(n);
@@ -526,10 +519,9 @@ async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
* @param {Uint8Array} u
*/
async function privateToJWK(n, e, d, p, q, u) {
- const BigInteger = await util.getBigInteger();
- const pNum = new BigInteger(p);
- const qNum = new BigInteger(q);
- const dNum = new BigInteger(d);
+ const pNum = BigInteger.new(p);
+ const qNum = BigInteger.new(q);
+ const dNum = BigInteger.new(d);
let dq = dNum.mod(qNum.dec()); // d mod (q-1)
let dp = dNum.mod(pNum.dec()); // d mod (p-1)
diff --git a/src/crypto/random.js b/src/crypto/random.js
index ffef7d653..8c7ad4183 100644
--- a/src/crypto/random.js
+++ b/src/crypto/random.js
@@ -21,6 +21,7 @@
* @fileoverview Provides tools for retrieving secure randomness from browsers or Node.js
* @module crypto/random
*/
+import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import util from '../util';
const nodeCrypto = util.getNodeCrypto();
@@ -51,8 +52,6 @@ export function getRandomBytes(length) {
* @async
*/
export async function getRandomBigInteger(min, max) {
- const BigInteger = await util.getBigInteger();
-
if (max.lt(min)) {
throw new Error('Illegal parameter value: max <= min');
}
@@ -63,6 +62,6 @@ export async function getRandomBigInteger(min, max) {
// Using a while loop is necessary to avoid bias introduced by the mod operation.
// However, we request 64 extra random bits so that the bias is negligible.
// Section B.1.1 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
- const r = new BigInteger(await getRandomBytes(bytes + 8));
+ const r = BigInteger.new(await getRandomBytes(bytes + 8));
return r.mod(modulus).add(min);
}
diff --git a/src/util.js b/src/util.js
index 47a02f956..25ba5cd0d 100644
--- a/src/util.js
+++ b/src/util.js
@@ -24,7 +24,6 @@
import * as stream from '@openpgp/web-stream-tools';
import { createRequire } from 'module'; // Must be stripped in browser built
-import { getBigInteger } from './biginteger';
import enums from './enums';
const debugMode = (() => {
@@ -384,15 +383,6 @@ const util = {
return typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.subtle;
},
- /**
- * Get BigInteger class
- * It wraps the native BigInt type if it's available
- * Otherwise it relies on bn.js
- * @returns {BigInteger}
- * @async
- */
- getBigInteger,
-
/**
* Get native Node.js crypto api.
* @returns {Object} The crypto module or 'undefined'.
diff --git a/test/general/biginteger.js b/test/general/biginteger.js
deleted file mode 100644
index 90fd0d38a..000000000
--- a/test/general/biginteger.js
+++ /dev/null
@@ -1,161 +0,0 @@
-import { use as chaiUse, expect } from 'chai';
-import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
-chaiUse(chaiAsPromised);
-
-import BN from 'bn.js';
-import * as random from '../../src/crypto/random.js';
-import util from '../../src/util.js';
-
-let BigInteger;
-
-async function getRandomBN(min, max) {
- if (max.cmp(min) <= 0) {
- throw new Error('Illegal parameter value: max <= min');
- }
-
- const modulus = max.sub(min);
- const bytes = modulus.byteLength();
- const r = new BN(random.getRandomBytes(bytes + 8));
- return r.mod(modulus).add(min);
-}
-
-export default () => describe('BigInteger interface', function() {
- before(async () => {
- BigInteger = await util.getBigInteger();
- });
-
- it('constructor throws on undefined input', function() {
- expect(() => new BigInteger()).to.throw('Invalid BigInteger input');
- });
-
-
- it('constructor supports strings', function() {
- const input = '417653931840771530406225971293556769925351769207235721650257629558293828796031115397206059067934284452829611906818956352854418342467914729341523414945427019410284762464062112274326172407819051167058569790660930309496043254270888417520676082271432948852231332576271876251597199882908964994070268531832274431027';
- const got = new BigInteger(input);
- const expected = new BN(input);
- expect(got.toString()).to.equal(expected.toString());
- });
-
- it('constructor supports Uint8Arrays', function() {
- const expected = new BN('417653931840771530406225971293556769925351769207235721650257629558293828796031115397206059067934284452829611906818956352854418342467914729341523414945427019410284762464062112274326172407819051167058569790660930309496043254270888417520676082271432948852231332576271876251597199882908964994070268531832274431027');
- const input = expected.toArrayLike(Uint8Array);
- const got = new BigInteger(input);
- expect(got.toString()).to.equal(expected.toString());
- });
-
- it('conditional operators are correct', function() {
- const a = new BigInteger(12);
- const b = new BigInteger(34);
-
- expect(a.equal(a)).to.be.true;
- expect(a.equal(b)).to.be.false;
- expect(a.gt(a) === a.lt(a)).to.be.true;
- expect(a.gt(b) === a.lt(b)).to.be.false;
- expect(a.gte(a) === a.lte(a)).to.be.true;
-
- const zero = new BigInteger(0);
- const one = new BigInteger(1);
- expect(zero.isZero()).to.be.true;
- expect(one.isZero()).to.be.false;
-
- expect(one.isOne()).to.be.true;
- expect(zero.isOne()).to.be.false;
-
- expect(zero.isEven()).to.be.true;
- expect(one.isEven()).to.be.false;
-
- expect(zero.isNegative()).to.be.false;
- expect(zero.dec().isNegative()).to.be.true;
- });
-
- it('bitLength is correct', function() {
- const n = new BigInteger(127);
- let expected = 7;
- expect(n.bitLength() === expected).to.be.true;
- expect(n.inc().bitLength() === (++expected)).to.be.true;
- });
-
- it('byteLength is correct', function() {
- const n = new BigInteger(65535);
- let expected = 2;
- expect(n.byteLength() === expected).to.be.true;
- expect(n.inc().byteLength() === (++expected)).to.be.true;
- });
-
- it('toUint8Array is correct', function() {
- const nString = '417653931840771530406225971293556769925351769207235721650257629558293828796031115397206059067934284452829611906818956352854418342467914729341523414945427019410284762464062112274326172407819051167058569790660930309496043254270888417520676082271432948852231332576271876251597199882908964994070268531832274431027';
- const n = new BigInteger(nString);
- const paddedSize = Number(n.byteLength()) + 1;
- // big endian, unpadded
- let expected = new BN(nString).toArrayLike(Uint8Array);
- expect(n.toUint8Array()).to.deep.equal(expected);
- // big endian, padded
- expected = new BN(nString).toArrayLike(Uint8Array, 'be', paddedSize);
- expect(n.toUint8Array('be', paddedSize)).to.deep.equal(expected);
- // little endian, unpadded
- expected = new BN(nString).toArrayLike(Uint8Array, 'le');
- expect(n.toUint8Array('le')).to.deep.equal(expected);
- //little endian, padded
- expected = new BN(nString).toArrayLike(Uint8Array, 'le', paddedSize);
- expect(n.toUint8Array('le', paddedSize)).to.deep.equal(expected);
- });
-
- it('binary operators are consistent', function() {
- const a = new BigInteger(12);
- const b = new BigInteger(34);
- const ops = ['add', 'sub', 'mul', 'mod', 'leftShift', 'rightShift'];
- ops.forEach(op => {
- const iop = `i${op}`;
- expect(a[op](b).equal(a[iop](b))).to.be.true;
- });
- });
-
- it('unary operators are consistent', function() {
- const a = new BigInteger(12);
- const one = new BigInteger(1);
- expect(a.sub(one).equal(a.dec())).to.be.true;
- expect(a.add(one).equal(a.inc())).to.be.true;
- });
-
- it('modExp is correct (large values)', function() {
- const stringX = '417653931840771530406225971293556769925351769207235721650257629558293828796031115397206059067934284452829611906818956352854418342467914729341523414945427019410284762464062112274326172407819051167058569790660930309496043254270888417520676082271432948852231332576271876251597199882908964994070268531832274431027';
- const stringE = '21139356010872569239159922781526379521587348169074209285187910481667533072168468011617194695181255483288792585413365359733692097084373249198758148704369207793873998901870577262254971784191473102265830193058813215898765238784670469696574407580179153118937858890572095234316482449291777882525949871374961971753';
- const stringN = '129189808515414783602892982235788912674846062846614219472827821758734760420002631653235573915244294540972376140705505703576175711417114803419704967903726436285518767606681184247119430411311152556442947708732584954518890222684529678365388350886907287414896703685680210648760841628375425909680236584021041565183';
- const x = new BigInteger(stringX);
- const e = new BigInteger(stringE);
- const n = new BigInteger(stringN);
-
- const got = x.modExp(e, n);
- const expected = new BN(stringX).toRed(BN.red(new BN(stringN))).redPow(new BN(stringE));
- // different formats, it's easier to compare strings
- expect(got.toString() === expected.toString()).to.be.true;
- });
-
- it('gcd is correct', async function() {
- const aBN = await getRandomBN(new BN(2), new BN(200));
- const bBN = await getRandomBN(new BN(2), new BN(200));
- if (aBN.isEven()) aBN.iaddn(1);
- const a = new BigInteger(aBN.toString());
- const b = new BigInteger(bBN.toString());
- const expected = aBN.gcd(bBN);
- expect(a.gcd(b).toString()).to.equal(expected.toString());
- });
-
- it('modular inversion is correct', async function() {
- const moduloBN = new BN(229); // this is a prime
- const baseBN = await getRandomBN(new BN(2), moduloBN);
- const a = new BigInteger(baseBN.toString());
- const n = new BigInteger(moduloBN.toString());
- const expected = baseBN.invm(moduloBN);
- expect(a.modInv(n).toString()).to.equal(expected.toString());
- expect(() => a.mul(n).modInv(n)).to.throw('Inverse does not exist');
- });
-
- it('getBit is correct', async function() {
- const i = 5;
- const nBN = await getRandomBN(new BN(2), new BN(200));
- const n = new BigInteger(nBN.toString());
- const expected = nBN.testn(5) ? 1 : 0;
- expect(n.getBit(i) === expected).to.be.true;
- });
-});
diff --git a/test/general/index.js b/test/general/index.js
index 2ddf0794d..478a0c5a5 100644
--- a/test/general/index.js
+++ b/test/general/index.js
@@ -1,6 +1,5 @@
import testX25519 from './x25519.js';
import testUtil from './util.js';
-import testBigInteger from './biginteger.js';
import testArmor from './armor.js';
import testPacket from './packet.js';
import testSignature from './signature.js';
@@ -17,7 +16,6 @@ import testStreaming from './streaming.js';
export default () => describe('General', function () {
testX25519();
testUtil();
- testBigInteger();
testArmor();
testPacket();
testSignature();
From 538b5b63043f20408aacb2c668bb1fe695ccf740 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 27 Jul 2023 12:31:02 +0200
Subject: [PATCH 022/224] Set Node 16 as minimum supported version in
package.json
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 3047d6447..f1439c747 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -56,7 +56,7 @@
"web-streams-polyfill": "^3.2.0"
},
"engines": {
- "node": ">= 8.0.0"
+ "node": ">= 16.0.0"
}
},
"node_modules/@babel/code-frame": {
diff --git a/package.json b/package.json
index afae2dddd..d73390ece 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"license": "LGPL-3.0+",
"homepage": "https://openpgpjs.org/",
"engines": {
- "node": ">= 8.0.0"
+ "node": ">= 16.0.0"
},
"keywords": [
"crypto",
From 4521de2beac27af94ac5e9c45b5c971dea712c40 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 27 Jul 2023 12:28:27 +0200
Subject: [PATCH 023/224] HKDF: remove fallback for Node 14
v6 drops support for Node 14, which does not include SubtleCrypto
---
src/crypto/hkdf.js | 48 ++++------------------------------------------
1 file changed, 4 insertions(+), 44 deletions(-)
diff --git a/src/crypto/hkdf.js b/src/crypto/hkdf.js
index cf531aed2..c08720b11 100644
--- a/src/crypto/hkdf.js
+++ b/src/crypto/hkdf.js
@@ -8,53 +8,13 @@ import util from '../util';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
-const nodeSubtleCrypto = nodeCrypto && nodeCrypto.webcrypto && nodeCrypto.webcrypto.subtle;
export default async function HKDF(hashAlgo, inputKey, salt, info, outLen) {
const hash = enums.read(enums.webHash, hashAlgo);
if (!hash) throw new Error('Hash algo not supported with HKDF');
- if (webCrypto || nodeSubtleCrypto) {
- const crypto = webCrypto || nodeSubtleCrypto;
- const importedKey = await crypto.importKey('raw', inputKey, 'HKDF', false, ['deriveBits']);
- const bits = await crypto.deriveBits({ name: 'HKDF', hash, salt, info }, importedKey, outLen * 8);
- return new Uint8Array(bits);
- }
-
- if (nodeCrypto) {
- const hashAlgoName = enums.read(enums.hash, hashAlgo);
- // Node-only HKDF implementation based on https://www.rfc-editor.org/rfc/rfc5869
-
- const computeHMAC = (hmacKey, hmacMessage) => nodeCrypto.createHmac(hashAlgoName, hmacKey).update(hmacMessage).digest();
- // Step 1: Extract
- // PRK = HMAC-Hash(salt, IKM)
- const pseudoRandomKey = computeHMAC(salt, inputKey);
-
- const hashLen = pseudoRandomKey.length;
-
- // Step 2: Expand
- // HKDF-Expand(PRK, info, L) -> OKM
- const n = Math.ceil(outLen / hashLen);
- const outputKeyingMaterial = new Uint8Array(n * hashLen);
-
- // HMAC input buffer updated at each iteration
- const roundInput = new Uint8Array(hashLen + info.length + 1);
- // T_i and last byte are updated at each iteration, but `info` remains constant
- roundInput.set(info, hashLen);
-
- for (let i = 0; i < n; i++) {
- // T(0) = empty string (zero length)
- // T(i) = HMAC-Hash(PRK, T(i-1) | info | i)
- roundInput[roundInput.length - 1] = i + 1;
- // t = T(i+1)
- const t = computeHMAC(pseudoRandomKey, i > 0 ? roundInput : roundInput.subarray(hashLen));
- roundInput.set(t, 0);
-
- outputKeyingMaterial.set(t, i * hashLen);
- }
-
- return outputKeyingMaterial.subarray(0, outLen);
- }
-
- throw new Error('No HKDF implementation available');
+ const crypto = webCrypto || nodeCrypto.webcrypto.subtle;
+ const importedKey = await crypto.importKey('raw', inputKey, 'HKDF', false, ['deriveBits']);
+ const bits = await crypto.deriveBits({ name: 'HKDF', hash, salt, info }, importedKey, outLen * 8);
+ return new Uint8Array(bits);
}
From 31c2a2575d05eb65dc3f4eb0bcd0bf14f1eaae08 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 15 Mar 2023 18:39:19 +0100
Subject: [PATCH 024/224] Add support for v6 key packets
Compared to v5 keys, v6 keys contain additional length fields to aid in
parsing the key, but omit the secret key material length field.
Additionally, unencrypted v6 secret key packets don't include the count
of the optional fields, as per the updated crypto refresh. Since they
are always absent, the count is not needed.
Finally, unencrypted v6 secret keys do not include the two-byte checksum.
---
src/packet/public_key.js | 19 +++++++++----------
src/packet/secret_key.js | 39 +++++++++++++++++++++++++++++++++------
2 files changed, 42 insertions(+), 16 deletions(-)
diff --git a/src/packet/public_key.js b/src/packet/public_key.js
index 15e90857c..d9d038f2d 100644
--- a/src/packet/public_key.js
+++ b/src/packet/public_key.js
@@ -106,10 +106,10 @@ class PublicKeyPacket {
*/
async read(bytes) {
let pos = 0;
- // A one-octet version number (3, 4 or 5).
+ // A one-octet version number (4, 5 or 6).
this.version = bytes[pos++];
- if (this.version === 4 || this.version === 5) {
+ if (this.version === 4 || this.version === 5 || this.version === 6) {
// - A four-octet number denoting the time that the key was created.
this.created = util.readDate(bytes.subarray(pos, pos + 4));
pos += 4;
@@ -117,7 +117,7 @@ class PublicKeyPacket {
// - A one-octet number denoting the public-key algorithm of this key.
this.algorithm = bytes[pos++];
- if (this.version === 5) {
+ if (this.version >= 5) {
// - A four-octet scalar octet count for the following key material.
pos += 4;
}
@@ -147,7 +147,7 @@ class PublicKeyPacket {
arr.push(new Uint8Array([this.algorithm]));
const params = crypto.serializeParams(this.algorithm, this.publicParams);
- if (this.version === 5) {
+ if (this.version >= 5) {
// A four-octet scalar octet count for the following key material
arr.push(util.writeNumber(params.length, 4));
}
@@ -163,10 +163,9 @@ class PublicKeyPacket {
writeForHash(version) {
const bytes = this.writePublicKey();
- if (version === 5) {
- return util.concatUint8Array([new Uint8Array([0x9A]), util.writeNumber(bytes.length, 4), bytes]);
- }
- return util.concatUint8Array([new Uint8Array([0x99]), util.writeNumber(bytes.length, 2), bytes]);
+ const versionOctet = 0x95 + version;
+ const lengthOctets = version >= 5 ? 4 : 2;
+ return util.concatUint8Array([new Uint8Array([versionOctet]), util.writeNumber(bytes.length, lengthOctets), bytes]);
}
/**
@@ -201,7 +200,7 @@ class PublicKeyPacket {
await this.computeFingerprint();
this.keyID = new KeyID();
- if (this.version === 5) {
+ if (this.version >= 5) {
this.keyID.read(this.fingerprint.subarray(0, 8));
} else if (this.version === 4) {
this.keyID.read(this.fingerprint.subarray(12, 20));
@@ -216,7 +215,7 @@ class PublicKeyPacket {
async computeFingerprint() {
const toHash = this.writeForHash(this.version);
- if (this.version === 5) {
+ if (this.version >= 5) {
this.fingerprint = await crypto.hash.sha256(toHash);
} else if (this.version === 4) {
this.fingerprint = await crypto.hash.sha1(toHash);
diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js
index cab073350..d3e8616f9 100644
--- a/src/packet/secret_key.js
+++ b/src/packet/secret_key.js
@@ -100,6 +100,14 @@ class SecretKeyPacket extends PublicKeyPacket {
i++;
}
+ // - Only for a version 6 packet where the secret key material is
+ // encrypted (that is, where the previous octet is not zero), a one-
+ // octet scalar octet count of the cumulative length of all the
+ // following optional string-to-key parameter fields.
+ if (this.version === 6 && this.s2kUsage) {
+ i++;
+ }
+
try {
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// one-octet symmetric encryption algorithm.
@@ -112,6 +120,12 @@ class SecretKeyPacket extends PublicKeyPacket {
this.aead = bytes[i++];
}
+ // - [Optional] Only for a version 6 packet, and if string-to-key usage
+ // octet was 255, 254, or 253, an one-octet count of the following field.
+ if (this.version === 6) {
+ i++;
+ }
+
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above.
@@ -157,9 +171,14 @@ class SecretKeyPacket extends PublicKeyPacket {
this.isEncrypted = !!this.s2kUsage;
if (!this.isEncrypted) {
- const cleartext = this.keyMaterial.subarray(0, -2);
- if (!util.equalsUint8Array(util.writeChecksum(cleartext), this.keyMaterial.subarray(-2))) {
- throw new Error('Key checksum mismatch');
+ let cleartext;
+ if (this.version === 6) {
+ cleartext = this.keyMaterial;
+ } else {
+ cleartext = this.keyMaterial.subarray(0, -2);
+ if (!util.equalsUint8Array(util.writeChecksum(cleartext), this.keyMaterial.subarray(-2))) {
+ throw new Error('Key checksum mismatch');
+ }
}
try {
const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
@@ -200,10 +219,18 @@ class SecretKeyPacket extends PublicKeyPacket {
optionalFieldsArr.push(this.aead);
}
+ const s2k = this.s2k.write();
+
+ // - [Optional] Only for a version 6 packet, and if string-to-key usage
+ // octet was 255, 254, or 253, an one-octet count of the following field.
+ if (this.version === 6) {
+ optionalFieldsArr.push(s2k.length);
+ }
+
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above.
- optionalFieldsArr.push(...this.s2k.write());
+ optionalFieldsArr.push(...s2k);
}
// - [Optional] If secret data is encrypted (string-to-key usage octet
@@ -213,7 +240,7 @@ class SecretKeyPacket extends PublicKeyPacket {
optionalFieldsArr.push(...this.iv);
}
- if (this.version === 5) {
+ if (this.version === 5 || (this.version === 6 && this.s2kUsage)) {
arr.push(new Uint8Array([optionalFieldsArr.length]));
}
arr.push(new Uint8Array(optionalFieldsArr));
@@ -228,7 +255,7 @@ class SecretKeyPacket extends PublicKeyPacket {
}
arr.push(this.keyMaterial);
- if (!this.s2kUsage) {
+ if (!this.s2kUsage && this.version !== 6) {
arr.push(util.writeChecksum(this.keyMaterial));
}
}
From 8816bd754159f4cfcc2f217a822715d4e76fde26 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 15 Mar 2023 19:37:55 +0100
Subject: [PATCH 025/224] Replace config.v5Keys with config.v6Keys flag
Also, don't generate v5 keys flag, which has been removed from the draft specification.
---
openpgp.d.ts | 2 +-
src/config/config.js | 6 ++---
src/key/factory.js | 3 ---
src/packet/public_key.js | 2 +-
test/general/config.js | 10 +++----
test/general/key.js | 20 +++++++-------
test/general/openpgp.js | 10 +++----
test/general/packet.js | 48 +++++++++++++++++++++++++---------
test/typescript/definitions.ts | 2 +-
9 files changed, 61 insertions(+), 42 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index e674c0177..049c0d539 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -329,7 +329,7 @@ interface Config {
allowInsecureVerificationWithReformattedKeys: boolean;
constantTimePKCS1Decryption: boolean;
constantTimePKCS1DecryptionSupportedSymmetricAlgorithms: Set;
- v5Keys: boolean;
+ v6Keys: boolean;
preferredAEADAlgorithm: enums.aead;
aeadChunkSizeByte: number;
s2kType: enums.s2k.iterated | enums.s2k.argon2;
diff --git a/src/config/config.js b/src/config/config.js
index 1e6bd3ef9..e7f684351 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -68,13 +68,13 @@ export default {
*/
aeadChunkSizeByte: 12,
/**
- * Use V5 keys.
+ * Use v6 keys.
* Note: not all OpenPGP implementations are compatible with this option.
* **FUTURE OPENPGP.JS VERSIONS MAY BREAK COMPATIBILITY WHEN USING THIS OPTION**
* @memberof module:config
- * @property {Boolean} v5Keys
+ * @property {Boolean} v6Keys
*/
- v5Keys: false,
+ v6Keys: false,
/**
* S2K (String to Key) type, used for key derivation in the context of secret key encryption
* and password-encrypted data. Weaker s2k options are not allowed.
diff --git a/src/key/factory.js b/src/key/factory.js
index 44d7462f4..7a150aaf6 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -232,9 +232,6 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
if (config.aeadProtect) {
signatureProperties.features[0] |= enums.features.aead;
}
- if (config.v5Keys) {
- signatureProperties.features[0] |= enums.features.v5Keys;
- }
if (options.keyExpirationTime > 0) {
signatureProperties.keyExpirationTime = options.keyExpirationTime;
signatureProperties.keyNeverExpires = false;
diff --git a/src/packet/public_key.js b/src/packet/public_key.js
index d9d038f2d..af81f3a95 100644
--- a/src/packet/public_key.js
+++ b/src/packet/public_key.js
@@ -47,7 +47,7 @@ class PublicKeyPacket {
* Packet version
* @type {Integer}
*/
- this.version = config.v5Keys ? 5 : 4;
+ this.version = config.v6Keys ? 6 : 4;
/**
* Key creation date.
* @type {Date}
diff --git a/test/general/config.js b/test/general/config.js
index 038e72f56..73363792e 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -116,10 +116,10 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
});
it('openpgp.generateKey', async function() {
- const v5KeysVal = openpgp.config.v5Keys;
+ const v6KeysVal = openpgp.config.v6Keys;
const preferredHashAlgorithmVal = openpgp.config.preferredHashAlgorithm;
const showCommentVal = openpgp.config.showComment;
- openpgp.config.v5Keys = false;
+ openpgp.config.v6Keys = false;
openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha256;
openpgp.config.showComment = false;
@@ -134,7 +134,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm);
const config = {
- v5Keys: true,
+ v6Keys: true,
showComment: true,
preferredHashAlgorithm: openpgp.enums.hash.sha512
};
@@ -144,11 +144,11 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
};
const { privateKey: privateKeyArmored2 } = await openpgp.generateKey(opt2);
const key2 = await openpgp.readKey({ armoredKey: privateKeyArmored2 });
- expect(key2.keyPacket.version).to.equal(5);
+ expect(key2.keyPacket.version).to.equal(6);
expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
} finally {
- openpgp.config.v5Keys = v5KeysVal;
+ openpgp.config.v6Keys = v6KeysVal;
openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
openpgp.config.showComment = showCommentVal;
}
diff --git a/test/general/key.js b/test/general/key.js
index 661f19047..04a995414 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -2258,7 +2258,7 @@ function versionSpecificTests() {
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.uncompressed, compr.zlib, compr.zip]);
let expectedFeatures;
- if (openpgp.config.v5Keys) {
+ if (openpgp.config.v6Keys) {
expectedFeatures = [7]; // v5 + aead + mdc
} else if (openpgp.config.aeadProtect) {
expectedFeatures = [3]; // aead + mdc
@@ -2303,7 +2303,7 @@ function versionSpecificTests() {
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zip, compr.zlib, compr.uncompressed]);
let expectedFeatures;
- if (openpgp.config.v5Keys) {
+ if (openpgp.config.v6Keys) {
expectedFeatures = [7]; // v5 + aead + mdc
} else if (openpgp.config.aeadProtect) {
expectedFeatures = [3]; // aead + mdc
@@ -2894,30 +2894,30 @@ function versionSpecificTests() {
}
export default () => describe('Key', function() {
- let v5KeysVal;
+ let v6KeysVal;
let aeadProtectVal;
tryTests('V4', versionSpecificTests, {
if: !openpgp.config.ci,
beforeEach: function() {
- v5KeysVal = openpgp.config.v5Keys;
- openpgp.config.v5Keys = false;
+ v6KeysVal = openpgp.config.v6Keys;
+ openpgp.config.v6Keys = false;
},
afterEach: function() {
- openpgp.config.v5Keys = v5KeysVal;
+ openpgp.config.v6Keys = v6KeysVal;
}
});
- tryTests('V5', versionSpecificTests, {
+ tryTests('V6', versionSpecificTests, {
if: !openpgp.config.ci,
beforeEach: function() {
- v5KeysVal = openpgp.config.v5Keys;
+ v6KeysVal = openpgp.config.v6Keys;
aeadProtectVal = openpgp.config.aeadProtect;
- openpgp.config.v5Keys = true;
+ openpgp.config.v6Keys = true;
openpgp.config.aeadProtect = true;
},
afterEach: function() {
- openpgp.config.v5Keys = v5KeysVal;
+ openpgp.config.v6Keys = v6KeysVal;
openpgp.config.aeadProtect = aeadProtectVal;
}
});
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 063265183..20a8e1ac3 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -2231,7 +2231,7 @@ XfA3pqV4mTzF
let aeadProtectVal;
let preferredAEADAlgorithmVal;
let aeadChunkSizeByteVal;
- let v5KeysVal;
+ let v6KeysVal;
let minRSABitsVal;
beforeEach(async function() {
@@ -2248,7 +2248,7 @@ XfA3pqV4mTzF
aeadProtectVal = openpgp.config.aeadProtect;
preferredAEADAlgorithmVal = openpgp.config.preferredAEADAlgorithm;
aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
- v5KeysVal = openpgp.config.v5Keys;
+ v6KeysVal = openpgp.config.v6Keys;
minRSABitsVal = openpgp.config.minRSABits;
openpgp.config.minRSABits = 512;
@@ -2258,7 +2258,7 @@ XfA3pqV4mTzF
openpgp.config.aeadProtect = aeadProtectVal;
openpgp.config.preferredAEADAlgorithm = preferredAEADAlgorithmVal;
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
- openpgp.config.v5Keys = v5KeysVal;
+ openpgp.config.v6Keys = v6KeysVal;
openpgp.config.minRSABits = minRSABitsVal;
});
@@ -2293,12 +2293,12 @@ XfA3pqV4mTzF
}
});
- tryTests('GCM mode (V5 keys)', tests, {
+ tryTests('GCM mode (V6 keys)', tests, {
if: true,
beforeEach: function() {
openpgp.config.aeadProtect = true;
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM;
- openpgp.config.v5Keys = true;
+ openpgp.config.v6Keys = true;
// Monkey-patch AEAD feature flag
publicKey.users[0].selfCertifications[0].features = [7];
diff --git a/test/general/packet.js b/test/general/packet.js
index ced7121cf..dca36eadc 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -854,8 +854,36 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
});
it('Writing of unencrypted v5 secret key packet', async function() {
- const originalV5KeysSetting = openpgp.config.v5Keys;
- openpgp.config.v5Keys = true;
+ const packet = new openpgp.SecretKeyPacket();
+ packet.version = 5;
+ packet.privateParams = { key: new Uint8Array([1, 2, 3]) };
+ packet.publicParams = { pubKey: new Uint8Array([4, 5, 6]) };
+ packet.algorithm = openpgp.enums.publicKey.rsaSign;
+ packet.isEncrypted = false;
+ packet.s2kUsage = 0;
+
+ const written = packet.write();
+ expect(written.length).to.equal(28);
+
+ /* The serialized length of private data */
+ expect(written[17]).to.equal(0);
+ expect(written[18]).to.equal(0);
+ expect(written[19]).to.equal(0);
+ expect(written[20]).to.equal(5);
+
+ /**
+ * The private data
+ *
+ * The 2 bytes missing here are the length prefix of the MPI
+ */
+ expect(written[23]).to.equal(1);
+ expect(written[24]).to.equal(2);
+ expect(written[25]).to.equal(3);
+ });
+
+ it('Writing of unencrypted v6 secret key packet', async function() {
+ const originalv6KeysSetting = openpgp.config.v6Keys;
+ openpgp.config.v6Keys = true;
try {
const packet = new openpgp.SecretKeyPacket();
@@ -867,24 +895,18 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
packet.s2kUsage = 0;
const written = packet.write();
- expect(written.length).to.equal(28);
-
- /* The serialized length of private data */
- expect(written[17]).to.equal(0);
- expect(written[18]).to.equal(0);
- expect(written[19]).to.equal(0);
- expect(written[20]).to.equal(5);
+ expect(written.length).to.equal(21);
/**
* The private data
*
* The 2 bytes missing here are the length prefix of the MPI
*/
- expect(written[23]).to.equal(1);
- expect(written[24]).to.equal(2);
- expect(written[25]).to.equal(3);
+ expect(written[18]).to.equal(1);
+ expect(written[19]).to.equal(2);
+ expect(written[20]).to.equal(3);
} finally {
- openpgp.config.v5Keys = originalV5KeysSetting;
+ openpgp.config.v6Keys = originalv6KeysSetting;
}
});
diff --git a/test/typescript/definitions.ts b/test/typescript/definitions.ts
index c3513ef4e..949830434 100644
--- a/test/typescript/definitions.ts
+++ b/test/typescript/definitions.ts
@@ -21,7 +21,7 @@ import {
(async () => {
// Generate keys
- const keyOptions = { userIDs: [{ email: 'user@corp.co' }], config: { v5Keys: true } };
+ const keyOptions = { userIDs: [{ email: 'user@corp.co' }], config: { v6Keys: true } };
const { privateKey: privateKeyArmored, publicKey: publicKeyArmored } = await generateKey(keyOptions);
const { privateKey: privateKeyBinary } = await generateKey({ ...keyOptions, format: 'binary' });
const { privateKey, publicKey, revocationCertificate } = await generateKey({ ...keyOptions, format: 'object' });
From a5f1ab8a1c9ba5994eac5ea9eddec8ca2876e51c Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 15 Mar 2023 19:28:52 +0100
Subject: [PATCH 026/224] Add support for v6 signatures
Compared to v5 signatures, v6 signatures include a salt, and the
subpacket lengths are increased from 2 to 4 bytes.
---
src/packet/signature.js | 69 ++++++++++++++++++++++++++++++++---------
1 file changed, 54 insertions(+), 15 deletions(-)
diff --git a/src/packet/signature.js b/src/packet/signature.js
index 8bd0347a4..25188a1dd 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -60,6 +60,7 @@ class SignaturePacket {
this.signatureData = null;
this.unhashedSubpackets = [];
this.signedHashValue = null;
+ this.salt = null;
this.created = null;
this.signatureExpirationTime = null;
@@ -110,7 +111,7 @@ class SignaturePacket {
let i = 0;
this.version = bytes[i++];
- if (this.version !== 4 && this.version !== 5) {
+ if (this.version !== 4 && this.version !== 5 && this.version !== 6) {
throw new UnsupportedError(`Version ${this.version} of the signature packet is unsupported.`);
}
@@ -139,6 +140,20 @@ class SignaturePacket {
this.signedHashValue = bytes.subarray(i, i + 2);
i += 2;
+ // Only for v6 signatures, a variable-length field containing:
+ if (this.version === 6) {
+ // A one-octet salt size. The value MUST match the value defined
+ // for the hash algorithm as specified in Table 23 (Hash algorithm registry).
+ const saltLength = bytes[i++];
+ if (saltLength !== saltLengthForHash(this.hashAlgorithm)) {
+ throw new Error('Unexpected salt size for the hash algorithm');
+ }
+
+ // The salt; a random value value of the specified size.
+ this.salt = bytes.subarray(i, i + saltLength);
+ i += saltLength;
+ }
+
this.params = crypto.signature.parseSignatureParams(this.publicKeyAlgorithm, bytes.subarray(i, bytes.length));
}
@@ -159,6 +174,10 @@ class SignaturePacket {
arr.push(this.signatureData);
arr.push(this.writeUnhashedSubPackets());
arr.push(this.signedHashValue);
+ if (this.version === 6) {
+ arr.push(new Uint8Array([this.salt.length]));
+ arr.push(this.salt);
+ }
arr.push(this.writeParams());
return util.concat(arr);
}
@@ -173,18 +192,15 @@ class SignaturePacket {
* @async
*/
async sign(key, data, date = new Date(), detached = false) {
- if (key.version === 5) {
- this.version = 5;
- } else {
- this.version = 4;
- }
- const arr = [new Uint8Array([this.version, this.signatureType, this.publicKeyAlgorithm, this.hashAlgorithm])];
+ this.version = key.version;
this.created = util.normalizeDate(date);
this.issuerKeyVersion = key.version;
this.issuerFingerprint = key.getFingerprintBytes();
this.issuerKeyID = key.getKeyID();
+ const arr = [new Uint8Array([this.version, this.signatureType, this.publicKeyAlgorithm, this.hashAlgorithm])];
+
// Add hashed subpackets
arr.push(this.writeHashedSubPackets());
@@ -195,6 +211,10 @@ class SignaturePacket {
this.signatureData = util.concat(arr);
+ if (this.version === 6) {
+ const saltLength = saltLengthForHash(this.hashAlgorithm);
+ this.salt = await crypto.random.getRandomBytes(saltLength);
+ }
const toHash = this.toHash(this.signatureType, data, detached);
const hash = await this.hash(this.signatureType, data, toHash, detached);
@@ -255,7 +275,7 @@ class SignaturePacket {
bytes = util.concat([bytes, this.revocationKeyFingerprint]);
arr.push(writeSubPacket(sub.revocationKey, false, bytes));
}
- if (!this.issuerKeyID.isNull() && this.issuerKeyVersion !== 5) {
+ if (!this.issuerKeyID.isNull() && this.issuerKeyVersion < 5) {
// If the version of [the] key is greater than 4, this subpacket
// MUST NOT be included in the signature.
arr.push(writeSubPacket(sub.issuer, true, this.issuerKeyID.write()));
@@ -320,7 +340,7 @@ class SignaturePacket {
if (this.issuerFingerprint !== null) {
bytes = [new Uint8Array([this.issuerKeyVersion]), this.issuerFingerprint];
bytes = util.concat(bytes);
- arr.push(writeSubPacket(sub.issuerFingerprint, this.version === 5, bytes));
+ arr.push(writeSubPacket(sub.issuerFingerprint, this.version >= 5, bytes));
}
if (this.preferredAEADAlgorithms !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.preferredAEADAlgorithms));
@@ -328,7 +348,7 @@ class SignaturePacket {
}
const result = util.concat(arr);
- const length = util.writeNumber(result.length, 2);
+ const length = util.writeNumber(result.length, this.version === 6 ? 4 : 2);
return util.concat([length, result]);
}
@@ -345,7 +365,7 @@ class SignaturePacket {
});
const result = util.concat(arr);
- const length = util.writeNumber(result.length, 2);
+ const length = util.writeNumber(result.length, this.version === 6 ? 4 : 2);
return util.concat([length, result]);
}
@@ -509,7 +529,7 @@ class SignaturePacket {
// Issuer Fingerprint
this.issuerKeyVersion = bytes[mypos++];
this.issuerFingerprint = bytes.subarray(mypos, bytes.length);
- if (this.issuerKeyVersion === 5) {
+ if (this.issuerKeyVersion >= 5) {
this.issuerKeyID.read(this.issuerFingerprint);
} else {
this.issuerKeyID.read(this.issuerFingerprint.subarray(-8));
@@ -531,10 +551,12 @@ class SignaturePacket {
}
readSubPackets(bytes, trusted = true, config) {
+ const subpacketLengthBytes = this.version === 6 ? 4 : 2;
+
// Two-octet scalar octet count for following subpacket data.
- const subpacketLength = util.readNumber(bytes.subarray(0, 2));
+ const subpacketLength = util.readNumber(bytes.subarray(0, subpacketLengthBytes));
- let i = 2;
+ let i = subpacketLengthBytes;
// subpacket data set (zero or more subpackets)
while (i < 2 + subpacketLength) {
@@ -645,7 +667,7 @@ class SignaturePacket {
toHash(signatureType, data, detached = false) {
const bytes = this.toSign(signatureType, data);
- return util.concat([bytes, this.signatureData, this.calculateTrailer(data, detached)]);
+ return util.concat([this.salt || new Uint8Array(), bytes, this.signatureData, this.calculateTrailer(data, detached)]);
}
async hash(signatureType, data, toHash, detached = false) {
@@ -769,3 +791,20 @@ function writeSubPacket(type, critical, data) {
arr.push(data);
return util.concat(arr);
}
+
+/**
+ * Select the required salt length for the given hash algorithm, as per Table 23 (Hash algorithm registry) of the crypto refresh.
+ * @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#section-9.5|Crypto Refresh Section 9.5}
+ * @param {enums.hash} hashAlgorithm - Hash algorithm.
+ * @returns {Integer} Salt length.
+ * @private
+ */
+function saltLengthForHash(hashAlgorithm) {
+ switch (hashAlgorithm) {
+ case enums.hash.sha256: return 16;
+ case enums.hash.sha384: return 24;
+ case enums.hash.sha512: return 32;
+ case enums.hash.sha224: return 16;
+ default: throw new Error('Unsupported hash function for V6 signatures');
+ }
+}
From 71ac6aff2f0813b97c1f26784e95839ca1e9e341 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 31 Aug 2023 15:24:44 +0200
Subject: [PATCH 027/224] Only parse Issuer Key ID subpacket in v4 signatures
This packet must not be included in newer signature versions, but if it is
present it can cause internal inconsistencies, so we avoid parsing it.
---
src/packet/signature.js | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/packet/signature.js b/src/packet/signature.js
index 25188a1dd..07f2a823d 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -444,7 +444,19 @@ class SignaturePacket {
case enums.signatureSubpacket.issuer:
// Issuer
- this.issuerKeyID.read(bytes.subarray(mypos, bytes.length));
+ if (this.version === 4) {
+ this.issuerKeyID.read(bytes.subarray(mypos, bytes.length));
+ } else if (hashed) {
+ // If the version of the key is greater than 4, this subpacket MUST NOT be included in the signature,
+ // since the Issuer Fingerprint subpacket is to be used instead.
+ // The `issuerKeyID` value will be set when reading the issuerFingerprint packet.
+ // For this reason, if the issuer Key ID packet is present but unhashed, we simply ignore it,
+ // to avoid situations where `.getSigningKeyIDs()` returns a keyID potentially different from the (signed)
+ // issuerFingerprint.
+ // If the packet is hashed, then we reject the signature, to avoid verifying data different from
+ // what was parsed.
+ throw new Error('Unexpected Issuer Key ID subpacket');
+ }
break;
case enums.signatureSubpacket.notationData: {
From 091be036f40c65f32c347b9448c7bbdfd382a70a Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 31 Aug 2023 16:00:11 +0200
Subject: [PATCH 028/224] Rename `enums.signatureSubpacket.issuer` to
`.issuerKeyID`
To reflect the subpacket rename in the crypto-refresh.
---
src/enums.js | 2 +-
src/packet/signature.js | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/enums.js b/src/enums.js
index 33982062a..fd6fb7252 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -378,7 +378,7 @@ export default {
placeholderBackwardsCompatibility: 10,
preferredSymmetricAlgorithms: 11,
revocationKey: 12,
- issuer: 16,
+ issuerKeyID: 16,
notationData: 20,
preferredHashAlgorithms: 21,
preferredCompressionAlgorithms: 22,
diff --git a/src/packet/signature.js b/src/packet/signature.js
index 07f2a823d..f129dbef8 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -30,7 +30,7 @@ const verified = Symbol('verified');
// Tampering with those invalidates the signature, so we still trust them and parse them.
// All other unhashed subpackets are ignored.
const allowedUnhashedSubpackets = new Set([
- enums.signatureSubpacket.issuer,
+ enums.signatureSubpacket.issuerKeyID,
enums.signatureSubpacket.issuerFingerprint,
enums.signatureSubpacket.embeddedSignature
]);
@@ -278,7 +278,7 @@ class SignaturePacket {
if (!this.issuerKeyID.isNull() && this.issuerKeyVersion < 5) {
// If the version of [the] key is greater than 4, this subpacket
// MUST NOT be included in the signature.
- arr.push(writeSubPacket(sub.issuer, true, this.issuerKeyID.write()));
+ arr.push(writeSubPacket(sub.issuerKeyID, true, this.issuerKeyID.write()));
}
this.rawNotations.forEach(({ name, value, humanReadable, critical }) => {
bytes = [new Uint8Array([humanReadable ? 0x80 : 0, 0, 0, 0])];
@@ -442,7 +442,7 @@ class SignaturePacket {
this.revocationKeyFingerprint = bytes.subarray(mypos, mypos + 20);
break;
- case enums.signatureSubpacket.issuer:
+ case enums.signatureSubpacket.issuerKeyID:
// Issuer
if (this.version === 4) {
this.issuerKeyID.read(bytes.subarray(mypos, bytes.length));
From 3ea21f6c6ade6047bfc628a257f9f3e36db0d48a Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 2 Mar 2022 17:16:58 +0100
Subject: [PATCH 029/224] For v6 keys, create direct-key signature for key
properties
Store key flags, features and preferences in a direct-key signature
instead of user ID signatures, for V6 keys.
---
src/key/factory.js | 43 +++++++++++++++++++++++++++++-------------
test/general/config.js | 2 +-
2 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/src/key/factory.js b/src/key/factory.js
index 7a150aaf6..8d6094155 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -188,18 +188,12 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
const packetlist = new PacketList();
packetlist.push(secretKeyPacket);
- await Promise.all(options.userIDs.map(async function(userID, index) {
- function createPreferredAlgos(algos, preferredAlgo) {
- return [preferredAlgo, ...algos.filter(algo => algo !== preferredAlgo)];
- }
-
- const userIDPacket = UserIDPacket.fromObject(userID);
- const dataToSign = {};
- dataToSign.userID = userIDPacket;
- dataToSign.key = secretKeyPacket;
+ function createPreferredAlgos(algos, preferredAlgo) {
+ return [preferredAlgo, ...algos.filter(algo => algo !== preferredAlgo)];
+ }
+ function getKeySignatureProperties() {
const signatureProperties = {};
- signatureProperties.signatureType = enums.signature.certGeneric;
signatureProperties.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
signatureProperties.preferredSymmetricAlgorithms = createPreferredAlgos([
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
@@ -223,9 +217,6 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
enums.compression.zip,
enums.compression.uncompressed
], config.preferredCompressionAlgorithm);
- if (index === 0) {
- signatureProperties.isPrimaryUserID = true;
- }
// integrity protection always enabled
signatureProperties.features = [0];
signatureProperties.features[0] |= enums.features.modificationDetection;
@@ -236,6 +227,32 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
signatureProperties.keyExpirationTime = options.keyExpirationTime;
signatureProperties.keyNeverExpires = false;
}
+ return signatureProperties;
+ }
+
+ if (secretKeyPacket.version === 6) { // add direct key signature with key prefs
+ const dataToSign = {
+ key: secretKeyPacket
+ };
+
+ const signatureProperties = getKeySignatureProperties();
+ signatureProperties.signatureType = enums.signature.key;
+
+ const signaturePacket = await helper.createSignaturePacket(dataToSign, null, secretKeyPacket, signatureProperties, options.date, undefined, undefined, undefined, config);
+ packetlist.push(signaturePacket);
+ }
+
+ await Promise.all(options.userIDs.map(async function(userID, index) {
+ const userIDPacket = UserIDPacket.fromObject(userID);
+ const dataToSign = {
+ userID: userIDPacket,
+ key: secretKeyPacket
+ };
+ const signatureProperties = secretKeyPacket.version !== 6 ? getKeySignatureProperties() : {};
+ signatureProperties.signatureType = enums.signature.certGeneric;
+ if (index === 0) {
+ signatureProperties.isPrimaryUserID = true;
+ }
const signaturePacket = await helper.createSignaturePacket(dataToSign, null, secretKeyPacket, signatureProperties, options.date, undefined, undefined, undefined, config);
diff --git a/test/general/config.js b/test/general/config.js
index 73363792e..e522097a2 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -146,7 +146,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
const key2 = await openpgp.readKey({ armoredKey: privateKeyArmored2 });
expect(key2.keyPacket.version).to.equal(6);
expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
- expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
+ expect(key2.directSignatures[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
} finally {
openpgp.config.v6Keys = v6KeysVal;
openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
From bafdab20cfbad5b744415fdf4db072511c4d4840 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 2 Mar 2022 17:17:49 +0100
Subject: [PATCH 030/224] Don't require User IDs for v6 keys
---
src/openpgp.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/openpgp.js b/src/openpgp.js
index 28554e7b9..cef01e9b3 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -58,8 +58,8 @@ export async function generateKey({ userIDs = [], passphrase, type = 'ecc', rsaB
userIDs = toArray(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
- if (userIDs.length === 0) {
- throw new Error('UserIDs are required for key generation');
+ if (userIDs.length === 0 && !config.v6Keys) {
+ throw new Error('UserIDs are required for V4 keys');
}
if (type === 'rsa' && rsaBits < config.minRSABits) {
throw new Error(`rsaBits should be at least ${config.minRSABits}, got: ${rsaBits}`);
@@ -102,8 +102,8 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase, keyExp
userIDs = toArray(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
- if (userIDs.length === 0) {
- throw new Error('UserIDs are required for key reformat');
+ if (userIDs.length === 0 && privateKey.keyPacket.version !== 6) {
+ throw new Error('UserIDs are required for V4 keys');
}
const options = { privateKey, userIDs, passphrase, keyExpirationTime, date };
From 5078b8a66dd62048e526d134cbd5bab4dde57795 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 2 Mar 2022 17:18:44 +0100
Subject: [PATCH 031/224] Generate SEIPD v2 flag instead of AEAD flag
The AEAD Encrypted Data packet has been removed from the draft
in favor of version 2 of the Sym. Encrypted Integrity Protected
Data packet. It also has a new feature flag to match.
---
src/enums.js | 3 ++-
src/key/factory.js | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/enums.js b/src/enums.js
index fd6fb7252..b120ebb74 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -462,7 +462,8 @@ export default {
aead: 2,
/** 0x04 - Version 5 Public-Key Packet format and corresponding new
* fingerprint format */
- v5Keys: 4
+ v5Keys: 4,
+ seipdv2: 8
},
/**
diff --git a/src/key/factory.js b/src/key/factory.js
index 8d6094155..516a3ceec 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -221,7 +221,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
signatureProperties.features = [0];
signatureProperties.features[0] |= enums.features.modificationDetection;
if (config.aeadProtect) {
- signatureProperties.features[0] |= enums.features.aead;
+ signatureProperties.features[0] |= enums.features.seipdv2;
}
if (options.keyExpirationTime > 0) {
signatureProperties.keyExpirationTime = options.keyExpirationTime;
From b6dc112eb358c70b0afc95b02e190663a3b54f87 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 2 Mar 2022 18:17:16 +0100
Subject: [PATCH 032/224] Add (non-experimental) GCM
Also, set it as the preferred AEAD algorithm.
---
src/config/config.js | 2 +-
src/enums.js | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/config/config.js b/src/config/config.js
index e7f684351..4b273c914 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -58,7 +58,7 @@ export default {
* @memberof module:config
* @property {Integer} preferredAEADAlgorithm Default AEAD mode {@link module:enums.aead}
*/
- preferredAEADAlgorithm: enums.aead.eax,
+ preferredAEADAlgorithm: enums.aead.gcm,
/**
* Chunk Size Byte for Authenticated Encryption with Additional Data (AEAD) mode
* Only has an effect when aeadProtect is set to true.
diff --git a/src/enums.js b/src/enums.js
index b120ebb74..342373e0c 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -197,6 +197,7 @@ export default {
aead: {
eax: 1,
ocb: 2,
+ gcm: 3,
experimentalGCM: 100 // Private algorithm
},
From 5008f07808d7d67592cdb7cd2359ec9ea639f277 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 2 Mar 2022 18:50:40 +0100
Subject: [PATCH 033/224] Add preferred ciphersuites subpacket
This subpacket replaces both symmetric algorithm preferences and
AEAD algorithm preferences when AEAD is supported, by providing
sets of preferred symmetric and AEAD algorithm pairs.
We still keep the symmetric algorithm preferences in case AEAD is
not supported.
---
src/enums.js | 3 ++-
src/key/factory.js | 11 +++++++++--
src/packet/signature.js | 12 ++++++++++++
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/enums.js b/src/enums.js
index 342373e0c..aa49c9729 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -394,7 +394,8 @@ export default {
signatureTarget: 31,
embeddedSignature: 32,
issuerFingerprint: 33,
- preferredAEADAlgorithms: 34
+ preferredAEADAlgorithms: 34,
+ preferredCipherSuites: 39
},
/** Key flags
diff --git a/src/key/factory.js b/src/key/factory.js
index 516a3ceec..95bcc7488 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -195,17 +195,24 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
function getKeySignatureProperties() {
const signatureProperties = {};
signatureProperties.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
- signatureProperties.preferredSymmetricAlgorithms = createPreferredAlgos([
+ const symmetricAlgorithms = createPreferredAlgos([
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
enums.symmetric.aes256,
enums.symmetric.aes128,
enums.symmetric.aes192
], config.preferredSymmetricAlgorithm);
+ signatureProperties.preferredSymmetricAlgorithms = symmetricAlgorithms;
if (config.aeadProtect) {
- signatureProperties.preferredAEADAlgorithms = createPreferredAlgos([
+ const aeadAlgorithms = createPreferredAlgos([
+ enums.aead.gcm,
enums.aead.eax,
enums.aead.ocb
], config.preferredAEADAlgorithm);
+ signatureProperties.preferredCipherSuites = aeadAlgorithms.flatMap(aeadAlgorithm => {
+ return symmetricAlgorithms.map(symmetricAlgorithm => {
+ return [symmetricAlgorithm, aeadAlgorithm];
+ });
+ });
}
signatureProperties.preferredHashAlgorithms = createPreferredAlgos([
// prefer fast asm.js implementations (SHA-256)
diff --git a/src/packet/signature.js b/src/packet/signature.js
index f129dbef8..eb7f8062c 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -97,6 +97,7 @@ class SignaturePacket {
this.issuerKeyVersion = null;
this.issuerFingerprint = null;
this.preferredAEADAlgorithms = null;
+ this.preferredCipherSuites = null;
this.revoked = null;
this[verified] = null;
@@ -346,6 +347,10 @@ class SignaturePacket {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.preferredAEADAlgorithms));
arr.push(writeSubPacket(sub.preferredAEADAlgorithms, false, bytes));
}
+ if (this.preferredCipherSuites !== null) {
+ bytes = new Uint8Array([].concat(...this.preferredCipherSuites));
+ arr.push(writeSubPacket(sub.preferredCipherSuites, false, bytes));
+ }
const result = util.concat(arr);
const length = util.writeNumber(result.length, this.version === 6 ? 4 : 2);
@@ -551,6 +556,13 @@ class SignaturePacket {
// Preferred AEAD Algorithms
this.preferredAEADAlgorithms = [...bytes.subarray(mypos, bytes.length)];
break;
+ case enums.signatureSubpacket.preferredCipherSuites:
+ // Preferred AEAD Cipher Suites
+ this.preferredCipherSuites = [];
+ for (let i = mypos; i < bytes.length; i += 2) {
+ this.preferredCipherSuites.push([bytes[i], bytes[i + 1]]);
+ }
+ break;
default: {
const err = new Error(`Unknown signature subpacket type ${type}`);
if (critical) {
From b077504b3cf6d9ff0d23e83f3d2b839ca1ccdc73 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 6 Dec 2022 13:22:09 +0100
Subject: [PATCH 034/224] Remove AES-192 from preferred symmetric algorithms
Chrome's Web Crypto implementation doesn't support it, and it
seems unnecessary to list it when AES-256 is available.
---
src/key/factory.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/key/factory.js b/src/key/factory.js
index 95bcc7488..b25c9873a 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -196,10 +196,9 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
const signatureProperties = {};
signatureProperties.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
const symmetricAlgorithms = createPreferredAlgos([
- // prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
+ // prefer aes256, aes128, no aes192 (no Web Crypto support in Chrome: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
enums.symmetric.aes256,
- enums.symmetric.aes128,
- enums.symmetric.aes192
+ enums.symmetric.aes128
], config.preferredSymmetricAlgorithm);
signatureProperties.preferredSymmetricAlgorithms = symmetricAlgorithms;
if (config.aeadProtect) {
From 762775bc03ef8d6fcd1e6fa8f6cc830e586132f5 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 30 Nov 2022 17:48:06 +0100
Subject: [PATCH 035/224] Don't generate armor checksum lines
---
src/encoding/armor.js | 8 --------
test/general/armor.js | 3 +--
2 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/src/encoding/armor.js b/src/encoding/armor.js
index 47442c34d..6011b94cb 100644
--- a/src/encoding/armor.js
+++ b/src/encoding/armor.js
@@ -369,21 +369,18 @@ export function armor(messageType, body, partIndex, partTotal, customComment, co
hash = body.hash;
body = body.data;
}
- const bodyClone = stream.passiveClone(body);
const result = [];
switch (messageType) {
case enums.armor.multipartSection:
result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
break;
case enums.armor.multipartLast:
result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP MESSAGE, PART ' + partIndex + '-----\n');
break;
case enums.armor.signed:
@@ -393,35 +390,30 @@ export function armor(messageType, body, partIndex, partTotal, customComment, co
result.push('\n-----BEGIN PGP SIGNATURE-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP SIGNATURE-----\n');
break;
case enums.armor.message:
result.push('-----BEGIN PGP MESSAGE-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP MESSAGE-----\n');
break;
case enums.armor.publicKey:
result.push('-----BEGIN PGP PUBLIC KEY BLOCK-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP PUBLIC KEY BLOCK-----\n');
break;
case enums.armor.privateKey:
result.push('-----BEGIN PGP PRIVATE KEY BLOCK-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP PRIVATE KEY BLOCK-----\n');
break;
case enums.armor.signature:
result.push('-----BEGIN PGP SIGNATURE-----\n');
result.push(addheader(customComment, config));
result.push(base64.encode(body));
- result.push('=', getCheckSum(bodyClone));
result.push('-----END PGP SIGNATURE-----\n');
break;
}
diff --git a/test/general/armor.js b/test/general/armor.js
index 10624ee2a..7f7c788b6 100644
--- a/test/general/armor.js
+++ b/test/general/armor.js
@@ -379,7 +379,6 @@ VWx8AtKEInT8YvN19cS2Jpr81jCN819IqgDr+YQezYMwZMzWISmA3w5Z3UCU
lO771jlg4fHlWOZ2nJqselFlNc3X/VoZ8swmMkI6KVDV+rKaeyTWe61Up0Jj
NJCB6+LWtabSoVIjNVgKwyKqyTLaESNwC2ogZwkdE8qPGiDFEHo4Gg9zuRof
-=trqv
-----END PGP PUBLIC KEY BLOCK-----
`;
@@ -390,7 +389,7 @@ NJCB6+LWtabSoVIjNVgKwyKqyTLaESNwC2ogZwkdE8qPGiDFEHo4Gg9zuRof
.replace(/^(Version|Comment): .*$\n/mg, '')
).to.equal(
pubKey
- .replace('\n=', '=')
+ .replace('\n-', '-')
.replace(/\n\r/g, '\n')
);
});
From 2419e6b4c5a1111ba06958d2562674fce1eb8c41 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 6 Dec 2022 12:43:02 +0100
Subject: [PATCH 036/224] Remove compression algorithms from preferences
---
src/key/factory.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/key/factory.js b/src/key/factory.js
index b25c9873a..6c1d7ee17 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -219,8 +219,6 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
enums.hash.sha512
], config.preferredHashAlgorithm);
signatureProperties.preferredCompressionAlgorithms = createPreferredAlgos([
- enums.compression.zlib,
- enums.compression.zip,
enums.compression.uncompressed
], config.preferredCompressionAlgorithm);
// integrity protection always enabled
From f21e327e69b893a3da63b3bb1212b43e01fb1400 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 6 Dec 2022 14:33:42 +0100
Subject: [PATCH 037/224] Tests: update expected algorithm preferences
---
test/general/key.js | 76 +++++++++++++++++++++++++++------------------
1 file changed, 45 insertions(+), 31 deletions(-)
diff --git a/test/general/key.js b/test/general/key.js
index 04a995414..2f266ef93 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -2240,32 +2240,36 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
function versionSpecificTests() {
it('Preferences of generated key', function() {
const testPref = function(key) {
+ const selfSignature = openpgp.config.v6Keys ? key.directSignatures[0] : key.users[0].selfCertifications[0];
// key flags
const keyFlags = openpgp.enums.keyFlags;
- expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys);
- expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData);
+ expect(selfSignature.keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys);
+ expect(selfSignature.keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData);
expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptCommunication).to.equal(keyFlags.encryptCommunication);
expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptStorage).to.equal(keyFlags.encryptStorage);
const sym = openpgp.enums.symmetric;
- expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes128, sym.aes192]);
+ expect(selfSignature.preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes128]);
if (openpgp.config.aeadProtect) {
const aead = openpgp.enums.aead;
- expect(key.users[0].selfCertifications[0].preferredAEADAlgorithms).to.eql([aead.eax, aead.ocb]);
+ expect(selfSignature.preferredCipherSuites).to.eql([
+ [sym.aes256, aead.gcm],
+ [sym.aes128, aead.gcm],
+ [sym.aes256, aead.eax],
+ [sym.aes128, aead.eax],
+ [sym.aes256, aead.ocb],
+ [sym.aes128, aead.ocb]
+ ]);
}
const hash = openpgp.enums.hash;
- expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha512]);
+ expect(selfSignature.preferredHashAlgorithms).to.eql([hash.sha256, hash.sha512]);
const compr = openpgp.enums.compression;
- expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.uncompressed, compr.zlib, compr.zip]);
-
- let expectedFeatures;
- if (openpgp.config.v6Keys) {
- expectedFeatures = [7]; // v5 + aead + mdc
- } else if (openpgp.config.aeadProtect) {
- expectedFeatures = [3]; // aead + mdc
- } else {
- expectedFeatures = [1]; // mdc
+ expect(selfSignature.preferredCompressionAlgorithms).to.eql([compr.uncompressed]);
+
+ let expectedFeatures = 0x01; // SEIPDv1
+ if (openpgp.config.aeadProtect) {
+ expectedFeatures |= 0x08; // SEIPDv2
}
- expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures);
+ expect(selfSignature.features).to.eql([expectedFeatures]);
};
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' };
return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
@@ -2281,36 +2285,46 @@ function versionSpecificTests() {
const preferredAEADAlgorithmVal = openpgp.config.preferredAEADAlgorithm;
openpgp.config.preferredSymmetricAlgorithm = openpgp.enums.symmetric.aes192;
openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha224;
- openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zip;
+ openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zlib;
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM;
const testPref = function(key) {
+ const selfSignature = openpgp.config.v6Keys ? key.directSignatures[0] : key.users[0].selfCertifications[0];
// key flags
const keyFlags = openpgp.enums.keyFlags;
- expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys);
- expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData);
+ expect(selfSignature.keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys);
+ expect(selfSignature.keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData);
expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptCommunication).to.equal(keyFlags.encryptCommunication);
expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptStorage).to.equal(keyFlags.encryptStorage);
const sym = openpgp.enums.symmetric;
- expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes192, sym.aes256, sym.aes128]);
+ expect(selfSignature.preferredSymmetricAlgorithms).to.eql([sym.aes192, sym.aes256, sym.aes128]);
if (openpgp.config.aeadProtect) {
const aead = openpgp.enums.aead;
- expect(key.users[0].selfCertifications[0].preferredAEADAlgorithms).to.eql([aead.experimentalGCM, aead.eax, aead.ocb]);
+ expect(selfSignature.preferredCipherSuites).to.eql([
+ [sym.aes192, aead.experimentalGCM],
+ [sym.aes256, aead.experimentalGCM],
+ [sym.aes128, aead.experimentalGCM],
+ [sym.aes192, aead.gcm],
+ [sym.aes256, aead.gcm],
+ [sym.aes128, aead.gcm],
+ [sym.aes192, aead.eax],
+ [sym.aes256, aead.eax],
+ [sym.aes128, aead.eax],
+ [sym.aes192, aead.ocb],
+ [sym.aes256, aead.ocb],
+ [sym.aes128, aead.ocb]
+ ]);
}
const hash = openpgp.enums.hash;
- expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha224, hash.sha256, hash.sha512]);
+ expect(selfSignature.preferredHashAlgorithms).to.eql([hash.sha224, hash.sha256, hash.sha512]);
const compr = openpgp.enums.compression;
- expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zip, compr.zlib, compr.uncompressed]);
-
- let expectedFeatures;
- if (openpgp.config.v6Keys) {
- expectedFeatures = [7]; // v5 + aead + mdc
- } else if (openpgp.config.aeadProtect) {
- expectedFeatures = [3]; // aead + mdc
- } else {
- expectedFeatures = [1]; // mdc
+ expect(selfSignature.preferredCompressionAlgorithms).to.eql([compr.zlib, compr.uncompressed]);
+
+ let expectedFeatures = 0x01; // SEIPDv1
+ if (openpgp.config.aeadProtect) {
+ expectedFeatures |= 0x08; // SEIPDv2
}
- expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures);
+ expect(selfSignature.features).to.eql([expectedFeatures]);
};
const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' };
try {
From 5391bcc1bcf13d187173e42814eb33a28558604b Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 6 Dec 2022 19:32:27 +0100
Subject: [PATCH 038/224] Update fallback (mandatory) AEAD algorithm to OCB
This has been changed in the crypto refresh.
---
src/key/helper.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/key/helper.js b/src/key/helper.js
index a8bc7cf92..f80b31ddb 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -144,9 +144,9 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us
* @async
*/
export async function getPreferredAlgo(type, keys = [], date = new Date(), userIDs = [], config = defaultConfig) {
- const defaultAlgo = { // these are all must-implement in rfc4880bis
+ const defaultAlgo = { // these are all must-implement in the crypto refresh
'symmetric': enums.symmetric.aes128,
- 'aead': enums.aead.eax,
+ 'aead': enums.aead.ocb,
'compression': enums.compression.uncompressed
}[type];
const preferredSenderAlgo = {
From 6f1eb061197554c7cecce5c0b5a112706e0e3c78 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 6 Dec 2022 14:33:10 +0100
Subject: [PATCH 039/224] For v6 keys, check direct-key signature for key
properties
Key flags, expiration time, algorithm preferences, et cetera, are now
read from the direct-key signature instead of the primary User ID
binding signature for v6 keys.
This also requires a direct-key signature to be present for v6 keys.
---
src/key/helper.js | 16 ++++++------
src/key/key.js | 55 ++++++++++++++++++++++++++++++------------
src/key/private_key.js | 4 +--
src/message.js | 6 ++---
4 files changed, 53 insertions(+), 28 deletions(-)
diff --git a/src/key/helper.js b/src/key/helper.js
index f80b31ddb..55fb5ff28 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -116,9 +116,9 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us
let hashAlgo = config.preferredHashAlgorithm;
let prefAlgo = hashAlgo;
if (key) {
- const primaryUser = await key.getPrimaryUser(date, userID, config);
- if (primaryUser.selfCertification.preferredHashAlgorithms) {
- [prefAlgo] = primaryUser.selfCertification.preferredHashAlgorithms;
+ const selfCertification = await key.getPrimarySelfSignature(date, userID, config);
+ if (selfCertification.preferredHashAlgorithms) {
+ [prefAlgo] = selfCertification.preferredHashAlgorithms;
hashAlgo = crypto.hash.getHashByteLength(hashAlgo) <= crypto.hash.getHashByteLength(prefAlgo) ?
prefAlgo : hashAlgo;
}
@@ -164,8 +164,8 @@ export async function getPreferredAlgo(type, keys = [], date = new Date(), userI
// otherwise we use the default algo
// if no keys are available, preferredSenderAlgo is returned
const senderAlgoSupport = await Promise.all(keys.map(async function(key, i) {
- const primaryUser = await key.getPrimaryUser(date, userIDs[i], config);
- const recipientPrefs = primaryUser.selfCertification[prefPropertyName];
+ const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config);
+ const recipientPrefs = selfCertification[prefPropertyName];
return !!recipientPrefs && recipientPrefs.indexOf(preferredSenderAlgo) >= 0;
}));
return senderAlgoSupport.every(Boolean) ? preferredSenderAlgo : defaultAlgo;
@@ -306,9 +306,9 @@ export async function isAEADSupported(keys, date = new Date(), userIDs = [], con
let supported = true;
// TODO replace when Promise.some or Promise.any are implemented
await Promise.all(keys.map(async function(key, i) {
- const primaryUser = await key.getPrimaryUser(date, userIDs[i], config);
- if (!primaryUser.selfCertification.features ||
- !(primaryUser.selfCertification.features[0] & enums.features.aead)) {
+ const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config);
+ if (!selfCertification.features ||
+ !(selfCertification.features[0] & enums.features.aead)) {
supported = false;
}
}));
diff --git a/src/key/key.js b/src/key/key.js
index 72286b1c1..3b1ed8c2a 100644
--- a/src/key/key.js
+++ b/src/key/key.js
@@ -288,9 +288,9 @@ class Key {
}
try {
- const primaryUser = await this.getPrimaryUser(date, userID, config);
+ const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
- helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, config)) {
+ helper.isValidSigningKeyPacket(primaryKey, selfCertification, config)) {
helper.checkKeyRequirements(primaryKey, config);
return this;
}
@@ -334,9 +334,9 @@ class Key {
try {
// if no valid subkey for encryption, evaluate primary key
- const primaryUser = await this.getPrimaryUser(date, userID, config);
+ const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
- helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
+ helper.isValidEncryptionKeyPacket(primaryKey, selfCertification)) {
helper.checkKeyRequirements(primaryKey, config);
return this;
}
@@ -380,18 +380,20 @@ class Key {
throw new Error('Primary key is revoked');
}
// check for valid, unrevoked, unexpired self signature
- const { selfCertification } = await this.getPrimaryUser(date, userID, config);
+ const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
// check for expiration time in binding signatures
if (helper.isDataExpired(primaryKey, selfCertification, date)) {
throw new Error('Primary key is expired');
}
- // check for expiration time in direct signatures
- const directSignature = await helper.getLatestValidSignature(
- this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config
- ).catch(() => {}); // invalid signatures are discarded, to avoid breaking the key
+ if (primaryKey.version !== 6) {
+ // check for expiration time in direct signatures (for V6 keys, the above already did so)
+ const directSignature = await helper.getLatestValidSignature(
+ this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config
+ ).catch(() => {}); // invalid signatures are discarded, to avoid breaking the key
- if (directSignature && helper.isDataExpired(primaryKey, directSignature, date)) {
- throw new Error('Primary key is expired');
+ if (directSignature && helper.isDataExpired(primaryKey, directSignature, date)) {
+ throw new Error('Primary key is expired');
+ }
}
}
@@ -406,12 +408,13 @@ class Key {
async getExpirationTime(userID, config = defaultConfig) {
let primaryKeyExpiry;
try {
- const { selfCertification } = await this.getPrimaryUser(null, userID, config);
+ const selfCertification = await this.getPrimarySelfSignature(null, userID, config);
const selfSigKeyExpiry = helper.getKeyExpirationTime(this.keyPacket, selfCertification);
const selfSigExpiry = selfCertification.getExpirationTime();
- const directSignature = await helper.getLatestValidSignature(
- this.directSignatures, this.keyPacket, enums.signature.key, { key: this.keyPacket }, null, config
- ).catch(() => {});
+ const directSignature = this.keyPacket.version !== 6 && // For V6 keys, the above already returns the direct-key signature.
+ await helper.getLatestValidSignature(
+ this.directSignatures, this.keyPacket, enums.signature.key, { key: this.keyPacket }, null, config
+ ).catch(() => {});
if (directSignature) {
const directSigKeyExpiry = helper.getKeyExpirationTime(this.keyPacket, directSignature);
// We do not support the edge case where the direct signature expires, since it would invalidate the corresponding key expiration,
@@ -428,6 +431,28 @@ class Key {
}
+ /**
+ * For V4 keys, returns the self-signature of the primary user.
+ * For V5 keys, returns the latest valid direct-key self-signature.
+ * This self-signature is to be used to check the key expiration,
+ * algorithm preferences, and so on.
+ * @param {Date} [date] - Use the given date for verification instead of the current time
+ * @param {Object} [userID] - User ID to get instead of the primary user for V4 keys, if it exists
+ * @param {Object} [config] - Full configuration, defaults to openpgp.config
+ * @returns {Promise} The primary self-signature
+ * @async
+ */
+ async getPrimarySelfSignature(date = new Date(), userID = {}, config = defaultConfig) {
+ const primaryKey = this.keyPacket;
+ if (primaryKey.version === 6) {
+ return helper.getLatestValidSignature(
+ this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config
+ );
+ }
+ const { selfCertification } = await this.getPrimaryUser(date, userID, config);
+ return selfCertification;
+ }
+
/**
* Returns primary user and most significant (latest valid) self signature
* - if multiple primary users exist, returns the one with the latest self signature
diff --git a/src/key/private_key.js b/src/key/private_key.js
index 384a94ec6..055de0085 100644
--- a/src/key/private_key.js
+++ b/src/key/private_key.js
@@ -93,9 +93,9 @@ class PrivateKey extends PublicKey {
}
// evaluate primary key
- const primaryUser = await this.getPrimaryUser(date, userID, config);
+ const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID, true)) &&
- helper.isValidDecryptionKeyPacket(primaryUser.selfCertification, config)) {
+ helper.isValidDecryptionKeyPacket(selfCertification, config)) {
keys.push(this);
}
diff --git a/src/message.js b/src/message.js
index 5a88e7b08..611dfbc8c 100644
--- a/src/message.js
+++ b/src/message.js
@@ -204,9 +204,9 @@ export class Message {
enums.symmetric.cast5 // Golang OpenPGP fallback
];
try {
- const primaryUser = await decryptionKey.getPrimaryUser(date, undefined, config); // TODO: Pass userID from somewhere.
- if (primaryUser.selfCertification.preferredSymmetricAlgorithms) {
- algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms);
+ const selfCertification = await decryptionKey.getPrimarySelfSignature(date, undefined, config); // TODO: Pass userID from somewhere.
+ if (selfCertification.preferredSymmetricAlgorithms) {
+ algos = algos.concat(selfCertification.preferredSymmetricAlgorithms);
}
} catch (e) {}
From 939622e82797dee9f71efd955778f0fdc08d0b5b Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 13 Dec 2022 15:04:07 +0100
Subject: [PATCH 040/224] Remove armor checksum check
The crypto refresh says that we MUST NOT reject messages where the
CRC24 checksum is incorrect. So, we remove the check for it.
Also, remove the checksumRequired config.
---
openpgp.d.ts | 1 -
src/config/config.js | 5 ---
src/encoding/armor.js | 91 ---------------------------------------
test/general/armor.js | 54 ++---------------------
test/general/openpgp.js | 85 ++++++++++++++++--------------------
test/general/streaming.js | 49 +++------------------
6 files changed, 47 insertions(+), 238 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index 049c0d539..19a681a19 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -317,7 +317,6 @@ interface Config {
aeadProtect: boolean;
allowUnauthenticatedMessages: boolean;
allowUnauthenticatedStream: boolean;
- checksumRequired: boolean;
minRSABits: number;
passwordCollisionCheck: boolean;
revocationsExpire: boolean;
diff --git a/src/config/config.js b/src/config/config.js
index 4b273c914..2b8c35f1c 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -130,11 +130,6 @@ export default {
* @property {Boolean} allowUnauthenticatedStream
*/
allowUnauthenticatedStream: false,
- /**
- * @memberof module:config
- * @property {Boolean} checksumRequired Do not throw error when armor is missing a checksum
- */
- checksumRequired: false,
/**
* Minimum RSA key size allowed for key generation and message signing, verification and encryption.
* The default is 2047 since due to a bug, previous versions of OpenPGP.js could generate 2047-bit keys instead of 2048-bit ones.
diff --git a/src/encoding/armor.js b/src/encoding/armor.js
index 6011b94cb..daff2d4d9 100644
--- a/src/encoding/armor.js
+++ b/src/encoding/armor.js
@@ -108,79 +108,6 @@ function addheader(customComment, config) {
}
-/**
- * Calculates a checksum over the given data and returns it base64 encoded
- * @param {String | ReadableStream} data - Data to create a CRC-24 checksum for
- * @returns {String | ReadableStream} Base64 encoded checksum.
- * @private
- */
-function getCheckSum(data) {
- const crc = createcrc24(data);
- return base64.encode(crc);
-}
-
-// https://create.stephan-brumme.com/crc32/#slicing-by-8-overview
-
-const crc_table = [
- new Array(0xFF),
- new Array(0xFF),
- new Array(0xFF),
- new Array(0xFF)
-];
-
-for (let i = 0; i <= 0xFF; i++) {
- let crc = i << 16;
- for (let j = 0; j < 8; j++) {
- crc = (crc << 1) ^ ((crc & 0x800000) !== 0 ? 0x864CFB : 0);
- }
- crc_table[0][i] =
- ((crc & 0xFF0000) >> 16) |
- (crc & 0x00FF00) |
- ((crc & 0x0000FF) << 16);
-}
-for (let i = 0; i <= 0xFF; i++) {
- crc_table[1][i] = (crc_table[0][i] >> 8) ^ crc_table[0][crc_table[0][i] & 0xFF];
-}
-for (let i = 0; i <= 0xFF; i++) {
- crc_table[2][i] = (crc_table[1][i] >> 8) ^ crc_table[0][crc_table[1][i] & 0xFF];
-}
-for (let i = 0; i <= 0xFF; i++) {
- crc_table[3][i] = (crc_table[2][i] >> 8) ^ crc_table[0][crc_table[2][i] & 0xFF];
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
-const isLittleEndian = (function() {
- const buffer = new ArrayBuffer(2);
- new DataView(buffer).setInt16(0, 0xFF, true /* littleEndian */);
- // Int16Array uses the platform's endianness.
- return new Int16Array(buffer)[0] === 0xFF;
-}());
-
-/**
- * Internal function to calculate a CRC-24 checksum over a given string (data)
- * @param {String | ReadableStream} input - Data to create a CRC-24 checksum for
- * @returns {Uint8Array | ReadableStream} The CRC-24 checksum.
- * @private
- */
-function createcrc24(input) {
- let crc = 0xCE04B7;
- return stream.transform(input, value => {
- const len32 = isLittleEndian ? Math.floor(value.length / 4) : 0;
- const arr32 = new Uint32Array(value.buffer, value.byteOffset, len32);
- for (let i = 0; i < len32; i++) {
- crc ^= arr32[i];
- crc =
- crc_table[0][(crc >> 24) & 0xFF] ^
- crc_table[1][(crc >> 16) & 0xFF] ^
- crc_table[2][(crc >> 8) & 0xFF] ^
- crc_table[3][(crc >> 0) & 0xFF];
- }
- for (let i = len32 * 4; i < value.length; i++) {
- crc = (crc >> 8) ^ crc_table[0][(crc & 0xFF) ^ value[i]];
- }
- }, () => new Uint8Array([crc, crc >> 8, crc >> 16]));
-}
-
/**
* Verify armored headers. crypto-refresh-06, section 6.2:
* "An OpenPGP implementation may consider improperly formatted Armor
@@ -321,24 +248,6 @@ export function unarmor(input, config = defaultConfig) {
await writer.abort(e);
}
}));
- data = stream.transformPair(data, async (readable, writable) => {
- const checksumVerified = stream.readToEnd(getCheckSum(stream.passiveClone(readable)));
- checksumVerified.catch(() => {});
- await stream.pipe(readable, writable, {
- preventClose: true
- });
- const writer = stream.getWriter(writable);
- try {
- const checksumVerifiedString = (await checksumVerified).replace('\n', '');
- if (checksum !== checksumVerifiedString && (checksum || config.checksumRequired)) {
- throw new Error('Ascii armor integrity check failed');
- }
- await writer.ready;
- await writer.close();
- } catch (e) {
- await writer.abort(e);
- }
- });
} catch (e) {
reject(e);
}
diff --git a/test/general/armor.js b/test/general/armor.js
index 7f7c788b6..2c620d350 100644
--- a/test/general/armor.js
+++ b/test/general/armor.js
@@ -171,15 +171,7 @@ export default () => describe('ASCII armor', function() {
'-----END PGP PRIVATE KEY BLOCK-----'
].join('\n');
- // try with default config
- await expect(openpgp.readKey({ armoredKey: privKey })).to.be.rejectedWith(/Ascii armor integrity check failed/);
-
- // try opposite config
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
- await expect(openpgp.readKey({ armoredKey: privKey })).to.be.rejectedWith(/Ascii armor integrity check failed/);
-
- // back to default
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
+ await openpgp.readKey({ armoredKey: privKey });
});
it('Armor checksum validation - valid', async function () {
@@ -203,15 +195,7 @@ export default () => describe('ASCII armor', function() {
'=wJNM',
'-----END PGP PRIVATE KEY BLOCK-----'].join('\n');
- // try with default config
await openpgp.readKey({ armoredKey: privKey });
-
- // try opposite config
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
- await openpgp.readKey({ armoredKey: privKey });
-
- // back to default
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
});
it('Armor checksum validation - missing', async function () {
@@ -234,23 +218,7 @@ export default () => describe('ASCII armor', function() {
'71vlXMJNXvoCeuejiRw=',
'-----END PGP PRIVATE KEY BLOCK-----'].join('\n');
- // try with default config
- if (openpgp.config.checksumRequired) {
- await expect(openpgp.readKey({ armoredKey: privKeyNoCheckSum })).to.be.rejectedWith(/Ascii armor integrity check failed/);
- } else {
- await openpgp.readKey({ armoredKey: privKeyNoCheckSum });
- }
-
- // try opposite config
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
- if (openpgp.config.checksumRequired) {
- await expect(openpgp.readKey({ armoredKey: privKeyNoCheckSum })).to.be.rejectedWith(/Ascii armor integrity check failed/);
- } else {
- await openpgp.readKey({ armoredKey: privKeyNoCheckSum });
- }
-
- // back to default
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
+ await openpgp.readKey({ armoredKey: privKeyNoCheckSum });
});
it('Armor checksum validation - missing - trailing newline', async function () {
@@ -274,23 +242,7 @@ export default () => describe('ASCII armor', function() {
'-----END PGP PRIVATE KEY BLOCK-----',
''].join('\n');
- // try with default config
- if (openpgp.config.checksumRequired) {
- await expect(openpgp.readKey({ armoredKey: privKeyNoCheckSumWithTrailingNewline })).to.be.rejectedWith(/Ascii armor integrity check failed/);
- } else {
- await openpgp.readKey({ armoredKey: privKeyNoCheckSumWithTrailingNewline });
- }
-
- // try opposite config
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
- if (openpgp.config.checksumRequired) {
- await expect(openpgp.readKey({ armoredKey: privKeyNoCheckSumWithTrailingNewline })).to.be.rejectedWith(/Ascii armor integrity check failed/);
- } else {
- await openpgp.readKey({ armoredKey: privKeyNoCheckSumWithTrailingNewline });
- }
-
- // back to default
- openpgp.config.checksumRequired = !openpgp.config.checksumRequired;
+ await openpgp.readKey({ armoredKey: privKeyNoCheckSumWithTrailingNewline });
});
it('Accept header with trailing whitespace', async function () {
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 20a8e1ac3..15c5f9d8f 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -3057,60 +3057,51 @@ XfA3pqV4mTzF
expect(await isAEADSupported([key])).to.equal(openpgp.config.aeadProtect);
const data = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: new Uint8Array(500) }), encryptionKeys: [key.toPublic()] });
- let badSumEncrypted = data.replace(/\n=[a-zA-Z0-9/+]{4}/, '\n=aaaa');
- if (badSumEncrypted === data) { // checksum was already =aaaa
- badSumEncrypted = data.replace(/\n=[a-zA-Z0-9/+]{4}/, '\n=bbbb');
- }
- if (badSumEncrypted === data) {
- throw new Error('Was not able to successfully modify checksum');
- }
- const badBodyEncrypted = data.replace(/\n=([a-zA-Z0-9/+]{4})/, 'aaa\n=$1');
+ const encrypted = data.substr(0, 500) + (data[500] === 'a' ? 'b' : 'a') + data.substr(501);
await loadStreamsPolyfill();
try {
for (const allowStreaming of [true, false]) {
openpgp.config.allowUnauthenticatedStream = allowStreaming;
- await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => {
- await Promise.all([
- encrypted,
- new ReadableStream({
- start(controller) {
- controller.enqueue(encrypted);
+ for (const [i, encryptedData] of [
+ encrypted,
+ new ReadableStream({
+ start(controller) {
+ controller.enqueue(encrypted);
+ controller.close();
+ }
+ }),
+ new ReadableStream({
+ start() {
+ this.remaining = encrypted.split('\n');
+ },
+ async pull(controller) {
+ if (this.remaining.length) {
+ await new Promise(res => setTimeout(res));
+ controller.enqueue(this.remaining.shift() + '\n');
+ } else {
controller.close();
}
- }),
- new ReadableStream({
- start() {
- this.remaining = encrypted.split('\n');
- },
- async pull(controller) {
- if (this.remaining.length) {
- await new Promise(res => { setTimeout(res); });
- controller.enqueue(this.remaining.shift() + '\n');
- } else {
- controller.close();
- }
- }
- })
- ].map(async (encrypted, j) => {
- let stepReached = 0;
- try {
- const message = await openpgp.readMessage({ armoredMessage: encrypted });
- stepReached = 1;
- const { data: decrypted } = await openpgp.decrypt({ message: message, decryptionKeys: [key] });
- stepReached = 2;
- await stream.readToEnd(decrypted);
- } catch (e) {
- expect(e.message).to.match(/Ascii armor integrity check failed/);
- expect(stepReached).to.equal(
- j === 0 ? 0 :
- (openpgp.config.aeadChunkSizeByte === 0 && (j === 2 || detectNode() || util.getHardwareConcurrency() < 8)) || (!openpgp.config.aeadProtect && openpgp.config.allowUnauthenticatedStream) ? 2 :
- 1
- );
- return;
}
- throw new Error(`Expected "Ascii armor integrity check failed" error in subtest ${i}.${j}`);
- }));
- }));
+ })
+ ].entries()) {
+ let stepReached = 0;
+ try {
+ const message = await openpgp.readMessage({ armoredMessage: encryptedData });
+ stepReached = 1;
+ const { data: decrypted } = await openpgp.decrypt({ message: message, decryptionKeys: [key] });
+ stepReached = 2;
+ await stream.readToEnd(decrypted);
+ } catch (e) {
+ expect(e.message).to.match(/Modification detected|Authentication tag mismatch|Unsupported state or unable to authenticate data/);
+ expect(stepReached).to.equal(
+ i === 0 ? 1 :
+ (openpgp.config.aeadChunkSizeByte === 0 && (i === 2 || detectNode() || util.getHardwareConcurrency() < 8)) || (!openpgp.config.aeadProtect && openpgp.config.allowUnauthenticatedStream) ? 2 :
+ 1
+ );
+ continue;
+ }
+ throw new Error(`Expected "Modification detected" error in subtest ${i}`);
+ }
}
} finally {
openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStream;
diff --git a/test/general/streaming.js b/test/general/streaming.js
index e60a9f169..3489656aa 100644
--- a/test/general/streaming.js
+++ b/test/general/streaming.js
@@ -403,7 +403,7 @@ function tests() {
}
});
- it('Detect MDC modifications (allowUnauthenticatedStream=true)', async function() {
+ it('Detect modification (allowUnauthenticatedStream=true)', async function() {
const aeadProtectValue = openpgp.config.aeadProtect;
openpgp.config.aeadProtect = false;
const allowUnauthenticatedStreamValue = openpgp.config.allowUnauthenticatedStream;
@@ -418,7 +418,6 @@ function tests() {
const message = await openpgp.readMessage({
armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => {
value += '';
- if (value === '=' || value.length === 5) return; // Remove checksum
const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
return value;
@@ -441,44 +440,7 @@ function tests() {
}
});
- it('Detect armor checksum error (allowUnauthenticatedStream=true)', async function() {
- const allowUnauthenticatedStreamValue = openpgp.config.allowUnauthenticatedStream;
- openpgp.config.allowUnauthenticatedStream = true;
- try {
- const encrypted = await openpgp.encrypt({
- message: await openpgp.createMessage({ binary: data }),
- encryptionKeys: pubKey,
- signingKeys: privKey,
- config: { minRSABits: 1024 }
- });
- expect(stream.isStream(encrypted)).to.equal(expectedType);
-
- const message = await openpgp.readMessage({
- armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => {
- value += '';
- const newlineIndex = value.indexOf('\n', 500);
- if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
- return value;
- }), { encoding: 'utf8' })
- });
- const decrypted = await openpgp.decrypt({
- verificationKeys: pubKey,
- decryptionKeys: privKey,
- message,
- format: 'binary'
- });
- expect(stream.isStream(decrypted.data)).to.equal(expectedType);
- const reader = stream.getReader(decrypted.data);
- expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]);
- dataArrived();
- await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check failed');
- expect(decrypted.signatures).to.exist.and.have.length(1);
- } finally {
- openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStreamValue;
- }
- });
-
- it('Detect armor checksum error when not passing public keys (allowUnauthenticatedStream=true)', async function() {
+ it('Detect modification when not passing public keys (allowUnauthenticatedStream=true)', async function() {
const allowUnauthenticatedStreamValue = openpgp.config.allowUnauthenticatedStream;
openpgp.config.allowUnauthenticatedStream = true;
try {
@@ -507,7 +469,7 @@ function tests() {
const reader = stream.getReader(decrypted.data);
expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]);
dataArrived();
- await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check failed');
+ await expect(reader.readToEnd()).to.be.rejectedWith('Modification detected.');
expect(decrypted.signatures).to.exist.and.have.length(1);
await expect(decrypted.signatures[0].verified).to.be.eventually.rejectedWith(/Could not find signing key/);
} finally {
@@ -515,7 +477,7 @@ function tests() {
}
});
- it('Sign/verify: Detect armor checksum error', async function() {
+ it('Sign/verify: Detect modification', async function() {
const signed = await openpgp.sign({
message: await openpgp.createMessage({ binary: data }),
signingKeys: privKey,
@@ -541,8 +503,9 @@ function tests() {
const reader = stream.getReader(verified.data);
expect(await reader.peekBytes(1024)).not.to.deep.equal(plaintext[0]);
dataArrived();
- await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check failed');
expect(verified.signatures).to.exist.and.have.length(1);
+ await reader.readToEnd();
+ await expect(verified.signatures[0].verified).to.be.rejectedWith('Signed digest did not match');
});
it('stream.transformPair()', async function() {
From 9d85938ed716bf11acba8ad94ecbc9e339b6f0ec Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Tue, 13 Dec 2022 17:30:29 +0100
Subject: [PATCH 041/224] Implement SEIPD v2
---
src/crypto/hkdf.js | 2 +-
src/key/helper.js | 2 +-
src/message.js | 7 +-
src/packet/aead_encrypted_data.js | 84 +------
.../sym_encrypted_integrity_protected_data.js | 224 +++++++++++++++---
test/benchmarks/memory_usage.js | 21 +-
test/general/config.js | 4 +-
test/general/openpgp.js | 38 +--
test/general/packet.js | 8 +-
9 files changed, 239 insertions(+), 151 deletions(-)
diff --git a/src/crypto/hkdf.js b/src/crypto/hkdf.js
index c08720b11..91ff9a2e3 100644
--- a/src/crypto/hkdf.js
+++ b/src/crypto/hkdf.js
@@ -9,7 +9,7 @@ import util from '../util';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
-export default async function HKDF(hashAlgo, inputKey, salt, info, outLen) {
+export default async function computeHKDF(hashAlgo, inputKey, salt, info, outLen) {
const hash = enums.read(enums.webHash, hashAlgo);
if (!hash) throw new Error('Hash algo not supported with HKDF');
diff --git a/src/key/helper.js b/src/key/helper.js
index 55fb5ff28..766f41c92 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -308,7 +308,7 @@ export async function isAEADSupported(keys, date = new Date(), userIDs = [], con
await Promise.all(keys.map(async function(key, i) {
const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config);
if (!selfCertification.features ||
- !(selfCertification.features[0] & enums.features.aead)) {
+ !(selfCertification.features[0] & enums.features.seipdv2)) {
supported = false;
}
}));
diff --git a/src/message.js b/src/message.js
index 611dfbc8c..a17f523c2 100644
--- a/src/message.js
+++ b/src/message.js
@@ -392,13 +392,12 @@ export class Message {
const msg = await Message.encryptSessionKey(sessionKeyData, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, userIDs, config);
- let symEncryptedPacket;
+ const symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
if (aeadAlgorithmName) {
- symEncryptedPacket = new AEADEncryptedDataPacket();
+ symEncryptedPacket.version = 2;
symEncryptedPacket.aeadAlgorithm = enums.write(enums.aead, aeadAlgorithmName);
- } else {
- symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
}
+
symEncryptedPacket.packets = this.packets;
const algorithm = enums.write(enums.symmetric, algorithmName);
diff --git a/src/packet/aead_encrypted_data.js b/src/packet/aead_encrypted_data.js
index 5f42a8fbb..60bdc3a77 100644
--- a/src/packet/aead_encrypted_data.js
+++ b/src/packet/aead_encrypted_data.js
@@ -21,6 +21,7 @@ import enums from '../enums';
import util from '../util';
import defaultConfig from '../config';
import { UnsupportedError } from './packet';
+import { runAEAD } from './sym_encrypted_integrity_protected_data';
import LiteralDataPacket from './literal_data';
import CompressedDataPacket from './compressed_data';
@@ -101,7 +102,7 @@ class AEADEncryptedDataPacket {
*/
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
this.packets = await PacketList.fromBinary(
- await this.crypt('decrypt', key, stream.clone(this.encrypted)),
+ await runAEAD(this, 'decrypt', key, stream.clone(this.encrypted)),
allowedPackets,
config
);
@@ -122,86 +123,7 @@ class AEADEncryptedDataPacket {
this.iv = crypto.random.getRandomBytes(ivLength); // generate new random IV
this.chunkSizeByte = config.aeadChunkSizeByte;
const data = this.packets.write();
- this.encrypted = await this.crypt('encrypt', key, data);
- }
-
- /**
- * En/decrypt the payload.
- * @param {encrypt|decrypt} fn - Whether to encrypt or decrypt
- * @param {Uint8Array} key - The session key used to en/decrypt the payload
- * @param {Uint8Array | ReadableStream} data - The data to en/decrypt
- * @returns {Promise>}
- * @async
- */
- async crypt(fn, key, data) {
- const mode = crypto.getAEADMode(this.aeadAlgorithm);
- const modeInstance = await mode(this.cipherAlgorithm, key);
- const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
- const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
- const chunkSize = 2 ** (this.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
- const adataBuffer = new ArrayBuffer(21);
- const adataArray = new Uint8Array(adataBuffer, 0, 13);
- const adataTagArray = new Uint8Array(adataBuffer);
- const adataView = new DataView(adataBuffer);
- const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8);
- adataArray.set([0xC0 | AEADEncryptedDataPacket.tag, this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte], 0);
- let chunkIndex = 0;
- let latestPromise = Promise.resolve();
- let cryptedBytes = 0;
- let queuedBytes = 0;
- const iv = this.iv;
- return stream.transformPair(data, async (readable, writable) => {
- if (util.isStream(readable) !== 'array') {
- const buffer = new TransformStream({}, {
- highWaterMark: util.getHardwareConcurrency() * 2 ** (this.chunkSizeByte + 6),
- size: array => array.length
- });
- stream.pipe(buffer.readable, writable);
- writable = buffer.writable;
- }
- const reader = stream.getReader(readable);
- const writer = stream.getWriter(writable);
- try {
- while (true) {
- let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
- const finalChunk = chunk.subarray(chunk.length - tagLengthIfDecrypting);
- chunk = chunk.subarray(0, chunk.length - tagLengthIfDecrypting);
- let cryptedPromise;
- let done;
- if (!chunkIndex || chunk.length) {
- reader.unshift(finalChunk);
- cryptedPromise = modeInstance[fn](chunk, mode.getNonce(iv, chunkIndexArray), adataArray);
- queuedBytes += chunk.length - tagLengthIfDecrypting + tagLengthIfEncrypting;
- } else {
- // After the last chunk, we either encrypt a final, empty
- // data chunk to get the final authentication tag or
- // validate that final authentication tag.
- adataView.setInt32(13 + 4, cryptedBytes); // Should be setInt64(13, ...)
- cryptedPromise = modeInstance[fn](finalChunk, mode.getNonce(iv, chunkIndexArray), adataTagArray);
- queuedBytes += tagLengthIfEncrypting;
- done = true;
- }
- cryptedBytes += chunk.length - tagLengthIfDecrypting;
- // eslint-disable-next-line no-loop-func
- latestPromise = latestPromise.then(() => cryptedPromise).then(async crypted => {
- await writer.ready;
- await writer.write(crypted);
- queuedBytes -= crypted.length;
- }).catch(err => writer.abort(err));
- if (done || queuedBytes > writer.desiredSize) {
- await latestPromise; // Respect backpressure
- }
- if (!done) {
- adataView.setInt32(5 + 4, ++chunkIndex); // Should be setInt64(5, ...)
- } else {
- await writer.close();
- break;
- }
- }
- } catch (e) {
- await writer.abort(e);
- }
- });
+ this.encrypted = await runAEAD(this, 'encrypt', key, data);
}
}
diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js
index d1099a9f6..3f462c905 100644
--- a/src/packet/sym_encrypted_integrity_protected_data.js
+++ b/src/packet/sym_encrypted_integrity_protected_data.js
@@ -17,6 +17,7 @@
import * as stream from '@openpgp/web-stream-tools';
import crypto from '../crypto';
+import computeHKDF from '../crypto/hkdf';
import enums from '../enums';
import util from '../util';
import defaultConfig from '../config';
@@ -36,8 +37,6 @@ const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([
SignaturePacket
]);
-const VERSION = 1; // A one-octet version number of the data packet.
-
/**
* Implementation of the Sym. Encrypted Integrity Protected Data Packet (Tag 18)
*
@@ -54,28 +53,55 @@ class SymEncryptedIntegrityProtectedDataPacket {
}
constructor() {
- this.version = VERSION;
+ this.version = 1;
+
+ // The following 4 fields are for V2 only.
+ /** @type {enums.symmetric} */
+ this.cipherAlgorithm = null;
+ /** @type {enums.aead} */
+ this.aeadAlgorithm = null;
+ this.chunkSizeByte = null;
+ this.salt = null;
+
this.encrypted = null;
this.packets = null;
}
async read(bytes) {
await stream.parse(bytes, async reader => {
- const version = await reader.readByte();
- // - A one-octet version number. The only currently defined value is 1.
- if (version !== VERSION) {
+ this.version = await reader.readByte();
+ // - A one-octet version number with value 1 or 2.
+ if (this.version !== 1 && this.version !== 2) {
throw new UnsupportedError(`Version ${version} of the SEIP packet is unsupported.`);
}
+ if (this.version === 2) {
+ // - A one-octet cipher algorithm.
+ this.cipherAlgorithm = await reader.readByte();
+ // - A one-octet AEAD algorithm.
+ this.aeadAlgorithm = await reader.readByte();
+ // - A one-octet chunk size.
+ this.chunkSizeByte = await reader.readByte();
+ // - Thirty-two octets of salt. The salt is used to derive the message key and must be unique.
+ this.salt = await reader.readBytes(32);
+ }
+
+ // For V1:
// - Encrypted data, the output of the selected symmetric-key cipher
// operating in Cipher Feedback mode with shift amount equal to the
// block size of the cipher (CFB-n where n is the block size).
+ // For V2:
+ // - Encrypted data, the output of the selected symmetric-key cipher operating in the given AEAD mode.
+ // - A final, summary authentication tag for the AEAD mode.
this.encrypted = reader.remainder();
});
}
write() {
- return util.concat([new Uint8Array([VERSION]), this.encrypted]);
+ if (this.version === 2) {
+ return util.concat([new Uint8Array([this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte]), this.salt, this.encrypted]);
+ }
+ return util.concat([new Uint8Array([this.version]), this.encrypted]);
}
/**
@@ -88,18 +114,27 @@ class SymEncryptedIntegrityProtectedDataPacket {
* @async
*/
async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
- const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
-
let bytes = this.packets.write();
if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes);
- const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
- const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
- const tohash = util.concat([prefix, bytes, mdc]);
- const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
- const plaintext = util.concat([tohash, hash]);
+ if (this.version === 2) {
+ this.cipherAlgorithm = sessionKeyAlgorithm;
+
+ this.salt = crypto.random.getRandomBytes(32);
+ this.chunkSizeByte = config.aeadChunkSizeByte;
+ this.encrypted = await runAEAD(this, 'encrypt', key, bytes);
+ } else {
+ const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
+
+ const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm);
+ const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
- this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
+ const tohash = util.concat([prefix, bytes, mdc]);
+ const hash = await crypto.hash.sha1(stream.passiveClone(tohash));
+ const plaintext = util.concat([tohash, hash]);
+
+ this.encrypted = await crypto.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config);
+ }
return true;
}
@@ -113,33 +148,152 @@ class SymEncryptedIntegrityProtectedDataPacket {
* @async
*/
async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) {
- const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
let encrypted = stream.clone(this.encrypted);
if (stream.isArrayStream(encrypted)) encrypted = await stream.readToEnd(encrypted);
- const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
-
- // there must be a modification detection code packet as the
- // last packet and everything gets hashed except the hash itself
- const realHash = stream.slice(stream.passiveClone(decrypted), -20);
- const tohash = stream.slice(decrypted, 0, -20);
- const verifyHash = Promise.all([
- stream.readToEnd(await crypto.hash.sha1(stream.passiveClone(tohash))),
- stream.readToEnd(realHash)
- ]).then(([hash, mdc]) => {
- if (!util.equalsUint8Array(hash, mdc)) {
- throw new Error('Modification detected.');
+
+ let packetbytes;
+ if (this.version === 2) {
+ packetbytes = await runAEAD(this, 'decrypt', key, encrypted);
+ } else {
+ const { blockSize } = crypto.getCipher(sessionKeyAlgorithm);
+ const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
+
+ // there must be a modification detection code packet as the
+ // last packet and everything gets hashed except the hash itself
+ const realHash = stream.slice(stream.passiveClone(decrypted), -20);
+ const tohash = stream.slice(decrypted, 0, -20);
+ const verifyHash = Promise.all([
+ stream.readToEnd(await crypto.hash.sha1(stream.passiveClone(tohash))),
+ stream.readToEnd(realHash)
+ ]).then(([hash, mdc]) => {
+ if (!util.equalsUint8Array(hash, mdc)) {
+ throw new Error('Modification detected.');
+ }
+ return new Uint8Array();
+ });
+ const bytes = stream.slice(tohash, blockSize + 2); // Remove random prefix
+ packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet
+ packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]);
+ if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {
+ packetbytes = await stream.readToEnd(packetbytes);
}
- return new Uint8Array();
- });
- const bytes = stream.slice(tohash, blockSize + 2); // Remove random prefix
- let packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet
- packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]);
- if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) {
- packetbytes = await stream.readToEnd(packetbytes);
}
+
this.packets = await PacketList.fromBinary(packetbytes, allowedPackets, config);
return true;
}
}
export default SymEncryptedIntegrityProtectedDataPacket;
+
+/**
+ * En/decrypt the payload.
+ * @param {encrypt|decrypt} fn - Whether to encrypt or decrypt
+ * @param {Uint8Array} key - The session key used to en/decrypt the payload
+ * @param {Uint8Array | ReadableStream} data - The data to en/decrypt
+ * @returns {Promise>}
+ * @async
+ */
+export async function runAEAD(packet, fn, key, data) {
+ const isSEIPDv2 = packet instanceof SymEncryptedIntegrityProtectedDataPacket && packet.version === 2;
+ const isAEADP = !isSEIPDv2 && packet.constructor.tag === enums.packet.aeadEncryptedData; // no `instanceof` to avoid importing the corresponding class (circular import)
+ if (!isSEIPDv2 && !isAEADP) throw new Error('Unexpected packet type');
+
+ const mode = crypto.getAEADMode(packet.aeadAlgorithm);
+ const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
+ const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
+ const chunkSize = 2 ** (packet.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
+ const chunkIndexSizeIfAEADEP = isAEADP ? 8 : 0;
+ const adataBuffer = new ArrayBuffer(13 + chunkIndexSizeIfAEADEP);
+ const adataArray = new Uint8Array(adataBuffer, 0, 5 + chunkIndexSizeIfAEADEP);
+ const adataTagArray = new Uint8Array(adataBuffer);
+ const adataView = new DataView(adataBuffer);
+ const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8);
+ adataArray.set([0xC0 | packet.constructor.tag, packet.version, packet.cipherAlgorithm, packet.aeadAlgorithm, packet.chunkSizeByte], 0);
+ let chunkIndex = 0;
+ let latestPromise = Promise.resolve();
+ let cryptedBytes = 0;
+ let queuedBytes = 0;
+ let iv;
+ let ivView;
+ if (isSEIPDv2) {
+ const { keySize } = crypto.getCipher(packet.cipherAlgorithm);
+ const { ivLength } = mode;
+ const info = new Uint8Array(adataBuffer, 0, 5);
+ const derived = await computeHKDF(enums.hash.sha256, key, packet.salt, info, keySize + ivLength);
+ key = derived.subarray(0, keySize);
+ iv = derived.subarray(keySize); // The last 8 bytes of HKDF output are unneeded, but this avoids one copy.
+ iv.fill(0, iv.length - 8);
+ ivView = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);
+ } else { // AEADEncryptedDataPacket
+ iv = packet.iv;
+ // ivView is unused in this case
+ }
+ const modeInstance = await mode(packet.cipherAlgorithm, key);
+ return stream.transformPair(data, async (readable, writable) => {
+ if (util.isStream(readable) !== 'array') {
+ const buffer = new TransformStream({}, {
+ highWaterMark: util.getHardwareConcurrency() * 2 ** (packet.chunkSizeByte + 6),
+ size: array => array.length
+ });
+ stream.pipe(buffer.readable, writable);
+ writable = buffer.writable;
+ }
+ const reader = stream.getReader(readable);
+ const writer = stream.getWriter(writable);
+ try {
+ while (true) {
+ let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
+ const finalChunk = chunk.subarray(chunk.length - tagLengthIfDecrypting);
+ chunk = chunk.subarray(0, chunk.length - tagLengthIfDecrypting);
+ let cryptedPromise;
+ let done;
+ let nonce;
+ if (isSEIPDv2) { // SEIPD V2
+ nonce = iv;
+ } else { // AEADEncryptedDataPacket
+ nonce = iv.slice();
+ for (let i = 0; i < 8; i++) {
+ nonce[iv.length - 8 + i] ^= chunkIndexArray[i];
+ }
+ }
+ if (!chunkIndex || chunk.length) {
+ reader.unshift(finalChunk);
+ cryptedPromise = modeInstance[fn](chunk, nonce, adataArray);
+ queuedBytes += chunk.length - tagLengthIfDecrypting + tagLengthIfEncrypting;
+ } else {
+ // After the last chunk, we either encrypt a final, empty
+ // data chunk to get the final authentication tag or
+ // validate that final authentication tag.
+ adataView.setInt32(5 + chunkIndexSizeIfAEADEP + 4, cryptedBytes); // Should be setInt64(5 + chunkIndexSizeIfAEADEP, ...)
+ cryptedPromise = modeInstance[fn](finalChunk, nonce, adataTagArray);
+ queuedBytes += tagLengthIfEncrypting;
+ done = true;
+ }
+ cryptedBytes += chunk.length - tagLengthIfDecrypting;
+ // eslint-disable-next-line no-loop-func
+ latestPromise = latestPromise.then(() => cryptedPromise).then(async crypted => {
+ await writer.ready;
+ await writer.write(crypted);
+ queuedBytes -= crypted.length;
+ }).catch(err => writer.abort(err));
+ if (done || queuedBytes > writer.desiredSize) {
+ await latestPromise; // Respect backpressure
+ }
+ if (!done) {
+ if (isSEIPDv2) { // SEIPD V2
+ ivView.setInt32(iv.length - 4, ++chunkIndex); // Should be setInt64(iv.length - 8, ...)
+ } else { // AEADEncryptedDataPacket
+ adataView.setInt32(5 + 4, ++chunkIndex); // Should be setInt64(5, ...)
+ }
+ } else {
+ await writer.close();
+ break;
+ }
+ }
+ } catch (e) {
+ await writer.ready.catch(() => {});
+ await writer.abort(e);
+ }
+ });
+}
diff --git a/test/benchmarks/memory_usage.js b/test/benchmarks/memory_usage.js
index e50873e4f..323ae4755 100644
--- a/test/benchmarks/memory_usage.js
+++ b/test/benchmarks/memory_usage.js
@@ -119,6 +119,7 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 1);
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
});
@@ -131,6 +132,7 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 1);
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
});
@@ -142,7 +144,8 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
- assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
+ assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 2);
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
});
@@ -154,7 +157,8 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
- assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
+ assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 2);
await openpgp.decrypt({ message: encryptedMessage, passwords, config });
});
@@ -176,6 +180,7 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 1);
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
// read out output stream to trigger decryption
await new Promise(resolve => {
@@ -201,6 +206,7 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 1);
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
// read out output stream to trigger decryption
await new Promise(resolve => {
@@ -225,7 +231,8 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
- assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
+ assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 2);
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
// read out output stream to trigger decryption
await new Promise(resolve => {
@@ -250,7 +257,8 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
- assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
+ assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 2);
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
// read out output stream to trigger decryption
await new Promise(resolve => {
@@ -276,6 +284,7 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 1);
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
// read out output stream to trigger decryption
await new Promise(resolve => {
@@ -301,6 +310,7 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 1);
const { data: decryptedData } = await openpgp.decrypt({
message: encryptedMessage,
passwords,
@@ -329,7 +339,8 @@ class MemoryBenchamrkSuite {
const armoredEncryptedMessage = await openpgp.encrypt({ message: plaintextMessage, passwords, config });
const encryptedMessage = await openpgp.readMessage({ armoredMessage: armoredEncryptedMessage });
- assert.ok(encryptedMessage.packets[1] instanceof openpgp.AEADEncryptedDataPacket);
+ assert.ok(encryptedMessage.packets[1] instanceof openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ assert.ok(encryptedMessage.packets[1].version === 2);
const { data: decryptedData } = await openpgp.decrypt({ message: encryptedMessage, passwords, config });
// read out output stream to trigger decryption
await new Promise(resolve => {
diff --git a/test/general/config.js b/test/general/config.js
index e522097a2..0d5393d1c 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -272,6 +272,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
const { packets: [skesk, encData] } = encrypted;
expect(skesk.version).to.equal(4); // cfb
expect(encData.constructor.tag).to.equal(openpgp.enums.packet.symEncryptedIntegrityProtectedData);
+ expect(encData.version).to.equal(1);
const { packets: [literal] } = await encrypted.decrypt(null, passwords, null, encrypted.fromStream, openpgp.config);
expect(literal.constructor.tag).to.equal(openpgp.enums.packet.literalData);
@@ -284,7 +285,8 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
const encrypted2 = await openpgp.readMessage({ armoredMessage: armored2 });
const { packets: [skesk2, encData2] } = encrypted2;
expect(skesk2.version).to.equal(5);
- expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.aeadEncryptedData);
+ expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.symEncryptedIntegrityProtectedData);
+ expect(encData2.version).to.equal(2);
const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config);
expect(compressed.constructor.tag).to.equal(openpgp.enums.packet.compressedData);
expect(compressed.algorithm).to.equal(openpgp.enums.compression.zip);
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 15c5f9d8f..c0f19df88 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -2300,10 +2300,10 @@ XfA3pqV4mTzF
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM;
openpgp.config.v6Keys = true;
- // Monkey-patch AEAD feature flag
- publicKey.users[0].selfCertifications[0].features = [7];
- publicKey_2000_2008.users[0].selfCertifications[0].features = [7];
- publicKey_2038_2045.users[0].selfCertifications[0].features = [7];
+ // Monkey-patch SEIPD V2 feature flag
+ publicKey.users[0].selfCertifications[0].features = [9];
+ publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
+ publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
}
});
@@ -2313,10 +2313,10 @@ XfA3pqV4mTzF
openpgp.config.aeadProtect = true;
openpgp.config.aeadChunkSizeByte = 0;
- // Monkey-patch AEAD feature flag
- publicKey.users[0].selfCertifications[0].features = [7];
- publicKey_2000_2008.users[0].selfCertifications[0].features = [7];
- publicKey_2038_2045.users[0].selfCertifications[0].features = [7];
+ // Monkey-patch SEIPD V2 feature flag
+ publicKey.users[0].selfCertifications[0].features = [9];
+ publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
+ publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
}
});
@@ -2326,10 +2326,10 @@ XfA3pqV4mTzF
openpgp.config.aeadProtect = true;
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb;
- // Monkey-patch AEAD feature flag
- publicKey.users[0].selfCertifications[0].features = [7];
- publicKey_2000_2008.users[0].selfCertifications[0].features = [7];
- publicKey_2038_2045.users[0].selfCertifications[0].features = [7];
+ // Monkey-patch SEIPD V2 feature flag
+ publicKey.users[0].selfCertifications[0].features = [9];
+ publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
+ publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
}
});
@@ -2626,7 +2626,7 @@ XfA3pqV4mTzF
return openpgp.encrypt(encOpt).then(async function (encrypted) {
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(false);
+ expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
return openpgp.decrypt(decOpt);
}).then(function (decrypted) {
expect(decrypted.data).to.equal(plaintext);
@@ -2649,7 +2649,7 @@ XfA3pqV4mTzF
return openpgp.encrypt(encOpt).then(async function (encrypted) {
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(false);
+ expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
return openpgp.decrypt(decOpt);
}).then(function (decrypted) {
expect(decrypted.data).to.equal(plaintext);
@@ -2668,7 +2668,7 @@ XfA3pqV4mTzF
};
return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
+ expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
return openpgp.decrypt(decOpt);
}).then(async function (decrypted) {
expect(decrypted.data).to.equal(plaintext);
@@ -2692,7 +2692,7 @@ XfA3pqV4mTzF
};
return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
+ expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
return openpgp.decrypt(decOpt);
}).then(async function (decrypted) {
expect(decrypted.data).to.equal(plaintext);
@@ -2715,7 +2715,7 @@ XfA3pqV4mTzF
};
return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(false);
+ expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
return openpgp.decrypt(decOpt);
}).then(async function (decrypted) {
expect(decrypted.data).to.equal(plaintext);
@@ -2746,7 +2746,7 @@ XfA3pqV4mTzF
};
return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!decOpt.message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
+ expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
return openpgp.decrypt(decOpt);
}).then(async function (decrypted) {
expect(decrypted.data).to.equal(plaintext);
@@ -2775,7 +2775,7 @@ XfA3pqV4mTzF
detached: true
});
const message = await openpgp.readMessage({ armoredMessage: encrypted });
- expect(!!message.packets.findPacket(openpgp.enums.packet.aeadEncryptedData)).to.equal(openpgp.config.aeadProtect);
+ expect(message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(openpgp.config.aeadProtect);
const decrypted = await openpgp.decrypt({
message,
signature: await openpgp.readSignature({ armoredSignature: signed }),
diff --git a/test/general/packet.js b/test/general/packet.js
index dca36eadc..8d77cdfee 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -152,7 +152,7 @@ export default () => describe('Packet', function() {
expect(await stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
});
- it('Sym. encrypted AEAD protected packet', function() {
+ it('Sym. encrypted AEAD protected packet (AEADP)', function() {
const aeadProtectVal = openpgp.config.aeadProtect;
openpgp.config.aeadProtect = false;
@@ -201,7 +201,7 @@ export default () => describe('Packet', function() {
return cryptStub;
}
- it('Sym. encrypted AEAD protected packet is encrypted in parallel (AEAD, GCM)', async function() {
+ it('Sym. encrypted AEAD protected packet is encrypted in parallel (AEADP, GCM)', async function() {
const webCrypto = util.getWebCrypto();
if (!webCrypto || util.getNodeCrypto()) return;
const encryptStub = cryptStub(webCrypto, 'encrypt');
@@ -236,7 +236,7 @@ export default () => describe('Packet', function() {
}
});
- it('Sym. encrypted AEAD protected packet test vector (AEAD)', async function() {
+ it('AEAD Encrypted Data packet test vector (AEADP)', async function() {
// From https://gitlab.com/openpgp-wg/rfc4880bis/commit/00b20923e6233fb6ff1666ecd5acfefceb32907d
const nodeCrypto = util.getNodeCrypto();
@@ -516,7 +516,7 @@ export default () => describe('Packet', function() {
}
});
- it('Sym. encrypted session key reading/writing test vector (EAX, AEAD)', async function() {
+ it('Sym. encrypted session key reading/writing test vector (AEAD, EAX)', async function() {
// From https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b20923/back.mkd#sample-aead-eax-encryption-and-decryption
const nodeCrypto = util.getNodeCrypto();
From 6ae87b92082a978e6a08a69ba278f2250d33b120 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 14 Dec 2022 13:30:53 +0100
Subject: [PATCH 042/224] Implement Padding Packet
---
src/enums.js | 3 +-
src/packet/all_packets.js | 1 +
src/packet/packetlist.js | 3 +-
src/packet/padding.js | 63 +++++++++++++++
test/general/packet.js | 162 ++++++++++++++++++++++++++++++++++++++
5 files changed, 230 insertions(+), 2 deletions(-)
create mode 100644 src/packet/padding.js
diff --git a/src/enums.js b/src/enums.js
index aa49c9729..8b98ad177 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -223,7 +223,8 @@ export default {
userAttribute: 17,
symEncryptedIntegrityProtectedData: 18,
modificationDetectionCode: 19,
- aeadEncryptedData: 20 // see IETF draft: https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1
+ aeadEncryptedData: 20, // see IETF draft: https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1
+ padding: 21
},
/** Data types in the literal packet
diff --git a/src/packet/all_packets.js b/src/packet/all_packets.js
index 6362c3af3..1c3fd9787 100644
--- a/src/packet/all_packets.js
+++ b/src/packet/all_packets.js
@@ -21,3 +21,4 @@ export { default as UserIDPacket } from './userid';
export { default as SecretSubkeyPacket } from './secret_subkey';
export { default as SignaturePacket } from './signature';
export { default as TrustPacket } from './trust';
+export { default as PaddingPacket } from './padding';
diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js
index b0fea7f46..6207ef99e 100644
--- a/src/packet/packetlist.js
+++ b/src/packet/packetlist.js
@@ -74,10 +74,11 @@ class PacketList extends Array {
await writer.ready;
const done = await readPackets(readable, async parsed => {
try {
- if (parsed.tag === enums.packet.marker || parsed.tag === enums.packet.trust) {
+ if (parsed.tag === enums.packet.marker || parsed.tag === enums.packet.trust || parsed.tag === enums.packet.padding) {
// According to the spec, these packet types should be ignored and not cause parsing errors, even if not esplicitly allowed:
// - Marker packets MUST be ignored when received: https://github.com/openpgpjs/openpgpjs/issues/1145
// - Trust packets SHOULD be ignored outside of keyrings (unsupported): https://datatracker.ietf.org/doc/html/rfc4880#section-5.10
+ // - [Padding Packets] MUST be ignored when received: https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-padding-packet-tag-21
return;
}
const packet = newPacketFromTag(parsed.tag, allowedPackets);
diff --git a/src/packet/padding.js b/src/packet/padding.js
new file mode 100644
index 000000000..b60e1e4b3
--- /dev/null
+++ b/src/packet/padding.js
@@ -0,0 +1,63 @@
+// OpenPGP.js - An OpenPGP implementation in javascript
+// Copyright (C) 2022 Proton AG
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 3.0 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import crypto from '../crypto';
+import enums from '../enums';
+
+/**
+ * Implementation of the Padding Packet
+ *
+ * {@link https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-padding-packet-tag-21}:
+ * Padding Packet
+ */
+class PaddingPacket {
+ static get tag() {
+ return enums.packet.padding;
+ }
+
+ constructor() {
+ this.padding = null;
+ }
+
+ /**
+ * Read a padding packet
+ * @param {Uint8Array | ReadableStream} bytes
+ */
+ read(bytes) {
+ // Padding packets are ignored, so this function is never called.
+ }
+
+ /**
+ * Write the padding packet
+ * @returns {Uint8Array} The padding packet.
+ */
+ write() {
+ return this.padding;
+ }
+
+ /**
+ * Create random padding.
+ * @param {Number} length - The length of padding to be generated.
+ * @throws {Error} if padding generation was not successful
+ * @async
+ */
+ async createPadding(length) {
+ this.padding = await crypto.random.getRandomBytes(length);
+ }
+}
+
+export default PaddingPacket;
diff --git a/test/general/packet.js b/test/general/packet.js
index 8d77cdfee..329e13c78 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -280,6 +280,168 @@ export default () => describe('Packet', function() {
}
});
+ it('Sym. encrypted AEAD protected packet test vector (SEIPDv2 - EAX)', async function() {
+ // From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A-5
+
+ const nodeCrypto = util.getNodeCrypto();
+ if (!nodeCrypto) return;
+
+ const packetBytes = util.hexToUint8Array(`
+ d2 69 02 07 01 06
+ 9f f9 0e 3b 32 19 64 f3 a4 29 13 c8 dc c6 61 93
+ 25 01 52 27 ef b7 ea ea a4 9f 04 c2 e6 74 17 5d
+ 4a 3d 22 6e d6 af cb 9c a9 ac 12 2c 14 70 e1 1c
+ 63 d4 c0 ab 24 1c 6a 93 8a d4 8b f9 9a 5a 99 b9
+ 0b ba 83 25 de
+ 61 04 75 40 25 8a b7 95 9a 95 ad 05 1d da 96 eb
+ 15 43 1d fe f5 f5 e2 25 5c a7 82 61 54 6e 33 9a
+ `.replace(/\s+/g, ''));
+
+ const padding = util.hexToUint8Array('ae 5b f0 cd 67 05 50 03 55 81 6c b0 c8 ff'.replace(/\s+/g, ''));
+ const salt = util.hexToUint8Array('9f f9 0e 3b 32 19 64 f3 a4 29 13 c8 dc c6 61 93 25 01 52 27 ef b7 ea ea a4 9f 04 c2 e6 74 17 5d'.replace(/\s+/g, ''));
+ const key = util.hexToUint8Array('38 81 ba fe 98 54 12 45 9b 86 c3 6f 98 cb 9a 5e'.replace(/\s+/g, ''));
+ const algo = openpgp.enums.symmetric.aes128;
+
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
+ randomBytesStub.withArgs(14).returns(padding);
+ randomBytesStub.withArgs(32).returns(salt);
+
+ const literal = new openpgp.LiteralDataPacket(0);
+ literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
+ literal.filename = '';
+ const pad = new openpgp.PaddingPacket();
+ await pad.createPadding(14);
+ const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 2;
+ enc.aeadAlgorithm = openpgp.enums.aead.eax;
+ enc.packets = new openpgp.PacketList();
+ enc.packets.push(literal);
+ enc.packets.push(pad);
+ const msg = new openpgp.PacketList();
+ msg.push(enc);
+
+ const msg2 = new openpgp.PacketList();
+
+ try {
+ await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 6 });
+ const data = msg.write();
+ expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
+ await msg2.read(data, allAllowedPackets);
+ await msg2[0].decrypt(algo, key);
+ expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
+ } finally {
+ randomBytesStub.restore();
+ }
+ });
+
+ it('Sym. encrypted AEAD protected packet test vector (SEIPDv2 - OCB)', async function() {
+ // From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A-5
+
+ const nodeCrypto = util.getNodeCrypto();
+ if (!nodeCrypto) return;
+
+ const packetBytes = util.hexToUint8Array(`
+ d2 69 02 07 02 06
+ 20 a6 61 f7 31 fc 9a 30 32 b5 62 33 26 02 7e 3a
+ 5d 8d b5 74 8e be ff 0b 0c 59 10 d0 9e cd d6 41
+ ff 9f d3 85 62 75 80 35 bc 49 75 4c e1 bf 3f ff
+ a7 da d0 a3 b8 10 4f 51 33 cf 42 a4 10 0a 83 ee
+ f4 ca 1b 48 01
+ a8 84 6b f4 2b cd a7 c8 ce 9d 65 e2 12 f3 01 cb
+ cd 98 fd ca de 69 4a 87 7a d4 24 73 23 f6 e8 57
+ `.replace(/\s+/g, ''));
+
+ const padding = util.hexToUint8Array('ae 6a a1 64 9b 56 aa 83 5b 26 13 90 2b d2'.replace(/\s+/g, ''));
+ const salt = util.hexToUint8Array('20 a6 61 f7 31 fc 9a 30 32 b5 62 33 26 02 7e 3a 5d 8d b5 74 8e be ff 0b 0c 59 10 d0 9e cd d6 41'.replace(/\s+/g, ''));
+ const key = util.hexToUint8Array('28 e7 9a b8 23 97 d3 c6 3d e2 4a c2 17 d7 b7 91'.replace(/\s+/g, ''));
+ const algo = openpgp.enums.symmetric.aes128;
+
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
+ randomBytesStub.withArgs(14).returns(padding);
+ randomBytesStub.withArgs(32).returns(salt);
+
+ const literal = new openpgp.LiteralDataPacket(0);
+ literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
+ literal.filename = '';
+ const pad = new openpgp.PaddingPacket();
+ await pad.createPadding(14);
+ const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 2;
+ enc.aeadAlgorithm = openpgp.enums.aead.ocb;
+ enc.packets = new openpgp.PacketList();
+ enc.packets.push(literal);
+ enc.packets.push(pad);
+ const msg = new openpgp.PacketList();
+ msg.push(enc);
+
+ const msg2 = new openpgp.PacketList();
+
+ try {
+ await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 6 });
+ const data = msg.write();
+ expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
+ await msg2.read(data, allAllowedPackets);
+ await msg2[0].decrypt(algo, key);
+ expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
+ } finally {
+ randomBytesStub.restore();
+ }
+ });
+
+ it('Sym. encrypted AEAD protected packet test vector (SEIPDv2 - GCM)', async function() {
+ // From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A-5
+
+ const nodeCrypto = util.getNodeCrypto();
+ if (!nodeCrypto) return;
+
+ const packetBytes = util.hexToUint8Array(`
+ d2 69 02 07 03 06
+ fc b9 44 90 bc b9 8b bd c9 d1 06 c6 09 02 66 94
+ 0f 72 e8 9e dc 21 b5 59 6b 15 76 b1 01 ed 0f 9f
+ fc 6f c6 d6 5b bf d2 4d cd 07 90 96 6e 6d 1e 85
+ a3 00 53 78 4c b1 d8 b6 a0 69 9e f1 21 55 a7 b2
+ ad 62 58 53 1b
+ 57 65 1f d7 77 79 12 fa 95 e3 5d 9b 40 21 6f 69
+ a4 c2 48 db 28 ff 43 31 f1 63 29 07 39 9e 6f f9
+ `.replace(/\s+/g, ''));
+
+ const padding = util.hexToUint8Array('1c e2 26 9a 9e dd ef 81 03 21 72 b7 ed 7c'.replace(/\s+/g, ''));
+ const salt = util.hexToUint8Array('fc b9 44 90 bc b9 8b bd c9 d1 06 c6 09 02 66 94 0f 72 e8 9e dc 21 b5 59 6b 15 76 b1 01 ed 0f 9f'.replace(/\s+/g, ''));
+ const key = util.hexToUint8Array('19 36 fc 85 68 98 02 74 bb 90 0d 83 19 36 0c 77'.replace(/\s+/g, ''));
+ const algo = openpgp.enums.symmetric.aes128;
+
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
+ randomBytesStub.withArgs(14).returns(padding);
+ randomBytesStub.withArgs(32).returns(salt);
+
+ const literal = new openpgp.LiteralDataPacket(0);
+ literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
+ literal.filename = '';
+ const pad = new openpgp.PaddingPacket();
+ await pad.createPadding(14);
+ const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 2;
+ enc.aeadAlgorithm = openpgp.enums.aead.gcm;
+ enc.packets = new openpgp.PacketList();
+ enc.packets.push(literal);
+ enc.packets.push(pad);
+ const msg = new openpgp.PacketList();
+ msg.push(enc);
+
+ const msg2 = new openpgp.PacketList();
+
+ try {
+ await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 6 });
+ const data = msg.write();
+ expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
+ await msg2.read(data, allAllowedPackets);
+ await msg2[0].decrypt(algo, key);
+ expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
+ } finally {
+ randomBytesStub.restore();
+ }
+ });
+
it('Sym. encrypted session key with a compressed packet', async function() {
const msg =
'-----BEGIN PGP MESSAGE-----\n' +
From e5fe84dc2e81010780ae45061e92d20f456c0fe6 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Wed, 14 Dec 2022 18:08:01 +0100
Subject: [PATCH 043/224] Support SKESK v6 as per the latest crypto refresh
The latest crypto refresh specifies an HKDF step to be used for
deriving the key to encrypt the session key with.
It also specifies two additional length fields.
---
src/packet/sym_encrypted_session_key.js | 50 +++--
test/general/config.js | 2 +-
test/general/packet.js | 282 ++++++++++++++++++++++++
3 files changed, 317 insertions(+), 17 deletions(-)
diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js
index 6e940779e..2dcfea541 100644
--- a/src/packet/sym_encrypted_session_key.js
+++ b/src/packet/sym_encrypted_session_key.js
@@ -18,6 +18,7 @@
import { newS2KFromConfig, newS2KFromType } from '../type/s2k';
import defaultConfig from '../config';
import crypto from '../crypto';
+import computeHKDF from '../crypto/hkdf';
import enums from '../enums';
import util from '../util';
import { UnsupportedError } from './packet';
@@ -44,7 +45,7 @@ class SymEncryptedSessionKeyPacket {
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(config = defaultConfig) {
- this.version = config.aeadProtect ? 5 : 4;
+ this.version = config.aeadProtect ? 6 : 4;
this.sessionKey = null;
/**
* Algorithm to encrypt the session key with
@@ -74,18 +75,28 @@ class SymEncryptedSessionKeyPacket {
read(bytes) {
let offset = 0;
- // A one-octet version number. The only currently defined version is 4.
+ // A one-octet version number with value 4, 5 or 6.
this.version = bytes[offset++];
- if (this.version !== 4 && this.version !== 5) {
+ if (this.version !== 4 && this.version !== 5 && this.version !== 6) {
throw new UnsupportedError(`Version ${this.version} of the SKESK packet is unsupported.`);
}
+ if (this.version === 6) {
+ // A one-octet scalar octet count of the following 5 fields.
+ offset++;
+ }
+
// A one-octet number describing the symmetric algorithm used.
const algo = bytes[offset++];
- if (this.version === 5) {
+ if (this.version >= 5) {
// A one-octet AEAD algorithm.
this.aeadAlgorithm = bytes[offset++];
+
+ if (this.version === 6) {
+ // A one-octet scalar octet count of the following field.
+ offset++;
+ }
}
// A string-to-key (S2K) specifier, length as defined above.
@@ -93,7 +104,7 @@ class SymEncryptedSessionKeyPacket {
this.s2k = newS2KFromType(s2kType);
offset += this.s2k.read(bytes.subarray(offset, bytes.length));
- if (this.version === 5) {
+ if (this.version >= 5) {
const mode = crypto.getAEADMode(this.aeadAlgorithm);
// A starting initialization vector of size specified by the AEAD
@@ -103,7 +114,7 @@ class SymEncryptedSessionKeyPacket {
// The encrypted session key itself, which is decrypted with the
// string-to-key object. This is optional in version 4.
- if (this.version === 5 || offset < bytes.length) {
+ if (this.version >= 5 || offset < bytes.length) {
this.encrypted = bytes.subarray(offset, bytes.length);
this.sessionKeyEncryptionAlgorithm = algo;
} else {
@@ -123,10 +134,15 @@ class SymEncryptedSessionKeyPacket {
let bytes;
- if (this.version === 5) {
- bytes = util.concatUint8Array([new Uint8Array([this.version, algo, this.aeadAlgorithm]), this.s2k.write(), this.iv, this.encrypted]);
+ const s2k = this.s2k.write();
+ if (this.version === 6) {
+ const s2kLen = s2k.length;
+ const fieldsLen = 3 + s2kLen + this.iv.length;
+ bytes = util.concatUint8Array([new Uint8Array([this.version, fieldsLen, algo, this.aeadAlgorithm, s2kLen]), s2k, this.iv, this.encrypted]);
+ } else if (this.version === 5) {
+ bytes = util.concatUint8Array([new Uint8Array([this.version, algo, this.aeadAlgorithm]), s2k, this.iv, this.encrypted]);
} else {
- bytes = util.concatUint8Array([new Uint8Array([this.version, algo]), this.s2k.write()]);
+ bytes = util.concatUint8Array([new Uint8Array([this.version, algo]), s2k]);
if (this.encrypted !== null) {
bytes = util.concatUint8Array([bytes, this.encrypted]);
@@ -150,10 +166,11 @@ class SymEncryptedSessionKeyPacket {
const { blockSize, keySize } = crypto.getCipher(algo);
const key = await this.s2k.produceKey(passphrase, keySize);
- if (this.version === 5) {
+ if (this.version >= 5) {
const mode = crypto.getAEADMode(this.aeadAlgorithm);
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
- const modeInstance = await mode(algo, key);
+ const encryptionKey = this.version === 6 ? await computeHKDF(enums.hash.sha256, key, new Uint8Array(), adata, keySize) : key;
+ const modeInstance = await mode(algo, encryptionKey);
this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata);
} else if (this.encrypted !== null) {
const decrypted = await crypto.mode.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(blockSize));
@@ -183,24 +200,25 @@ class SymEncryptedSessionKeyPacket {
this.s2k.generateSalt();
const { blockSize, keySize } = crypto.getCipher(algo);
- const encryptionKey = await this.s2k.produceKey(passphrase, keySize);
+ const key = await this.s2k.produceKey(passphrase, keySize);
if (this.sessionKey === null) {
this.sessionKey = crypto.generateSessionKey(this.sessionKeyAlgorithm);
}
- if (this.version === 5) {
+ if (this.version >= 5) {
const mode = crypto.getAEADMode(this.aeadAlgorithm);
this.iv = crypto.random.getRandomBytes(mode.ivLength); // generate new random IV
- const associatedData = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
+ const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
+ const encryptionKey = this.version === 6 ? await computeHKDF(enums.hash.sha256, key, new Uint8Array(), adata, keySize) : key;
const modeInstance = await mode(algo, encryptionKey);
- this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, associatedData);
+ this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, adata);
} else {
const toEncrypt = util.concatUint8Array([
new Uint8Array([this.sessionKeyAlgorithm]),
this.sessionKey
]);
- this.encrypted = await crypto.mode.cfb.encrypt(algo, encryptionKey, toEncrypt, new Uint8Array(blockSize), config);
+ this.encrypted = await crypto.mode.cfb.encrypt(algo, key, toEncrypt, new Uint8Array(blockSize), config);
}
}
}
diff --git a/test/general/config.js b/test/general/config.js
index 0d5393d1c..66032a91e 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -284,7 +284,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
const armored2 = await openpgp.encrypt({ message, passwords, config });
const encrypted2 = await openpgp.readMessage({ armoredMessage: armored2 });
const { packets: [skesk2, encData2] } = encrypted2;
- expect(skesk2.version).to.equal(5);
+ expect(skesk2.version).to.equal(6);
expect(encData2.constructor.tag).to.equal(openpgp.enums.packet.symEncryptedIntegrityProtectedData);
expect(encData2.version).to.equal(2);
const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config);
diff --git a/test/general/packet.js b/test/general/packet.js
index 329e13c78..11397a454 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -644,6 +644,45 @@ export default () => describe('Packet', function() {
const aeadProtectVal = openpgp.config.aeadProtect;
openpgp.config.aeadProtect = true;
+ try {
+ const passphrase = 'hello';
+ const algo = openpgp.enums.symmetric.aes256;
+ const testText = input.createSomeMessage();
+
+ const literal = new openpgp.LiteralDataPacket();
+ literal.setText(testText);
+ const skesk = new openpgp.SymEncryptedSessionKeyPacket();
+ skesk.version = 5;
+ const aeadEnc = new openpgp.AEADEncryptedDataPacket();
+ aeadEnc.packets = new openpgp.PacketList();
+ aeadEnc.packets.push(literal);
+ const msg = new openpgp.PacketList();
+ msg.push(skesk);
+ msg.push(aeadEnc);
+
+ skesk.sessionKeyAlgorithm = algo;
+ await skesk.encrypt(passphrase, openpgp.config);
+
+ const key = skesk.sessionKey;
+ await aeadEnc.encrypt(algo, key, undefined, openpgp.config);
+
+ const msg2 = new openpgp.PacketList();
+ await msg2.read(msg.write(), allAllowedPackets);
+
+ await msg2[0].decrypt(passphrase);
+ const key2 = msg2[0].sessionKey;
+ await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
+
+ expect(await stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
+ } finally {
+ openpgp.config.aeadProtect = aeadProtectVal;
+ }
+ });
+
+ it('Sym. encrypted session key reading/writing (SEIPDv2)', async function() {
+ const aeadProtectVal = openpgp.config.aeadProtect;
+ openpgp.config.aeadProtect = true;
+
try {
const passphrase = 'hello';
const algo = openpgp.enums.symmetric.aes256;
@@ -723,10 +762,12 @@ export default () => describe('Packet', function() {
literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
literal.filename = '';
const skesk = new openpgp.SymEncryptedSessionKeyPacket();
+ skesk.version = 5;
skesk.sessionKeyAlgorithm = algo;
const encData = new openpgp.AEADEncryptedDataPacket();
encData.packets = new openpgp.PacketList();
encData.packets.push(literal);
+ encData.aeadAlgorithm = skesk.aeadAlgorithm = openpgp.enums.aead.eax;
const msg = new openpgp.PacketList();
msg.push(skesk);
msg.push(encData);
@@ -800,6 +841,7 @@ export default () => describe('Packet', function() {
literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary);
literal.filename = '';
const skesk = new openpgp.SymEncryptedSessionKeyPacket();
+ skesk.version = 5;
skesk.sessionKeyAlgorithm = algo;
const enc = new openpgp.AEADEncryptedDataPacket();
enc.packets = new openpgp.PacketList();
@@ -833,6 +875,246 @@ export default () => describe('Packet', function() {
}
});
+ it('Sym. encrypted session key reading/writing test vector (SEIPDv2, EAX)', async function() {
+ // From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A.5
+
+ const nodeCrypto = util.getNodeCrypto();
+ if (!nodeCrypto) return;
+
+ const aeadProtectVal = openpgp.config.aeadProtect;
+ const aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
+ const s2kIterationCountByteVal = openpgp.config.s2kIterationCountByte;
+ openpgp.config.aeadProtect = true;
+ openpgp.config.aeadChunkSizeByte = 6;
+ openpgp.config.s2kIterationCountByte = 255;
+
+ const padding = util.hexToUint8Array('ae 5b f0 cd 67 05 50 03 55 81 6c b0 c8 ff'.replace(/\s+/g, ''));
+ const salt = util.hexToUint8Array('a5 ae 57 9d 1f c5 d8 2b'.replace(/\s+/g, ''));
+ const sessionKey = util.hexToUint8Array('38 81 ba fe 98 54 12 45 9b 86 c3 6f 98 cb 9a 5e'.replace(/\s+/g, ''));
+ const sessionIV = util.hexToUint8Array('69 22 4f 91 99 93 b3 50 6f a3 b5 9a 6a 73 cf f8'.replace(/\s+/g, ''));
+ const dataSalt = util.hexToUint8Array('9f f9 0e 3b 32 19 64 f3 a4 29 13 c8 dc c6 61 93 25 01 52 27 ef b7 ea ea a4 9f 04 c2 e6 74 17 5d'.replace(/\s+/g, ''));
+
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
+ randomBytesStub.onCall(0).returns(padding);
+ randomBytesStub.onCall(1).returns(salt);
+ randomBytesStub.onCall(2).returns(sessionKey);
+ randomBytesStub.onCall(3).returns(sessionIV);
+ randomBytesStub.onCall(4).returns(dataSalt);
+
+ const { data: packetBytes } = await openpgp.unarmor(`-----BEGIN PGP MESSAGE-----
+
+w0AGHgcBCwMIpa5XnR/F2Cv/aSJPkZmTs1Bvo7WaanPP+MXvxfQcV/tU4cImgV14
+KPX5LEVOtl6+AKtZhsaObnxV0mkCBwEGn/kOOzIZZPOkKRPI3MZhkyUBUifvt+rq
+pJ8EwuZ0F11KPSJu1q/LnKmsEiwUcOEcY9TAqyQcapOK1Iv5mlqZuQu6gyXeYQR1
+QCWKt5Wala0FHdqW6xVDHf719eIlXKeCYVRuM5o=
+-----END PGP MESSAGE-----
+`);
+
+ try {
+ const passphrase = 'password';
+ const algo = openpgp.enums.symmetric.aes128;
+
+ const skesk = new openpgp.SymEncryptedSessionKeyPacket();
+ skesk.sessionKeyAlgorithm = algo;
+ const literal = new openpgp.LiteralDataPacket(0);
+ literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
+ literal.filename = '';
+ const pad = new openpgp.PaddingPacket();
+ await pad.createPadding(14);
+ const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 2;
+ enc.aeadAlgorithm = skesk.aeadAlgorithm = openpgp.enums.aead.eax;
+ enc.packets = new openpgp.PacketList();
+ enc.packets.push(literal);
+ enc.packets.push(pad);
+ const msg = new openpgp.PacketList();
+ msg.push(skesk);
+ msg.push(enc);
+
+ await skesk.encrypt(passphrase, openpgp.config);
+
+ const key = skesk.sessionKey;
+ await enc.encrypt(algo, key, undefined, openpgp.config);
+
+ const data = msg.write();
+ expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
+
+ const msg2 = new openpgp.PacketList();
+ await msg2.read(data, allAllowedPackets);
+
+ await msg2[0].decrypt(passphrase);
+ const key2 = msg2[0].sessionKey;
+ await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
+
+ expect(await stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
+ } finally {
+ openpgp.config.aeadProtect = aeadProtectVal;
+ openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
+ openpgp.config.s2kIterationCountByte = s2kIterationCountByteVal;
+ randomBytesStub.restore();
+ }
+ });
+
+ it('Sym. encrypted session key reading/writing test vector (SEIPDv2, OCB)', async function() {
+ // From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A.6
+
+ const nodeCrypto = util.getNodeCrypto();
+ if (!nodeCrypto) return;
+
+ const aeadProtectVal = openpgp.config.aeadProtect;
+ const aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
+ const s2kIterationCountByteVal = openpgp.config.s2kIterationCountByte;
+ openpgp.config.aeadProtect = true;
+ openpgp.config.aeadChunkSizeByte = 6;
+ openpgp.config.s2kIterationCountByte = 255;
+
+ const padding = util.hexToUint8Array('ae 6a a1 64 9b 56 aa 83 5b 26 13 90 2b d2'.replace(/\s+/g, ''));
+ const salt = util.hexToUint8Array('56 a2 98 d2 f5 e3 64 53'.replace(/\s+/g, ''));
+ const sessionKey = util.hexToUint8Array('28 e7 9a b8 23 97 d3 c6 3d e2 4a c2 17 d7 b7 91'.replace(/\s+/g, ''));
+ const sessionIV = util.hexToUint8Array('cf cc 5c 11 66 4e db 9d b4 25 90 d7 dc 46 b0'.replace(/\s+/g, ''));
+ const dataSalt = util.hexToUint8Array('20 a6 61 f7 31 fc 9a 30 32 b5 62 33 26 02 7e 3a 5d 8d b5 74 8e be ff 0b 0c 59 10 d0 9e cd d6 41'.replace(/\s+/g, ''));
+
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
+ randomBytesStub.onCall(0).returns(padding);
+ randomBytesStub.onCall(1).returns(salt);
+ randomBytesStub.onCall(2).returns(sessionKey);
+ randomBytesStub.onCall(3).returns(sessionIV);
+ randomBytesStub.onCall(4).returns(dataSalt);
+
+ const { data: packetBytes } = await openpgp.unarmor(`-----BEGIN PGP MESSAGE-----
+
+wz8GHQcCCwMIVqKY0vXjZFP/z8xcEWZO2520JZDX3EawckG2EsOBLP/76gDyNHsl
+ZBEj+IeuYNT9YU4IN9gZ02zSaQIHAgYgpmH3MfyaMDK1YjMmAn46XY21dI6+/wsM
+WRDQns3WQf+f04VidYA1vEl1TOG/P/+n2tCjuBBPUTPPQqQQCoPu9MobSAGohGv0
+K82nyM6dZeIS8wHLzZj9yt5pSod61CRzI/boVw==
+-----END PGP MESSAGE-----
+`);
+
+ try {
+ const passphrase = 'password';
+ const algo = openpgp.enums.symmetric.aes128;
+
+ const skesk = new openpgp.SymEncryptedSessionKeyPacket();
+ skesk.sessionKeyAlgorithm = algo;
+ const literal = new openpgp.LiteralDataPacket(0);
+ literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
+ literal.filename = '';
+ const pad = new openpgp.PaddingPacket();
+ await pad.createPadding(14);
+ const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 2;
+ enc.aeadAlgorithm = skesk.aeadAlgorithm = openpgp.enums.aead.ocb;
+ enc.packets = new openpgp.PacketList();
+ enc.packets.push(literal);
+ enc.packets.push(pad);
+ const msg = new openpgp.PacketList();
+ msg.push(skesk);
+ msg.push(enc);
+
+ await skesk.encrypt(passphrase, openpgp.config);
+
+ const key = skesk.sessionKey;
+ await enc.encrypt(algo, key, undefined, openpgp.config);
+
+ const data = msg.write();
+ expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
+
+ const msg2 = new openpgp.PacketList();
+ await msg2.read(data, allAllowedPackets);
+
+ await msg2[0].decrypt(passphrase);
+ const key2 = msg2[0].sessionKey;
+ await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
+
+ expect(await stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
+ } finally {
+ openpgp.config.aeadProtect = aeadProtectVal;
+ openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
+ openpgp.config.s2kIterationCountByte = s2kIterationCountByteVal;
+ randomBytesStub.restore();
+ }
+ });
+
+ it('Sym. encrypted session key reading/writing test vector (SEIPDv2, GCM)', async function() {
+ // From https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#appendix-A.7
+
+ const nodeCrypto = util.getNodeCrypto();
+ if (!nodeCrypto) return;
+
+ const aeadProtectVal = openpgp.config.aeadProtect;
+ const aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
+ const s2kIterationCountByteVal = openpgp.config.s2kIterationCountByte;
+ openpgp.config.aeadProtect = true;
+ openpgp.config.aeadChunkSizeByte = 6;
+ openpgp.config.s2kIterationCountByte = 255;
+
+ const padding = util.hexToUint8Array('1c e2 26 9a 9e dd ef 81 03 21 72 b7 ed 7c'.replace(/\s+/g, ''));
+ const salt = util.hexToUint8Array('e9 d3 97 85 b2 07 00 08'.replace(/\s+/g, ''));
+ const sessionKey = util.hexToUint8Array('19 36 fc 85 68 98 02 74 bb 90 0d 83 19 36 0c 77'.replace(/\s+/g, ''));
+ const sessionIV = util.hexToUint8Array('b4 2e 7c 48 3e f4 88 44 57 cb 37 26'.replace(/\s+/g, ''));
+ const dataSalt = util.hexToUint8Array('fc b9 44 90 bc b9 8b bd c9 d1 06 c6 09 02 66 94 0f 72 e8 9e dc 21 b5 59 6b 15 76 b1 01 ed 0f 9f'.replace(/\s+/g, ''));
+
+ const randomBytesStub = sinon.stub(nodeCrypto, 'randomBytes');
+ randomBytesStub.onCall(0).returns(padding);
+ randomBytesStub.onCall(1).returns(salt);
+ randomBytesStub.onCall(2).returns(sessionKey);
+ randomBytesStub.onCall(3).returns(sessionIV);
+ randomBytesStub.onCall(4).returns(dataSalt);
+
+ const { data: packetBytes } = await openpgp.unarmor(`-----BEGIN PGP MESSAGE-----
+
+wzwGGgcDCwMI6dOXhbIHAAj/tC58SD70iERXyzcmubPbn/d25fTZpAlS4kRymIUa
+v/91Jt8t1VRBdXmneZ/SaQIHAwb8uUSQvLmLvcnRBsYJAmaUD3LontwhtVlrFXax
+Ae0Pn/xvxtZbv9JNzQeQlm5tHoWjAFN4TLHYtqBpnvEhVaeyrWJYUxtXZR/Xd3kS
++pXjXZtAIW9ppMJI2yj/QzHxYykHOZ5v+Q==
+-----END PGP MESSAGE-----
+`);
+
+ try {
+ const passphrase = 'password';
+ const algo = openpgp.enums.symmetric.aes128;
+
+ const skesk = new openpgp.SymEncryptedSessionKeyPacket();
+ skesk.sessionKeyAlgorithm = algo;
+ const literal = new openpgp.LiteralDataPacket(0);
+ literal.setBytes(util.stringToUint8Array('Hello, world!'), openpgp.enums.literal.binary);
+ literal.filename = '';
+ const pad = new openpgp.PaddingPacket();
+ await pad.createPadding(14);
+ const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 2;
+ enc.aeadAlgorithm = skesk.aeadAlgorithm = openpgp.enums.aead.gcm;
+ enc.packets = new openpgp.PacketList();
+ enc.packets.push(literal);
+ enc.packets.push(pad);
+ const msg = new openpgp.PacketList();
+ msg.push(skesk);
+ msg.push(enc);
+
+ await skesk.encrypt(passphrase, openpgp.config);
+
+ const key = skesk.sessionKey;
+ await enc.encrypt(algo, key, undefined, openpgp.config);
+
+ const data = msg.write();
+ expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
+
+ const msg2 = new openpgp.PacketList();
+ await msg2.read(data, allAllowedPackets);
+
+ await msg2[0].decrypt(passphrase);
+ const key2 = msg2[0].sessionKey;
+ await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
+
+ expect(await stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
+ } finally {
+ openpgp.config.aeadProtect = aeadProtectVal;
+ openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
+ openpgp.config.s2kIterationCountByte = s2kIterationCountByteVal;
+ randomBytesStub.restore();
+ }
+ });
+
it('Secret key encryption/decryption test', async function() {
const armored_msg =
'-----BEGIN PGP MESSAGE-----\n' +
From f77ed0c0ed062349d64d52aca31c9e4b57d5fd8e Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Thu, 16 Mar 2023 18:17:26 +0100
Subject: [PATCH 044/224] Look up preferred ciphersuite in one go
Instead of calling getPreferredAlgo('symmetric') and
getPreferredAlgo('aead'), we define and call getPreferredCipherSuite()
to determine the preferred symmetric and AEAD algorithm.
Additionally, we remove isAEADSupported(), instead we return
aeadAlgorithm: undefined from getPreferredCipherSuite() if AEAD is not
supported (CFB is used instead).
And finally, we define getPreferredCompressionAlgo() to replace
getPreferredAlgo('compression').
---
src/key/helper.js | 78 +++++++++++++++++++---------------------
src/key/index.js | 8 ++---
src/message.js | 16 ++++-----
src/openpgp.js | 4 +--
test/general/key.js | 79 +++++++++++++++++++++++------------------
test/general/openpgp.js | 5 +--
6 files changed, 96 insertions(+), 94 deletions(-)
diff --git a/src/key/helper.js b/src/key/helper.js
index 766f41c92..15ed43701 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -134,43 +134,59 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us
}
/**
- * Returns the preferred symmetric/aead/compression algorithm for a set of keys
- * @param {'symmetric'|'aead'|'compression'} type - Type of preference to return
+ * Returns the preferred compression algorithm for a set of keys
* @param {Array} [keys] - Set of keys
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Array} [userIDs] - User IDs
* @param {Object} [config] - Full configuration, defaults to openpgp.config
- * @returns {Promise} Preferred algorithm
+ * @returns {Promise} Preferred compression algorithm
* @async
*/
-export async function getPreferredAlgo(type, keys = [], date = new Date(), userIDs = [], config = defaultConfig) {
- const defaultAlgo = { // these are all must-implement in the crypto refresh
- 'symmetric': enums.symmetric.aes128,
- 'aead': enums.aead.ocb,
- 'compression': enums.compression.uncompressed
- }[type];
- const preferredSenderAlgo = {
- 'symmetric': config.preferredSymmetricAlgorithm,
- 'aead': config.preferredAEADAlgorithm,
- 'compression': config.preferredCompressionAlgorithm
- }[type];
- const prefPropertyName = {
- 'symmetric': 'preferredSymmetricAlgorithms',
- 'aead': 'preferredAEADAlgorithms',
- 'compression': 'preferredCompressionAlgorithms'
- }[type];
+export async function getPreferredCompressionAlgo(keys = [], date = new Date(), userIDs = [], config = defaultConfig) {
+ const defaultAlgo = enums.compression.uncompressed;
+ const preferredSenderAlgo = config.preferredCompressionAlgorithm;
// if preferredSenderAlgo appears in the prefs of all recipients, we pick it
// otherwise we use the default algo
// if no keys are available, preferredSenderAlgo is returned
const senderAlgoSupport = await Promise.all(keys.map(async function(key, i) {
const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config);
- const recipientPrefs = selfCertification[prefPropertyName];
+ const recipientPrefs = selfCertification.preferredCompressionAlgorithms;
return !!recipientPrefs && recipientPrefs.indexOf(preferredSenderAlgo) >= 0;
}));
return senderAlgoSupport.every(Boolean) ? preferredSenderAlgo : defaultAlgo;
}
+/**
+ * Returns the preferred symmetric and AEAD algorithm (if any) for a set of keys
+ * @param {Array} [keys] - Set of keys
+ * @param {Date} [date] - Use the given date for verification instead of the current time
+ * @param {Array} [userIDs] - User IDs
+ * @param {Object} [config] - Full configuration, defaults to openpgp.config
+ * @returns {Promise<{ symmetricAlgo: module:enums.symmetric, aeadAlgo: module:enums.aead | undefined }>} Object containing the preferred symmetric algorithm, and the preferred AEAD algorithm, or undefined if CFB is preferred
+ * @async
+ */
+export async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [], config = defaultConfig) {
+ const selfSigs = await Promise.all(keys.map((key, i) => key.getPrimarySelfSignature(date, userIDs[i], config)));
+ if (config.aeadProtect && selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2)) {
+ const defaultCipherSuite = { symmetricAlgo: enums.symmetric.aes128, aeadAlgo: enums.aead.ocb };
+ const desiredCipherSuite = { symmetricAlgo: config.preferredSymmetricAlgorithm, aeadAlgo: config.preferredAEADAlgorithm };
+ return selfSigs.every(selfSig => selfSig.preferredCipherSuites && selfSig.preferredCipherSuites.some(
+ cipherSuite => cipherSuite[0] === desiredCipherSuite.symmetricAlgo && cipherSuite[1] === desiredCipherSuite.aeadAlgo
+ )) ?
+ desiredCipherSuite :
+ defaultCipherSuite;
+ }
+ const defaultSymAlgo = enums.symmetric.aes128;
+ const desiredSymAlgo = config.preferredSymmetricAlgorithm;
+ return {
+ symmetricAlgo: selfSigs.every(selfSig => selfSig.preferredSymmetricAlgorithms && selfSig.preferredSymmetricAlgorithms.includes(desiredSymAlgo)) ?
+ desiredSymAlgo :
+ defaultSymAlgo,
+ aeadAlgo: undefined
+ };
+}
+
/**
* Create signature packet
* @param {Object} dataToSign - Contains packets to be signed
@@ -293,28 +309,6 @@ export function getKeyExpirationTime(keyPacket, signature) {
return expirationTime ? new Date(expirationTime) : Infinity;
}
-/**
- * Returns whether aead is supported by all keys in the set
- * @param {Array} keys - Set of keys
- * @param {Date} [date] - Use the given date for verification instead of the current time
- * @param {Array} [userIDs] - User IDs
- * @param {Object} config - full configuration
- * @returns {Promise}
- * @async
- */
-export async function isAEADSupported(keys, date = new Date(), userIDs = [], config = defaultConfig) {
- let supported = true;
- // TODO replace when Promise.some or Promise.any are implemented
- await Promise.all(keys.map(async function(key, i) {
- const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config);
- if (!selfCertification.features ||
- !(selfCertification.features[0] & enums.features.seipdv2)) {
- supported = false;
- }
- }));
- return supported;
-}
-
export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
options.type = options.type || subkeyDefaults.type;
options.curve = options.curve || subkeyDefaults.curve;
diff --git a/src/key/index.js b/src/key/index.js
index 47c430196..6781baa94 100644
--- a/src/key/index.js
+++ b/src/key/index.js
@@ -8,9 +8,9 @@ import {
} from './factory';
import {
- getPreferredAlgo,
- isAEADSupported,
getPreferredHashAlgo,
+ getPreferredCompressionAlgo,
+ getPreferredCipherSuite,
createSignaturePacket
} from './helper';
@@ -25,9 +25,9 @@ export {
readPrivateKeys,
generate,
reformat,
- getPreferredAlgo,
- isAEADSupported,
getPreferredHashAlgo,
+ getPreferredCompressionAlgo,
+ getPreferredCipherSuite,
createSignaturePacket,
PrivateKey,
PublicKey,
diff --git a/src/message.js b/src/message.js
index a17f523c2..fac3eb96a 100644
--- a/src/message.js
+++ b/src/message.js
@@ -24,7 +24,7 @@ import crypto from './crypto';
import enums from './enums';
import util from './util';
import { Signature } from './signature';
-import { getPreferredHashAlgo, getPreferredAlgo, isAEADSupported, createSignaturePacket } from './key';
+import { getPreferredHashAlgo, getPreferredCipherSuite, createSignaturePacket } from './key';
import {
PacketList,
LiteralDataPacket,
@@ -343,23 +343,21 @@ export class Message {
* @async
*/
static async generateSessionKey(encryptionKeys = [], date = new Date(), userIDs = [], config = defaultConfig) {
- const algo = await getPreferredAlgo('symmetric', encryptionKeys, date, userIDs, config);
- const algorithmName = enums.read(enums.symmetric, algo);
- const aeadAlgorithmName = config.aeadProtect && await isAEADSupported(encryptionKeys, date, userIDs, config) ?
- enums.read(enums.aead, await getPreferredAlgo('aead', encryptionKeys, date, userIDs, config)) :
- undefined;
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite(encryptionKeys, date, userIDs, config);
+ const symmetricAlgoName = enums.read(enums.symmetric, symmetricAlgo);
+ const aeadAlgoName = aeadAlgo ? enums.read(enums.aead, aeadAlgo) : undefined;
await Promise.all(encryptionKeys.map(key => key.getEncryptionKey()
.catch(() => null) // ignore key strength requirements
.then(maybeKey => {
- if (maybeKey && (maybeKey.keyPacket.algorithm === enums.publicKey.x25519) && !util.isAES(algo)) {
+ if (maybeKey && (maybeKey.keyPacket.algorithm === enums.publicKey.x25519) && !util.isAES(symmetricAlgo)) {
throw new Error('Could not generate a session key compatible with the given `encryptionKeys`: X22519 keys can only be used to encrypt AES session keys; change `config.preferredSymmetricAlgorithm` accordingly.');
}
})
));
- const sessionKeyData = crypto.generateSessionKey(algo);
- return { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName };
+ const sessionKeyData = crypto.generateSessionKey(symmetricAlgo);
+ return { data: sessionKeyData, algorithm: symmetricAlgoName, aeadAlgorithm: aeadAlgoName };
}
/**
diff --git a/src/openpgp.js b/src/openpgp.js
index cef01e9b3..223ebfdf9 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -18,7 +18,7 @@
import * as stream from '@openpgp/web-stream-tools';
import { Message } from './message';
import { CleartextMessage } from './cleartext';
-import { generate, reformat, getPreferredAlgo } from './key';
+import { generate, reformat, getPreferredCompressionAlgo } from './key';
import defaultConfig from './config';
import util from './util';
import { checkKeyRequirements } from './key/helper';
@@ -284,7 +284,7 @@ export async function encrypt({ message, encryptionKeys, signingKeys, passwords,
message = await message.sign(signingKeys, signature, signingKeyIDs, date, signingUserIDs, signatureNotations, config);
}
message = message.compress(
- await getPreferredAlgo('compression', encryptionKeys, date, encryptionUserIDs, config),
+ await getPreferredCompressionAlgo(encryptionKeys, date, encryptionUserIDs, config),
config
);
message = await message.encrypt(encryptionKeys, passwords, sessionKey, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config);
diff --git a/test/general/key.js b/test/general/key.js
index 2f266ef93..9ed68d979 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -6,7 +6,7 @@ chaiUse(chaiAsPromised);
import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
-import { isAEADSupported, getPreferredAlgo } from '../../src/key';
+import { getPreferredCipherSuite } from '../../src/key';
import KeyID from '../../src/type/keyid.js';
@@ -3643,76 +3643,85 @@ aU71tdtNBQ==
expect(revKey.armor()).not.to.match(/Comment: This is a revocation certificate/);
});
- it("getPreferredAlgo('symmetric') - one key", async function() {
+ it('getPreferredCipherSuite - one key', async function() {
const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
- const prefAlgo = await getPreferredAlgo('symmetric', [key1], undefined, undefined, {
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1], undefined, undefined, {
...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256
});
- expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
+ expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
+ expect(aeadAlgo).to.equal(undefined);
});
- it("getPreferredAlgo('symmetric') - two key", async function() {
+ it('getPreferredCipherSuite - two keys', async function() {
const { aes128, aes192, cast5 } = openpgp.enums.symmetric;
const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys });
const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = [6, aes192, cast5];
- const prefAlgo = await getPreferredAlgo('symmetric', [key1, key2], undefined, undefined, {
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes192
});
- expect(prefAlgo).to.equal(aes192);
- const prefAlgo2 = await getPreferredAlgo('symmetric', [key1, key2], undefined, undefined, {
+ expect(symmetricAlgo).to.equal(aes192);
+ expect(aeadAlgo).to.equal(undefined);
+ const { symmetricAlgo: symmetricAlgo2, aeadAlgo: aeadAlgo2 } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256
});
- expect(prefAlgo2).to.equal(aes128);
+ expect(symmetricAlgo2).to.equal(aes128);
+ expect(aeadAlgo2).to.equal(undefined);
});
- it("getPreferredAlgo('symmetric') - two key - one without pref", async function() {
+ it('getPreferredCipherSuite - two keys - one without pref', async function() {
const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys });
const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = null;
- const prefAlgo = await getPreferredAlgo('symmetric', [key1, key2]);
- expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128);
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2]);
+ expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes128);
+ expect(aeadAlgo).to.equal(undefined);
});
- it("getPreferredAlgo('aead') - one key - OCB", async function() {
+ it('getPreferredCipherSuite with AEAD - one key - GCM', async function() {
const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
const primaryUser = await key1.getPrimaryUser();
- primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
- primaryUser.selfCertification.preferredAEADAlgorithms = [2,1];
- const prefAlgo = await getPreferredAlgo('aead', [key1], undefined, undefined, {
- ...openpgp.config, preferredAEADAlgorithm: openpgp.enums.aead.ocb
+ primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
+ primaryUser.selfCertification.preferredCipherSuites = [[9, 3], [9, 2]];
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1], undefined, undefined, {
+ ...openpgp.config,
+ aeadProtect: true,
+ preferredAEADAlgorithm: openpgp.enums.aead.gcm
});
- expect(prefAlgo).to.equal(openpgp.enums.aead.ocb);
- const supported = await isAEADSupported([key1]);
- expect(supported).to.be.true;
+ expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
+ expect(aeadAlgo).to.equal(openpgp.enums.aead.gcm);
});
- it("getPreferredAlgo('aead') - two key - one without pref", async function() {
+ it('getPreferredCipherSuite with AEAD - two keys - one without pref', async function() {
const keys = await openpgp.readKeys({ armoredKeys: twoKeys });
const key1 = keys[0];
const key2 = keys[1];
const primaryUser = await key1.getPrimaryUser();
- primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
- primaryUser.selfCertification.preferredAEADAlgorithms = [2,1];
+ primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
+ primaryUser.selfCertification.preferredCipherSuites = [[9, 3], [9, 2]];
const primaryUser2 = await key2.getPrimaryUser();
- primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
- const prefAlgo = await getPreferredAlgo('aead', [key1, key2]);
- expect(prefAlgo).to.equal(openpgp.enums.aead.eax);
- const supported = await isAEADSupported([key1, key2]);
- expect(supported).to.be.true;
+ primaryUser2.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
+ ...openpgp.config,
+ aeadProtect: true
+ });
+ expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes128);
+ expect(aeadAlgo).to.equal(openpgp.enums.aead.ocb);
});
- it("getPreferredAlgo('aead') - two key - one with no support", async function() {
+ it('getPreferredCipherSuite with AEAD - two keys - one with no support', async function() {
const keys = await openpgp.readKeys({ armoredKeys: twoKeys });
const key1 = keys[0];
const key2 = keys[1];
const primaryUser = await key1.getPrimaryUser();
- primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
- primaryUser.selfCertification.preferredAEADAlgorithms = [2,1];
- const prefAlgo = await getPreferredAlgo('aead', [key1, key2]);
- expect(prefAlgo).to.equal(openpgp.enums.aead.eax);
- const supported = await isAEADSupported([key1, key2]);
- expect(supported).to.be.false;
+ primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
+ primaryUser.selfCertification.preferredCipherSuites = [[9, 3], [9, 2]];
+ const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
+ ...openpgp.config,
+ aeadProtect: true
+ });
+ expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
+ expect(aeadAlgo).to.equal(undefined);
});
it('User attribute packet read & write', async function() {
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index c0f19df88..16a2c949e 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -11,7 +11,7 @@ import crypto from '../../src/crypto';
import * as random from '../../src/crypto/random.js';
import util from '../../src/util.js';
import keyIDType from '../../src/type/keyid.js';
-import { isAEADSupported } from '../../src/key';
+import { getPreferredCipherSuite } from '../../src/key';
import * as input from './testInputs.js';
@@ -3054,7 +3054,8 @@ XfA3pqV4mTzF
it('should fail to decrypt modified message', async function() {
const allowUnauthenticatedStream = openpgp.config.allowUnauthenticatedStream;
const { privateKey: key } = await openpgp.generateKey({ userIDs: [{ email: 'test@email.com' }], format: 'object' });
- expect(await isAEADSupported([key])).to.equal(openpgp.config.aeadProtect);
+ const { aeadAlgo } = await getPreferredCipherSuite([key], undefined, undefined, openpgp.config);
+ expect(!!aeadAlgo).to.equal(openpgp.config.aeadProtect);
const data = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: new Uint8Array(500) }), encryptionKeys: [key.toPublic()] });
const encrypted = data.substr(0, 500) + (data[500] === 'a' ? 'b' : 'a') + data.substr(501);
From 7e382e6e43d9867b3c3ccb3d04849743fde37b3a Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Fri, 17 Mar 2023 18:41:34 +0100
Subject: [PATCH 045/224] Add support for PKESK v6
Also, set version in PKESK constructor to null,
requiring to explicitly set all fields.
Co-authored-by: Lukas Burkhalter
---
src/crypto/crypto.js | 2 +-
src/message.js | 29 +++++--
src/openpgp.js | 2 +-
.../public_key_encrypted_session_key.js | 84 +++++++++++++++----
test/general/openpgp.js | 34 ++++++++
test/general/packet.js | 2 +
6 files changed, 124 insertions(+), 29 deletions(-)
diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js
index aa6e6f345..fa252a09f 100644
--- a/src/crypto/crypto.js
+++ b/src/crypto/crypto.js
@@ -121,7 +121,7 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
const { A } = publicKeyParams;
const { k } = privateKeyParams;
const { ephemeralPublicKey, C } = sessionKeyParams;
- if (!util.isAES(C.algorithm)) {
+ if (C.algorithm !== null && !util.isAES(C.algorithm)) {
throw new Error('AES session key expected');
}
return publicKey.elliptic.ecdhX.decrypt(
diff --git a/src/message.js b/src/message.js
index fac3eb96a..ce103022e 100644
--- a/src/message.js
+++ b/src/message.js
@@ -108,8 +108,6 @@ export class Message {
* @async
*/
async decrypt(decryptionKeys, passwords, sessionKeys, date = new Date(), config = defaultConfig) {
- const sessionKeyObjects = sessionKeys || await this.decryptSessionKeys(decryptionKeys, passwords, date, config);
-
const symEncryptedPacketlist = this.packets.filterByTag(
enums.packet.symmetricallyEncryptedData,
enums.packet.symEncryptedIntegrityProtectedData,
@@ -121,14 +119,18 @@ export class Message {
}
const symEncryptedPacket = symEncryptedPacketlist[0];
+ const expectedSymmetricAlgorithm = symEncryptedPacket.cipherAlgorithm;
+
+ const sessionKeyObjects = sessionKeys || await this.decryptSessionKeys(decryptionKeys, passwords, expectedSymmetricAlgorithm, date, config);
+
let exception = null;
const decryptedPromise = Promise.all(sessionKeyObjects.map(async ({ algorithm: algorithmName, data }) => {
- if (!util.isUint8Array(data) || !util.isString(algorithmName)) {
+ if (!util.isUint8Array(data) || (!symEncryptedPacket.cipherAlgorithm && !util.isString(algorithmName))) {
throw new Error('Invalid session key for decryption.');
}
try {
- const algo = enums.write(enums.symmetric, algorithmName);
+ const algo = symEncryptedPacket.cipherAlgorithm || enums.write(enums.symmetric, algorithmName);
await symEncryptedPacket.decrypt(algo, data, config);
} catch (e) {
util.printDebugError(e);
@@ -154,6 +156,7 @@ export class Message {
* Decrypt encrypted session keys either with private keys or passwords.
* @param {Array} [decryptionKeys] - Private keys with decrypted secret data
* @param {Array} [passwords] - Passwords used to decrypt
+ * @param {enums.symmetric} [expectedSymmetricAlgorithm] - The symmetric algorithm the SEIPDv2 / AEAD packet is encrypted with (if applicable)
* @param {Date} [date] - Use the given date for key verification, instead of current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise>} array of object with potential sessionKey, algorithm pairs
* @async
*/
- async decryptSessionKeys(decryptionKeys, passwords, date = new Date(), config = defaultConfig) {
+ async decryptSessionKeys(decryptionKeys, passwords, expectedSymmetricAlgorithm, date = new Date(), config = defaultConfig) {
let decryptedSessionKeyPackets = [];
let exception;
@@ -260,7 +263,8 @@ export class Message {
} else {
try {
await pkeskPacket.decrypt(decryptionKeyPacket);
- if (!algos.includes(enums.write(enums.symmetric, pkeskPacket.sessionKeyAlgorithm))) {
+ const symmetricAlgorithm = expectedSymmetricAlgorithm || pkeskPacket.sessionKeyAlgorithm;
+ if (symmetricAlgorithm && !algos.includes(enums.write(enums.symmetric, symmetricAlgorithm))) {
throw new Error('A non-preferred symmetric algorithm was used.');
}
decryptedSessionKeyPackets.push(pkeskPacket);
@@ -294,7 +298,7 @@ export class Message {
return decryptedSessionKeyPackets.map(packet => ({
data: packet.sessionKey,
- algorithm: enums.read(enums.symmetric, packet.sessionKeyAlgorithm)
+ algorithm: packet.sessionKeyAlgorithm && enums.read(enums.symmetric, packet.sessionKeyAlgorithm)
}));
}
throw exception || new Error('Session key decryption failed.');
@@ -350,7 +354,7 @@ export class Message {
await Promise.all(encryptionKeys.map(key => key.getEncryptionKey()
.catch(() => null) // ignore key strength requirements
.then(maybeKey => {
- if (maybeKey && (maybeKey.keyPacket.algorithm === enums.publicKey.x25519) && !util.isAES(symmetricAlgo)) {
+ if (maybeKey && (maybeKey.keyPacket.algorithm === enums.publicKey.x25519) && !aeadAlgoName && !util.isAES(symmetricAlgo)) { // if AEAD is defined, then PKESK v6 are used, and the algo info is encrypted
throw new Error('Could not generate a session key compatible with the given `encryptionKeys`: X22519 keys can only be used to encrypt AES session keys; change `config.preferredSymmetricAlgorithm` accordingly.');
}
})
@@ -430,7 +434,14 @@ export class Message {
const results = await Promise.all(encryptionKeys.map(async function(primaryKey, i) {
const encryptionKey = await primaryKey.getEncryptionKey(encryptionKeyIDs[i], date, userIDs, config);
const pkESKeyPacket = new PublicKeyEncryptedSessionKeyPacket();
- pkESKeyPacket.publicKeyID = wildcard ? KeyID.wildcard() : encryptionKey.getKeyID();
+ if (aeadAlgorithm) {
+ pkESKeyPacket.version = 6;
+ pkESKeyPacket.publicKeyVersion = wildcard ? 0 : encryptionKey.keyPacket.version;
+ pkESKeyPacket.publicKeyFingerprint = wildcard ? null : encryptionKey.keyPacket.getFingerprintBytes();
+ } else {
+ pkESKeyPacket.version = 3;
+ pkESKeyPacket.publicKeyID = wildcard ? KeyID.wildcard() : encryptionKey.getKeyID();
+ }
pkESKeyPacket.publicKeyAlgorithm = encryptionKey.keyPacket.algorithm;
pkESKeyPacket.sessionKey = sessionKey;
pkESKeyPacket.sessionKeyAlgorithm = algorithm;
diff --git a/src/openpgp.js b/src/openpgp.js
index 223ebfdf9..70dfd2406 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -591,7 +591,7 @@ export async function decryptSessionKeys({ message, decryptionKeys, passwords, d
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try {
- const sessionKeys = await message.decryptSessionKeys(decryptionKeys, passwords, date, config);
+ const sessionKeys = await message.decryptSessionKeys(decryptionKeys, passwords, undefined, date, config);
return sessionKeys;
} catch (err) {
throw util.wrapError('Error decrypting session keys', err);
diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js
index 231c62c76..02828b5ed 100644
--- a/src/packet/public_key_encrypted_session_key.js
+++ b/src/packet/public_key_encrypted_session_key.js
@@ -21,8 +21,6 @@ import enums from '../enums';
import util from '../util';
import { UnsupportedError } from './packet';
-const VERSION = 3;
-
/**
* Public-Key Encrypted Session Key Packets (Tag 1)
*
@@ -45,9 +43,16 @@ class PublicKeyEncryptedSessionKeyPacket {
}
constructor() {
- this.version = 3;
+ this.version = null;
+ // For version 3:
this.publicKeyID = new KeyID();
+
+ // For version 6:
+ this.publicKeyVersion = null;
+ this.publicKeyFingerprint = null;
+
+ // For all versions:
this.publicKeyAlgorithm = null;
this.sessionKey = null;
@@ -67,15 +72,39 @@ class PublicKeyEncryptedSessionKeyPacket {
* @param {Uint8Array} bytes - Payload of a tag 1 packet
*/
read(bytes) {
- let i = 0;
- this.version = bytes[i++];
- if (this.version !== VERSION) {
+ let offset = 0;
+ this.version = bytes[offset++];
+ if (this.version !== 3 && this.version !== 6) {
throw new UnsupportedError(`Version ${this.version} of the PKESK packet is unsupported.`);
}
- i += this.publicKeyID.read(bytes.subarray(i));
- this.publicKeyAlgorithm = bytes[i++];
- this.encrypted = crypto.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(i), this.version);
- if (this.publicKeyAlgorithm === enums.publicKey.x25519) {
+ if (this.version === 6) {
+ // A one-octet size of the following two fields:
+ // - A one octet key version number.
+ // - The fingerprint of the public key or subkey to which the session key is encrypted.
+ // The size may also be zero.
+ const versionAndFingerprintLength = bytes[offset++];
+ if (versionAndFingerprintLength) {
+ this.publicKeyVersion = bytes[offset++];
+ const fingerprintLength = versionAndFingerprintLength - 1;
+ this.publicKeyFingerprint = bytes.subarray(offset, offset + fingerprintLength); offset += fingerprintLength;
+ if (this.publicKeyVersion >= 5) {
+ // For v5/6 the Key ID is the high-order 64 bits of the fingerprint.
+ this.publicKeyID.read(this.publicKeyFingerprint);
+ } else {
+ // For v4 The Key ID is the low-order 64 bits of the fingerprint.
+ this.publicKeyID.read(this.publicKeyFingerprint.subarray(-8));
+ }
+ } else {
+ // The size may also be zero, and the key version and
+ // fingerprint omitted for an "anonymous recipient"
+ this.publicKeyID = KeyID.wildcard();
+ }
+ } else {
+ offset += this.publicKeyID.read(bytes.subarray(offset, offset + 8));
+ }
+ this.publicKeyAlgorithm = bytes[offset++];
+ this.encrypted = crypto.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(offset));
+ if (this.version === 3 && this.publicKeyAlgorithm === enums.publicKey.x25519) {
this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
}
}
@@ -87,11 +116,27 @@ class PublicKeyEncryptedSessionKeyPacket {
*/
write() {
const arr = [
- new Uint8Array([this.version]),
- this.publicKeyID.write(),
+ new Uint8Array([this.version])
+ ];
+
+ if (this.version === 6) {
+ if (this.publicKeyFingerprint !== null) {
+ arr.push(new Uint8Array([
+ this.publicKeyFingerprint.length + 1,
+ this.publicKeyVersion]
+ ));
+ arr.push(this.publicKeyFingerprint);
+ } else {
+ arr.push(new Uint8Array([0]));
+ }
+ } else {
+ arr.push(this.publicKeyID.write());
+ }
+
+ arr.push(
new Uint8Array([this.publicKeyAlgorithm]),
crypto.serializeParams(this.publicKeyAlgorithm, this.encrypted)
- ];
+ );
return util.concatUint8Array(arr);
}
@@ -131,7 +176,7 @@ class PublicKeyEncryptedSessionKeyPacket {
const { sessionKey, sessionKeyAlgorithm } = decodeSessionKey(this.version, this.publicKeyAlgorithm, decryptedData, randomSessionKey);
// v3 Montgomery curves have cleartext cipher algo
- if (this.publicKeyAlgorithm !== enums.publicKey.x25519) {
+ if (this.version === 3 && this.publicKeyAlgorithm !== enums.publicKey.x25519) {
this.sessionKeyAlgorithm = sessionKeyAlgorithm;
}
this.sessionKey = sessionKey;
@@ -149,7 +194,7 @@ function encodeSessionKey(version, keyAlgo, cipherAlgo, sessionKeyData) {
case enums.publicKey.ecdh: {
// add checksum
return util.concatUint8Array([
- new Uint8Array([cipherAlgo]),
+ new Uint8Array(version === 6 ? [] : [cipherAlgo]),
sessionKeyData,
util.writeChecksum(sessionKeyData.subarray(sessionKeyData.length % 8))
]);
@@ -173,7 +218,9 @@ function decodeSessionKey(version, keyAlgo, decryptedData, randomSessionKey) {
const checksum = decryptedData.subarray(decryptedData.length - 2);
const computedChecksum = util.writeChecksum(result.subarray(result.length % 8));
const isValidChecksum = computedChecksum[0] === checksum[0] & computedChecksum[1] === checksum[1];
- const decryptedSessionKey = { sessionKeyAlgorithm: result[0], sessionKey: result.subarray(1) };
+ const decryptedSessionKey = version === 6 ?
+ { sessionKeyAlgorithm: null, sessionKey: result } :
+ { sessionKeyAlgorithm: result[0], sessionKey: result.subarray(1) };
if (randomSessionKey) {
// We must not leak info about the validity of the decrypted checksum or cipher algo.
// The decrypted session key must be of the same algo and size as the random session key, otherwise we discard it and use the random data.
@@ -182,14 +229,15 @@ function decodeSessionKey(version, keyAlgo, decryptedData, randomSessionKey) {
decryptedSessionKey.sessionKey.length === randomSessionKey.sessionKey.length;
return {
sessionKey: util.selectUint8Array(isValidPayload, decryptedSessionKey.sessionKey, randomSessionKey.sessionKey),
- sessionKeyAlgorithm: util.selectUint8(
+ sessionKeyAlgorithm: version === 6 ? null : util.selectUint8(
isValidPayload,
decryptedSessionKey.sessionKeyAlgorithm,
randomSessionKey.sessionKeyAlgorithm
)
};
} else {
- const isValidPayload = isValidChecksum && enums.read(enums.symmetric, decryptedSessionKey.sessionKeyAlgorithm);
+ const isValidPayload = isValidChecksum && (
+ version === 6 || enums.read(enums.symmetric, decryptedSessionKey.sessionKeyAlgorithm));
if (isValidPayload) {
return decryptedSessionKey;
} else {
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 16a2c949e..69260be99 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1311,6 +1311,40 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
await expect(openpgp.decrypt(decOpt)).to.be.rejectedWith('Error decrypting message: Decryption key is not decrypted.');
});
+ it('should decrypt test vector X25519-AEAD-OCB (PKESK v6, SEIPDv2)', async function() {
+ // test vector https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.8
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
+WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
+aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
+yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
+bhF30A+IitsxxA==
+-----END PGP MESSAGE-----`;
+
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const { data: decryptedData } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage }),
+ decryptionKeys: privateKey
+ });
+
+ expect(decryptedData).to.equal('Hello, world!');
+ });
+
it('decrypt/verify should succeed with valid signature (expectSigned=true)', async function () {
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
const privateKey = await openpgp.decryptKey({
diff --git a/test/general/packet.js b/test/general/packet.js
index 11397a454..0e1cdaab0 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -474,6 +474,7 @@ export default () => describe('Packet', function() {
return crypto.generateParams(rsa, keySize, 65537).then(function({ publicParams, privateParams }) {
const enc = new openpgp.PublicKeyEncryptedSessionKeyPacket();
+ enc.version = 3;
const msg = new openpgp.PacketList();
const msg2 = new openpgp.PacketList();
@@ -523,6 +524,7 @@ export default () => describe('Packet', function() {
key = key[0];
const enc = new openpgp.PublicKeyEncryptedSessionKeyPacket();
+ enc.version = 3;
const secret = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
enc.sessionKey = secret;
From 0e08abb3e210231cabd7946f7a1d16a438761584 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Sat, 18 Mar 2023 00:30:30 +0100
Subject: [PATCH 046/224] When decrypting a v6 PKESK in constant-time, use the
v2 SEIPD algorithm
Rather than using the config to determine which algorithms to try
to decrypt session keys for, try the algorithm we know the message
was encrypted with.
---
src/message.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/message.js b/src/message.js
index ce103022e..44d69a1ce 100644
--- a/src/message.js
+++ b/src/message.js
@@ -243,7 +243,11 @@ export class Message {
// NB: as a result, if the data is encrypted with a non-suported cipher, decryption will always fail.
const serialisedPKESK = pkeskPacket.write(); // make copies to be able to decrypt the PKESK packet multiple times
- await Promise.all(Array.from(config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms).map(async sessionKeyAlgorithm => {
+ await Promise.all((
+ expectedSymmetricAlgorithm ?
+ [expectedSymmetricAlgorithm] :
+ Array.from(config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms)
+ ).map(async sessionKeyAlgorithm => {
const pkeskPacketCopy = new PublicKeyEncryptedSessionKeyPacket();
pkeskPacketCopy.read(serialisedPKESK);
const randomSessionKey = {
From 33af3debc41b7e04bcffb5037fdf23c002de1889 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 5 Apr 2023 00:53:04 +0200
Subject: [PATCH 047/224] Throw intelligible error on GCM authentication
failure, fix/refactor test for modification detection on decryption
Also, address race condition in error handling as part of AEAD message decryption,
which would cause non-uniform errors during testing.
---
src/crypto/mode/gcm.js | 10 +-
.../sym_encrypted_integrity_protected_data.js | 2 +
test/general/openpgp.js | 138 +++++++++++-------
3 files changed, 95 insertions(+), 55 deletions(-)
diff --git a/src/crypto/mode/gcm.js b/src/crypto/mode/gcm.js
index a3cbd941c..b482a5dc7 100644
--- a/src/crypto/mode/gcm.js
+++ b/src/crypto/mode/gcm.js
@@ -84,8 +84,14 @@ async function GCM(cipher, key) {
if (webcryptoEmptyMessagesUnsupported && ct.length === tagLength) {
return AES_GCM.decrypt(ct, key, iv, adata);
}
- const pt = await webCrypto.decrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength * 8 }, _key, ct);
- return new Uint8Array(pt);
+ try {
+ const pt = await webCrypto.decrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength * 8 }, _key, ct);
+ return new Uint8Array(pt);
+ } catch (e) {
+ if (e.name === 'OperationError') {
+ throw new Error('Authentication tag mismatch');
+ }
+ }
}
};
} catch (err) {
diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js
index 3f462c905..1718e214e 100644
--- a/src/packet/sym_encrypted_integrity_protected_data.js
+++ b/src/packet/sym_encrypted_integrity_protected_data.js
@@ -260,6 +260,7 @@ export async function runAEAD(packet, fn, key, data) {
if (!chunkIndex || chunk.length) {
reader.unshift(finalChunk);
cryptedPromise = modeInstance[fn](chunk, nonce, adataArray);
+ cryptedPromise.catch(() => {});
queuedBytes += chunk.length - tagLengthIfDecrypting + tagLengthIfEncrypting;
} else {
// After the last chunk, we either encrypt a final, empty
@@ -267,6 +268,7 @@ export async function runAEAD(packet, fn, key, data) {
// validate that final authentication tag.
adataView.setInt32(5 + chunkIndexSizeIfAEADEP + 4, cryptedBytes); // Should be setInt64(5 + chunkIndexSizeIfAEADEP, ...)
cryptedPromise = modeInstance[fn](finalChunk, nonce, adataTagArray);
+ cryptedPromise.catch(() => {});
queuedBytes += tagLengthIfEncrypting;
done = true;
}
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 69260be99..98c6a3c67 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -15,7 +15,6 @@ import { getPreferredCipherSuite } from '../../src/key';
import * as input from './testInputs.js';
-const detectNode = () => typeof globalThis.process === 'object' && typeof globalThis.process.versions === 'object';
const detectBrowser = () => typeof navigator === 'object';
const pub_key = [
@@ -2331,7 +2330,7 @@ XfA3pqV4mTzF
if: true,
beforeEach: function() {
openpgp.config.aeadProtect = true;
- openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM;
+ openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.gcm;
openpgp.config.v6Keys = true;
// Monkey-patch SEIPD V2 feature flag
@@ -2346,6 +2345,7 @@ XfA3pqV4mTzF
beforeEach: function() {
openpgp.config.aeadProtect = true;
openpgp.config.aeadChunkSizeByte = 0;
+ openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax;
// Monkey-patch SEIPD V2 feature flag
publicKey.users[0].selfCertifications[0].features = [9];
@@ -2355,7 +2355,7 @@ XfA3pqV4mTzF
});
tryTests('OCB mode', tests, {
- if: !openpgp.config.ci,
+ if: true,
beforeEach: function() {
openpgp.config.aeadProtect = true;
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb;
@@ -3086,60 +3086,92 @@ XfA3pqV4mTzF
});
it('should fail to decrypt modified message', async function() {
- const allowUnauthenticatedStream = openpgp.config.allowUnauthenticatedStream;
- const { privateKey: key } = await openpgp.generateKey({ userIDs: [{ email: 'test@email.com' }], format: 'object' });
- const { aeadAlgo } = await getPreferredCipherSuite([key], undefined, undefined, openpgp.config);
- expect(!!aeadAlgo).to.equal(openpgp.config.aeadProtect);
-
- const data = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: new Uint8Array(500) }), encryptionKeys: [key.toPublic()] });
- const encrypted = data.substr(0, 500) + (data[500] === 'a' ? 'b' : 'a') + data.substr(501);
await loadStreamsPolyfill();
- try {
- for (const allowStreaming of [true, false]) {
- openpgp.config.allowUnauthenticatedStream = allowStreaming;
- for (const [i, encryptedData] of [
- encrypted,
- new ReadableStream({
- start(controller) {
- controller.enqueue(encrypted);
- controller.close();
- }
- }),
- new ReadableStream({
- start() {
- this.remaining = encrypted.split('\n');
- },
- async pull(controller) {
- if (this.remaining.length) {
- await new Promise(res => setTimeout(res));
- controller.enqueue(this.remaining.shift() + '\n');
- } else {
- controller.close();
- }
- }
- })
- ].entries()) {
- let stepReached = 0;
- try {
- const message = await openpgp.readMessage({ armoredMessage: encryptedData });
- stepReached = 1;
- const { data: decrypted } = await openpgp.decrypt({ message: message, decryptionKeys: [key] });
- stepReached = 2;
- await stream.readToEnd(decrypted);
- } catch (e) {
- expect(e.message).to.match(/Modification detected|Authentication tag mismatch|Unsupported state or unable to authenticate data/);
- expect(stepReached).to.equal(
- i === 0 ? 1 :
- (openpgp.config.aeadChunkSizeByte === 0 && (i === 2 || detectNode() || util.getHardwareConcurrency() < 8)) || (!openpgp.config.aeadProtect && openpgp.config.allowUnauthenticatedStream) ? 2 :
- 1
- );
- continue;
+ // need to generate new key with AEAD support
+ const { privateKey } = await openpgp.generateKey({ userIDs: [{ email: 'test@email.com' }], type: 'rsa', format: 'object' });
+ const { aeadAlgo } = await getPreferredCipherSuite([privateKey], undefined, undefined, openpgp.config);
+ // sanity check
+ expect(aeadAlgo).to.equal(openpgp.config.aeadProtect ? openpgp.config.preferredAEADAlgorithm : undefined);
+
+ const encrypted = await openpgp.encrypt({
+ message: await openpgp.createMessage({ binary: new Uint8Array(500) }),
+ encryptionKeys: privateKey
+ });
+ // corrupt the SEIPD packet
+ const encryptedCorrupted = encrypted.substr(0, 1000) + (encrypted[1000] === 'a' ? 'b' : 'a') + encrypted.substr(1001);
+
+ const generateSingleChunkStream = () => (
+ new ReadableStream({
+ start(controller) {
+ controller.enqueue(encryptedCorrupted);
+ controller.close();
+ }
+ })
+ );
+ const generateMultiChunkStream = () => (
+ new ReadableStream({
+ start() {
+ this.remaining = encryptedCorrupted.split('\n');
+ },
+ async pull(controller) {
+ if (this.remaining.length) {
+ // sleep to slow down enqeueing
+ await new Promise(resolve => { setTimeout(resolve); });
+ controller.enqueue(this.remaining.shift() + '\n');
+ } else {
+ controller.close();
}
- throw new Error(`Expected "Modification detected" error in subtest ${i}`);
}
+ })
+ );
+
+ if (openpgp.config.aeadProtect) {
+ const expectedError = /Authentication tag mismatch|Unsupported state or unable to authenticate data/;
+ // AEAD fails either on AEAD chunk decryption or when reading the decrypted stream:
+ // if the corruption is in the first AEAD chunk, then `openpgp.decrypt` will throw
+ // when reading the decrypted stream to parse the packet list.
+ await Promise.all([
+ testStreamingDecryption(encryptedCorrupted, true, expectedError, true),
+ testStreamingDecryption(encryptedCorrupted, false, expectedError, true),
+ // `config.allowUnauthenticatedStream` does not apply to AEAD
+ testStreamingDecryption(generateSingleChunkStream(), true, expectedError, openpgp.config.aeadChunkSizeByte > 0),
+ testStreamingDecryption(generateSingleChunkStream(), false, expectedError, openpgp.config.aeadChunkSizeByte > 0),
+ // Increasing number of streaming chunks should not affect the result
+ testStreamingDecryption(generateMultiChunkStream(), true, expectedError, openpgp.config.aeadChunkSizeByte > 0),
+ testStreamingDecryption(generateMultiChunkStream(), false, expectedError, openpgp.config.aeadChunkSizeByte > 0)
+ ]);
+ } else {
+ const expectedError = /Modification detected/;
+ await Promise.all([
+ testStreamingDecryption(encryptedCorrupted, true, expectedError, true),
+ testStreamingDecryption(encryptedCorrupted, false, expectedError, true),
+ testStreamingDecryption(generateSingleChunkStream(), true, expectedError, false),
+ testStreamingDecryption(generateSingleChunkStream(), false, expectedError, true),
+ // Increasing number of streaming chunks should not affect the result
+ testStreamingDecryption(generateMultiChunkStream(), true, expectedError, false),
+ testStreamingDecryption(generateMultiChunkStream(), false, expectedError, true)
+ ]);
+ }
+
+ async function testStreamingDecryption(encryptedDataOrStream, allowUnauthenticatedStream, expectedErrorMessage, expectedFailureOnDecrypt = null) {
+ // parsing the message won't fail since armor checksum is ignored
+ const message = await openpgp.readMessage({ armoredMessage: encryptedDataOrStream });
+ let didFailOnDecrypt = true;
+
+ try {
+ const { data: decrypted } = await openpgp.decrypt({
+ message,
+ decryptionKeys: [privateKey],
+ config: { allowUnauthenticatedStream }
+ });
+ didFailOnDecrypt = false;
+ await stream.readToEnd(decrypted);
+ // expected to have thrown
+ throw new Error(`Expected decryption to fail with error ${expectedErrorMessage}`);
+ } catch (e) {
+ expect(e.message).to.match(expectedErrorMessage);
+ expect(didFailOnDecrypt).to.equal(expectedFailureOnDecrypt);
}
- } finally {
- openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStream;
}
});
From 21343f2bb8b4be159d1b6da57e539af712336019 Mon Sep 17 00:00:00 2001
From: Daniel Huigens
Date: Thu, 6 Apr 2023 11:57:50 +0200
Subject: [PATCH 048/224] Appease linter
---
src/encoding/armor.js | 23 ++++++++-----------
src/message.js | 4 ++--
src/packet/padding.js | 2 +-
.../sym_encrypted_integrity_protected_data.js | 2 +-
4 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/src/encoding/armor.js b/src/encoding/armor.js
index daff2d4d9..0e0aa5aed 100644
--- a/src/encoding/armor.js
+++ b/src/encoding/armor.js
@@ -128,24 +128,21 @@ function verifyHeaders(headers) {
}
/**
- * Splits a message into two parts, the body and the checksum. This is an internal function
- * @param {String} text - OpenPGP armored message part
- * @returns {Object} An object with attribute "body" containing the body.
- * and an attribute "checksum" containing the checksum.
+ * Remove the (optional) checksum from an armored message.
+ * @param {String} text - OpenPGP armored message
+ * @returns {String} The body of the armored message.
* @private
*/
-function splitChecksum(text) {
+function removeChecksum(text) {
let body = text;
- let checksum = '';
const lastEquals = text.lastIndexOf('=');
if (lastEquals >= 0 && lastEquals !== text.length - 1) { // '=' as the last char means no checksum
body = text.slice(0, lastEquals);
- checksum = text.slice(lastEquals + 1).substr(0, 4);
}
- return { body: body, checksum: checksum };
+ return body;
}
/**
@@ -157,7 +154,7 @@ function splitChecksum(text) {
* @async
* @static
*/
-export function unarmor(input, config = defaultConfig) {
+export function unarmor(input) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
@@ -170,8 +167,7 @@ export function unarmor(input, config = defaultConfig) {
let headersDone;
let text = [];
let textDone;
- let checksum;
- let data = base64.decode(stream.transformPair(input, async (readable, writable) => {
+ const data = base64.decode(stream.transformPair(input, async (readable, writable) => {
const reader = stream.getReader(readable);
try {
while (true) {
@@ -236,9 +232,8 @@ export function unarmor(input, config = defaultConfig) {
if (parts.length === 1) {
throw new Error('Misformed armored text');
}
- const split = splitChecksum(parts[0].slice(0, -1));
- checksum = split.checksum;
- await writer.write(split.body);
+ const body = removeChecksum(parts[0].slice(0, -1));
+ await writer.write(body);
break;
}
}
diff --git a/src/message.js b/src/message.js
index 44d69a1ce..2ce9f6273 100644
--- a/src/message.js
+++ b/src/message.js
@@ -245,8 +245,8 @@ export class Message {
const serialisedPKESK = pkeskPacket.write(); // make copies to be able to decrypt the PKESK packet multiple times
await Promise.all((
expectedSymmetricAlgorithm ?
- [expectedSymmetricAlgorithm] :
- Array.from(config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms)
+ [expectedSymmetricAlgorithm] :
+ Array.from(config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms)
).map(async sessionKeyAlgorithm => {
const pkeskPacketCopy = new PublicKeyEncryptedSessionKeyPacket();
pkeskPacketCopy.read(serialisedPKESK);
diff --git a/src/packet/padding.js b/src/packet/padding.js
index b60e1e4b3..567ef2e58 100644
--- a/src/packet/padding.js
+++ b/src/packet/padding.js
@@ -37,7 +37,7 @@ class PaddingPacket {
* Read a padding packet
* @param {Uint8Array | ReadableStream} bytes
*/
- read(bytes) {
+ read(bytes) { // eslint-disable-line no-unused-vars
// Padding packets are ignored, so this function is never called.
}
diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js
index 1718e214e..8aedf18d3 100644
--- a/src/packet/sym_encrypted_integrity_protected_data.js
+++ b/src/packet/sym_encrypted_integrity_protected_data.js
@@ -72,7 +72,7 @@ class SymEncryptedIntegrityProtectedDataPacket {
this.version = await reader.readByte();
// - A one-octet version number with value 1 or 2.
if (this.version !== 1 && this.version !== 2) {
- throw new UnsupportedError(`Version ${version} of the SEIP packet is unsupported.`);
+ throw new UnsupportedError(`Version ${this.version} of the SEIP packet is unsupported.`);
}
if (this.version === 2) {
From 95fd04db8e13a157c1115fbfc3b6fcde5100dba0 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 6 Apr 2023 18:00:14 +0200
Subject: [PATCH 049/224] Support AEAD encryption for v4 and v6 private keys
---
src/packet/secret_key.js | 80 ++++++++++++++----
test/general/key.js | 171 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 233 insertions(+), 18 deletions(-)
diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js
index d3e8616f9..dc5b853d2 100644
--- a/src/packet/secret_key.js
+++ b/src/packet/secret_key.js
@@ -21,7 +21,8 @@ import crypto from '../crypto';
import enums from '../enums';
import util from '../util';
import defaultConfig from '../config';
-import { UnsupportedError } from './packet';
+import { UnsupportedError, writeTag } from './packet';
+import computeHKDF from '../crypto/hkdf';
/**
* A Secret-Key packet contains all the information that is found in a
@@ -140,14 +141,27 @@ class SecretKeyPacket extends PublicKeyPacket {
this.symmetric = this.s2kUsage;
}
- // - [Optional] If secret data is encrypted (string-to-key usage octet
- // not zero), an Initial Vector (IV) of the same length as the
- // cipher's block size.
+
if (this.s2kUsage) {
- this.iv = bytes.subarray(
- i,
- i + crypto.getCipher(this.symmetric).blockSize
- );
+ // - crypto-refresh: If string-to-key usage octet was 255, 254 [..], an initialization vector (IV)
+ // of the same length as the cipher's block size.
+ // - RFC4880bis (v5 keys, regardless of AEAD): an Initial Vector (IV) of the same length as the
+ // cipher's block size. If string-to-key usage octet was 253 the IV is used as the nonce for the AEAD algorithm.
+ // If the AEAD algorithm requires a shorter nonce, the high-order bits of the IV are used and the remaining bits MUST be zero
+ if (this.s2kUsage !== 253 || this.version === 5) {
+ this.iv = bytes.subarray(
+ i,
+ i + crypto.getCipher(this.symmetric).blockSize
+ );
+ } else {
+ // crypto-refresh: If string-to-key usage octet was 253 (that is, the secret data is AEAD-encrypted),
+ // an initialization vector (IV) of size specified by the AEAD algorithm (see Section 5.13.2), which
+ // is used as the nonce for the AEAD algorithm.
+ this.iv = bytes.subarray(
+ i,
+ i + crypto.getAEADMode(this.aead).ivLength
+ );
+ }
i += this.iv.length;
}
@@ -342,19 +356,28 @@ class SecretKeyPacket extends PublicKeyPacket {
this.s2k.generateSalt();
const cleartext = crypto.serializeParams(this.algorithm, this.privateParams);
this.symmetric = enums.symmetric.aes256;
- const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
const { blockSize } = crypto.getCipher(this.symmetric);
- this.iv = crypto.random.getRandomBytes(blockSize);
if (config.aeadProtect) {
this.s2kUsage = 253;
this.aead = enums.aead.eax;
const mode = crypto.getAEADMode(this.aead);
+
+ const serializedPacketTag = writeTag(this.constructor.tag);
+ const key = await produceEncryptionKey(this.version, this.s2k, passphrase, this.symmetric, this.aead, serializedPacketTag);
+
const modeInstance = await mode(this.symmetric, key);
- this.keyMaterial = await modeInstance.encrypt(cleartext, this.iv.subarray(0, mode.ivLength), new Uint8Array());
+ this.iv = (this.version === 5) ? crypto.random.getRandomBytes(blockSize) : crypto.random.getRandomBytes(mode.ivLength);
+ const associateData = this.version === 5 ?
+ new Uint8Array() :
+ util.concatUint8Array([serializedPacketTag, this.writePublicKey()]);
+
+ this.keyMaterial = await modeInstance.encrypt(cleartext, this.iv.subarray(0, mode.ivLength), associateData);
} else {
this.s2kUsage = 254;
+ const key = await produceEncryptionKey(this.version, this.s2k, passphrase, this.symmetric);
+ this.iv = crypto.random.getRandomBytes(blockSize);
this.keyMaterial = await crypto.mode.cfb.encrypt(this.symmetric, key, util.concatUint8Array([
cleartext,
await crypto.hash.sha1(cleartext, config)
@@ -385,8 +408,10 @@ class SecretKeyPacket extends PublicKeyPacket {
}
let key;
+ const serializedPacketTag = writeTag(this.constructor.tag); // relevant for AEAD only
if (this.s2kUsage === 254 || this.s2kUsage === 253) {
- key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
+ key = await produceEncryptionKey(
+ this.version, this.s2k, passphrase, this.symmetric, this.aead, serializedPacketTag);
} else if (this.s2kUsage === 255) {
throw new Error('Encrypted private key is authenticated using an insecure two-byte hash');
} else {
@@ -398,7 +423,10 @@ class SecretKeyPacket extends PublicKeyPacket {
const mode = crypto.getAEADMode(this.aead);
const modeInstance = await mode(this.symmetric, key);
try {
- cleartext = await modeInstance.decrypt(this.keyMaterial, this.iv.subarray(0, mode.ivLength), new Uint8Array());
+ const associateData = this.version === 5 ?
+ new Uint8Array() :
+ util.concatUint8Array([serializedPacketTag, this.writePublicKey()]);
+ cleartext = await modeInstance.decrypt(this.keyMaterial, this.iv.subarray(0, mode.ivLength), associateData);
} catch (err) {
if (err.message === 'Authentication tag mismatch') {
throw new Error('Incorrect key passphrase: ' + err.message);
@@ -425,6 +453,8 @@ class SecretKeyPacket extends PublicKeyPacket {
this.isEncrypted = false;
this.keyMaterial = null;
this.s2kUsage = 0;
+ this.aead = null;
+ this.symmetric = null;
}
/**
@@ -478,9 +508,27 @@ class SecretKeyPacket extends PublicKeyPacket {
}
}
-async function produceEncryptionKey(s2k, passphrase, algorithm) {
- const { keySize } = crypto.getCipher(algorithm);
- return s2k.produceKey(passphrase, keySize);
+/**
+ * Derive encryption key
+ * @param {Number} keyVersion - key derivation differs for v5 keys
+ * @param {module:type/s2k} s2k
+ * @param {String} passphrase
+ * @param {module:enums.symmetric} cipherAlgo
+ * @param {module:enums.aead} [aeadMode] - for AEAD-encrypted keys only (excluding v5)
+ * @param {Uint8Array} serializedPacketTag - for AEAD-encrypted keys only (excluding v5)
+ * @returns encryption key
+ */
+async function produceEncryptionKey(keyVersion, s2k, passphrase, cipherAlgo, aeadMode, serializedPacketTag) {
+ const { keySize } = crypto.getCipher(cipherAlgo);
+ const derivedKey = await s2k.produceKey(passphrase, keySize);
+ if (!aeadMode || keyVersion === 5) {
+ return derivedKey;
+ }
+ const info = util.concatUint8Array([
+ serializedPacketTag,
+ new Uint8Array([keyVersion, cipherAlgo, aeadMode])
+ ]);
+ return computeHKDF(enums.hash.sha256, derivedKey, new Uint8Array(), info, keySize);
}
export default SecretKeyPacket;
diff --git a/test/general/key.js b/test/general/key.js
index 9ed68d979..68d956d5f 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -4,6 +4,7 @@ import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);
+import sinon from 'sinon';
import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
import { getPreferredCipherSuite } from '../../src/key';
@@ -2912,7 +2913,7 @@ export default () => describe('Key', function() {
let aeadProtectVal;
tryTests('V4', versionSpecificTests, {
- if: !openpgp.config.ci,
+ if: true,
beforeEach: function() {
v6KeysVal = openpgp.config.v6Keys;
openpgp.config.v6Keys = false;
@@ -2923,7 +2924,7 @@ export default () => describe('Key', function() {
});
tryTests('V6', versionSpecificTests, {
- if: !openpgp.config.ci,
+ if: true,
beforeEach: function() {
v6KeysVal = openpgp.config.v6Keys;
aeadProtectVal = openpgp.config.aeadProtect;
@@ -2987,6 +2988,172 @@ export default () => describe('Key', function() {
expect(key).to.exist;
});
+ it('Parsing, decrypting, encrypting and serializing V5 key (AEAD-encrypted)', async function() {
+ const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYwFZC7tvxYAAAAtCSsGAQQB2kcPAQEHQP/d1oBAqCKZYxb6k8foyX2Aa/VK
+dHFymZPGvHRk1ncs/R0JAQMIrDnS3Bany9EAF6dwQSfPSdObc4ROYIMAnwAA
+ADKV1OhGzwANnapimvODI6fK5F7/V0GxETY9WmnipnBzr4Fe9GZw4QD4Q4hd
+IJMawjUBrs0MdjVAYWVhZC50ZXN0wpIFEBYKAEQFgmQu7b8ECwkHCAMVCAoE
+FgACAQIZAQKbAwIeByKhBQ/Y89PNwfdXUdI/td5Q9rNrYP9mb7Dg6k/3nxTg
+ugQ5AyIBAgAAf0kBAJv0OQvd4u8R0f3HAsmQeqMnwNA4or75BOn/ieApNZUt
+AP9kQVmYEk4+MV57Us15l2kQEslLDr3qiH5+VCICdEprB8eRBWQu7b8SAAAA
+MgorBgEEAZdVAQUBAQdA4IgEkfze3eNKRz6DgzGSJxw/CV/5Rp5u4Imn47h7
+pyADAQgH/R0JAQMIwayD3R4E0ugAyszSmOIpaLJ40YGBp5uU7wAAADKmSv4W
+tio7GfZCVl8eJ7xX3J1b0iMvEm876tUeHANQlYYCWz+2ahmPVe79zzZA9OhN
+FcJ6BRgWCAAsBYJkLu2/ApsMIqEFD9jz083B91dR0j+13lD2s2tg/2ZvsODq
+T/efFOC6BDkAAHcjAPwIPNHnR9bKmkVop6cE05dCIpZ/W8zXDGnjKYrrC4Hb
+4gEAmISD1GRkNOmCV8aHwN5svO6HuwXR4cR3o3l7HlYeag8=
+=wpkQ
+-----END PGP PRIVATE KEY BLOCK-----`;
+ const passphrase = 'password';
+ const encryptedKey = await openpgp.readKey({ armoredKey });
+ const decryptedKey = await openpgp.decryptKey({
+ privateKey: encryptedKey,
+ passphrase
+ });
+ const reecryptedKey = await openpgp.encryptKey({
+ privateKey: decryptedKey,
+ passphrase,
+ config: { aeadProtect: true }
+ });
+ expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
+ const redecryptedKey = await openpgp.decryptKey({
+ privateKey: reecryptedKey,
+ passphrase
+ });
+ expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
+ });
+
+ it('Parsing, decrypting, encrypting and serializing V4 key (AEAD-encrypted)', async function() {
+ // key from gopenpgp
+ const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xcMIBGQuuRABCADm+/vQI1Memff31qyXxdB4Z14hnF+Bu7RirXpYNjM07CcGTDdT
+vj1AmZNR0o3G1vvbAUp2jWxquWq+8C//NJn13Axrg3R599j3+1TL+9vlwmgSJJdT
+SjQkSUjlkJpZQJPfkk0tngLBQGwlEJJLOlnWLfCc1eTh5x/cjO5E/jOOHwSHNgBp
+mhpKO/k6bAdgyB6jAYOJKI6TZE0JNc2+ZGSjr5EdwEs8sGDT2nMgn3oectuZO4y8
+tmFzNvAY9oQD0T4wmqwZ8evzlgRkCMRrdKCCdHfYdluQuRJb2WOWoV03PRaPfRQS
+k2SiNSKYhQF2tnybd1BgnAiPcwa4dJtn1IWrABEBAAH9BwME1X5xBykUBjyv9kd4
+gx/UewMEEHfi7UejYVJhtGf63vgzp98C00CiDkYbCJXh2Io4Pro1lP7J75hm7zyf
+1VuNQbd8dx2IEcig8OpF+tlH14U+YexVrbm1rX/vBg0BZrqO87HU+ILiZFpGV/tF
+9GeLPBLLCyIqvb/PzP0hiqEHP84xBkIIOEY+PZJoXGpfA7TUNsGpVS9ySpGWxCny
+nsjv9Lnv2NVtfaaA8YoQl7GJbI/Qh9wx/wtiqE8sVuH9ddFdFGSvjhrLSu58jPIv
+9SBdMjI/WHVlqVXkAXpEPBlmpn4xgffW3HDAx19YuwHEVjrsLUISBi1PodfAieT/
+cdtqejiFLQv8zQkTOz/J59yUy+OUZ3SKBM3vRPf0lxSUAoNNYrvg0gNd6qpCNChN
+z7LjNkUjgDp0DorPtTLT4FS/O/kB25K69CxkUeOyk3i+p3fqr/9wz0gFpRW5pkLa
+Hi3T5gjT4O1kTyGeoetGKwbdzfLisc981ynqKhlLdBw0R0hMpalak3NOf3QUjZEu
+10TFHhGUuCJVNbluQwVSD9e5znu5IBxawo8yHcV8OEIcc8wS1TuJer/cWj9zf/3Y
+C/l5Gngwa99YE8nrZdhKlra0viiAvpPqJs61pOzGj5NoKoEPDWB26TpbrPGFyKu6
+EY8Uz1SNo+Zn42w1g4KTA2x4LPdyblYlea5RRqodqot9hgRMVy758QwMBmoLzwn3
+sSOZeasCF5pw4a1Trr+Qupy0N+TyoCvt7hlP3qt12+8Y7ObB5hAk9YHlWB/mXeGK
+APA0n6o2eTKBrXcjAk600nn30BH93GQ88LxwPsF2IKcwqf8sBlm3IPzmQUbGTtfr
+lcm7PTipnN9NyGZrimbS9Eujp6IEAQGsPT9VqWBf2xM18kLnkYWO3Q+iQxhoyeHU
+R+SpZ3rzZ7dqJKzNF2R1bW15IDxkdW1teUB0ZXN0LnRlc3Q+wsCLBBMBCAA/BQJk
+LrkQCZD/Lbr4zUX6OxYhBEJ8H0lz9aZ8pbX+hP8tuvjNRfo7AhsDAh4JAhkBAgsH
+AhUIAhYABScHAwcCAAA3RAgA2+RQ/U9FYhTghvU/2r/SDiL1BRA+TOOwDKyxLKKm
+J9j/f/GSon74YqZmWSZTWLgDxXGXO0+I9Mz029qEs/tQTcFrulJcxY6V5B6ci+Wv
+J9+7A4UDz7wk30jb0FKT6NDhw/w2UbI5tf9aUY+iKxqcvDI3zBL3AMkILPKK+kXw
+dq5DvbRIh3oUcD3+xhEnlkBWbB9oUcQC0QdC9bHdPNTPGNJLQozo+cSq/VMYn5Bj
+RPJQSoSA6BJa4omdNi1GkVoYNmnBVi8W+DnqgwwOxOhlbTRHyhoKC8pbGC/ty/qd
+HLWrGbFXOcl1cVio85zT74q98v+tL6CEKDHTire1tbKhy8fDCARkLrkQAQgAwbzO
+crec+eXvoxyL/woFffGBKoMICXFGYiZvd0mI7iMYDRy2oVBIZuT5fAorSfc8PUYS
+lljlV7LP9WW1/IA9oPRSTj0bywqZrxRVaIzBqoXNtpujnyPpFHDzubxkNr+WcbmQ
+KufphQMolp2p0LQ7C6c6ssAKS6ue8mNJ1KRvdvRXMUqop+fGaEKoec+PgRUwIKDq
+sLVAzGtGkJTC2J0w9673ZzxlbejHj/g/eEHFSwTm92E2q2UbSoJLV7dtpAR4y1i3
+GTZSNsPm3Wngn4C8AQtuZyqcFJiTvcrMJDptRsQ9pwkyDquEd0fsJel5pY1WQiXr
+g4UZDLQ4QmIIwFdbnwARAQAB/QcDBOMwz+uO8Knhstz1WDIJvPoDBBA+WqgPij7y
+RQz9nTftmWIPUVvrOC49h66Smv3eDVikCq2ibFj6znpvDZgp7LWly0OAfHLHf/qg
+4x7ld0miXTSe4ZeCTo2qsh8gKqqW/CLgSgnixSjdyyqHBLvCS3dPbwrjjeI+qPuS
+EcuDzRqDhwfs6eUCei2lDwOYlm69WkT73Ll2EoJUZOVkxrqHkfY5hakQZbMBy6gs
+VqCzaLOaqHaBrg6c2KqWEZ6WB2KasT/p5fuW+aoYqNbQibmic1H1ETGjnUlVWhwf
+4aySRvbaTw3DzJXduZsJEQSq2Dv04JM/InxZEvh+FLXluccv6Os6MqZnKEST/e7f
+zL6G4zphIFecrOqvvl/ej1UlOXCqUfOn3Srsy8AjLOvPJJ13VBPFo6Lz+P+5RcUX
+VauY/vepsjecrcY2BaANct6BNdL0rgRkoT2HZ2g8snvWl+UVTZnwsjnwEZYYazrK
+C6woDti14bn0Mc71kaeNTog0FU/nqfP1exMiV87H+EU04XcyGn8b0oSSI3DcEDau
+SV9qwksQcqF28fDbQz5h9UsEdWjjSYQmNpF4Iow6t18buspqSRbEZXap8Vt5tLAr
+9t1CV9vIKNMU7JIodZngUxITMZYZyVHHbTidu3rzv9ojsAMvFElr590yIk8FPsDD
+m3vnKlNHT7B8/irI8gyhLGlF+mwGEROM1PSeNNq6ufV74DWh0C4RpdzLfgzd8AqL
+bxX1kOOzC6kVjwa8lCowMRS4d9Kah8jRoOgx9Az/GSJ2ODBXYGGcOwF1ERDU8P7i
+IsAVjFZ2OeC5E36MHSiP60rRe4i/NGJOgY6pY3mwTdCFtUdnRv6ASc6k4TOQGMup
+xgGFJ0ph68AtRheZ0IdN/VXMQfseyzufb5bq0Yc3yb9spogH7sY4IplxvEtMwsB2
+BBgBCAAqBQJkLrkQCZD/Lbr4zUX6OxYhBEJ8H0lz9aZ8pbX+hP8tuvjNRfo7AhsM
+AABaJgf/dTX0lJCphR9DlppTFNhcwOdtmvJf9CPP8+vHpPjyL5fiB4wDPCU1C7x1
+ku/QS00EKIpPP1EbDUsY0jIN7IV24x0eQcAswIV1F63Bzfft1rWZsA5iiZms1bgh
+AEA3Kv2Xh7DUaiykaXvbtyfCI6pX+MgMZsLqVhFEH/5lq+dlYc8UyM7IE3LNWYj3
+Uluz+3GjCdLZ8FVJVTrRZz8wR8HDlcPdC60gqnnx6QQ4rmzYoivK0Rf/4LLjujOc
+VjyzpPJS+t/gabeMRho7vChSge603d227AKpJtQnfUKN3mjN1i/XQ3iIFlVAGlGA
+oZIvKIVq9Vqf8XJVjMDbRMNTmh3a5A==
+-----END PGP PRIVATE KEY BLOCK-----`;
+ const passphrase = 'password';
+ const encryptedKey = await openpgp.readKey({ armoredKey });
+ const decryptedKey = await openpgp.decryptKey({
+ privateKey: encryptedKey,
+ passphrase
+ });
+ const reecryptedKey = await openpgp.encryptKey({
+ privateKey: decryptedKey,
+ passphrase,
+ config: { aeadProtect: true }
+ });
+ expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
+ const redecryptedKey = await openpgp.decryptKey({
+ privateKey: reecryptedKey,
+ passphrase
+ });
+ expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
+ });
+
+ it('Parsing, decrypting, encrypting and serializing V6 key (AEAD-encrypted)', async function() {
+ // official test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.5
+ const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYIGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laP9JgkC
+FARdb9ccngltHraRe25uHuyuAQQVtKipJ0+r5jL4dacGWSAheCWPpITYiyfyIOPS
+3gIDyg8f7strd1OB4+LZsUhcIjOMpVHgmiY/IutJkulneoBYwrEGHxsKAAAAQgWC
+Y4d/4wMLCQcFFQoOCAwCFgACmwMCHgkiIQbLGGxPBgmml+TVLfpscisMHx4nwYpW
+cI9lJewnutmsyQUnCQIHAgAAAACtKCAQPi19In7A5tfORHHbNr/JcIMlNpAnFJin
+7wV2wH+q4UWFs7kDsBJ+xP2i8CMEWi7Ha8tPlXGpZR4UruETeh1mhELIj5UeM8T/
+0z+5oX1RHu11j8bZzFDLX9eTsgOdWATHggZjh3/jGQAAACCGkySDZ/nlAV25Ivj0
+gJXdp4SYfy1ZhbEvutFsr15ENf0mCQIUBA5hhGgp2oaavg6mFUXcFMwBBBUuE8qf
+9Ock+xwusd+GAglBr5LVyr/lup3xxQvHXFSjjA2haXfoN6xUGRdDEHI6+uevKjVR
+v5oAxgu7eJpaXNjCmwYYGwoAAAAsBYJjh3/jApsMIiEGyxhsTwYJppfk1S36bHIr
+DB8eJ8GKVnCPZSXsJ7rZrMkAAAAABAEgpukYbZ1ZNfyP5WMUzbUnSGpaUSD5t2Ki
+Nacp8DkBClZRa2c3AMQzSDXa9jGhYzxjzVb5scHDzTkjyRZWRdTq8U6L4da+/+Kt
+ruh8m7Xo2ehSSFyWRSuTSZe5tm/KXgYG
+-----END PGP PRIVATE KEY BLOCK-----`;
+ const passphrase = 'correct horse battery staple';
+ const encryptedKey = await openpgp.readKey({ armoredKey });
+
+ // avoid argon2's expensive computation
+ const stubArgon2PrimaryKey = sinon.stub(encryptedKey.keyPacket.s2k, 'produceKey').returns(
+ util.hexToUint8Array('832bd2662a5c2b251ee3fc82aec349a766ca539015880133002e5a21960b3bcf'));
+ const stubArgon2Subkey = sinon.stub(encryptedKey.subkeys[0].keyPacket.s2k, 'produceKey').returns(
+ util.hexToUint8Array('f74a6ce873a089ef13a3da9ac059777bb22340d15eaa6c9dc0f8ef09035c67cd'));
+
+ try {
+ const decryptedKey = await openpgp.decryptKey({
+ privateKey: encryptedKey,
+ passphrase
+ });
+
+ const reecryptedKey = await openpgp.encryptKey({
+ privateKey: decryptedKey,
+ passphrase,
+ config: { aeadProtect: true }
+ });
+ expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
+ const redecryptedKey = await openpgp.decryptKey({
+ privateKey: reecryptedKey,
+ passphrase
+ });
+ expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
+ } finally {
+ stubArgon2PrimaryKey.restore();
+ stubArgon2Subkey.restore();
+ }
+ });
+
it('Parsing ECDH key with unknown kdf param version', async function() {
// subkey with unknown kdfParam version 255. Parsing should not fail, the subkey should simply dropped
const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
From 0b8501427bea7cf29aa8fc46784f8f9cf784a83a Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 25 Jul 2023 11:41:20 +0200
Subject: [PATCH 050/224] Implement packet criticality check
The Packet Tag space is now partitioned into critical packets and non-critical packets.
If an implementation encounters a critical packet where the packet type is unknown in a packet sequence,
it MUST reject the whole packet sequence. On the other hand, an unknown non-critical packet MUST be ignored.
See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-4.3.1 .
---
src/packet/packet.js | 13 +++++++++++++
src/packet/packetlist.js | 16 ++++++++++++++--
test/general/packet.js | 14 ++++++++++++++
3 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/src/packet/packet.js b/src/packet/packet.js
index c40082f59..6eea12098 100644
--- a/src/packet/packet.js
+++ b/src/packet/packet.js
@@ -308,6 +308,19 @@ export class UnsupportedError extends Error {
}
}
+// unknown packet types are handled differently depending on the packet criticality
+export class UnknownPacketError extends UnsupportedError {
+ constructor(...params) {
+ super(...params);
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, UnsupportedError);
+ }
+
+ this.name = 'UnknownPacketError';
+ }
+}
+
export class UnparseablePacket {
constructor(tag, rawContent) {
this.tag = tag;
diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js
index 6207ef99e..2c8e2a08a 100644
--- a/src/packet/packetlist.js
+++ b/src/packet/packetlist.js
@@ -4,7 +4,8 @@ import {
writeTag, writeHeader,
writePartialLength, writeSimpleLength,
UnparseablePacket,
- UnsupportedError
+ UnsupportedError,
+ UnknownPacketError
} from './packet';
import util from '../util';
import enums from '../enums';
@@ -25,7 +26,7 @@ export function newPacketFromTag(tag, allowedPackets) {
try {
packetType = enums.read(enums.packet, tag);
} catch (e) {
- throw new UnsupportedError(`Unknown packet type with tag: ${tag}`);
+ throw new UnknownPacketError(`Unknown packet type with tag: ${tag}`);
}
throw new Error(`Packet not allowed in this context: ${packetType}`);
}
@@ -87,6 +88,17 @@ class PacketList extends Array {
await packet.read(parsed.packet, config);
await writer.write(packet);
} catch (e) {
+ // If an implementation encounters a critical packet where the packet type is unknown in a packet sequence,
+ // it MUST reject the whole packet sequence. On the other hand, an unknown non-critical packet MUST be ignored.
+ // Packet Tags from 0 to 39 are critical. Packet Tags from 40 to 63 are non-critical.
+ if (e instanceof UnknownPacketError) {
+ if (parsed.tag <= 39) {
+ await writer.abort(e);
+ } else {
+ return;
+ }
+ }
+
const throwUnsupportedError = !config.ignoreUnsupportedPackets && e instanceof UnsupportedError;
const throwMalformedError = !config.ignoreMalformedPackets && !(e instanceof UnsupportedError);
if (throwUnsupportedError || throwMalformedError || supportsStreaming(parsed.tag)) {
diff --git a/test/general/packet.js b/test/general/packet.js
index 0e1cdaab0..696d2846a 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -1514,6 +1514,20 @@ kePFjAnu9cpynKXu3usf8+FuBw2zLsg1Id1n7ttxoAte416KjBN9lFBt8mcu
).to.be.rejectedWith(/Unsupported S2K type/);
});
+ it('Throws on critical packet even with tolerant mode enabled', async function() {
+ const unknownPacketTag39 = util.hexToUint8Array('e70a750064bf943d6e756c6c'); // critical tag
+
+ await expect(openpgp.PacketList.fromBinary(unknownPacketTag39, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: false, ignoreMalformedPackets: false })).to.be.rejectedWith(/Unknown packet type/);
+ await expect(openpgp.PacketList.fromBinary(unknownPacketTag39, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: true, ignoreMalformedPackets: true })).to.be.rejectedWith(/Unknown packet type/);
+ });
+
+ it('Ignores non-critical packet even with tolerant mode disabled', async function() {
+ const unknownPacketTag63 = util.hexToUint8Array('ff0a750064bf943d6e756c6c'); // non-critical tag
+
+ await expect(openpgp.PacketList.fromBinary(unknownPacketTag63, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: false, ignoreMalformedPackets: false })).to.eventually.have.length(0);
+ await expect(openpgp.PacketList.fromBinary(unknownPacketTag63, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: true, ignoreMalformedPackets: true })).to.eventually.have.length(0);
+ });
+
it('Throws on disallowed packet even with tolerant mode enabled', async function() {
const packets = new openpgp.PacketList();
packets.push(new openpgp.LiteralDataPacket());
From af9662885560d0f8e6b02496f5c0f0dea2ca80e4 Mon Sep 17 00:00:00 2001
From: Lukas Burkhalter
Date: Thu, 1 Jun 2023 15:18:43 +0200
Subject: [PATCH 051/224] Add support for v6 one-pass signature packets
Introduces v6 one-pass signature packets required for v6 signatures.
Includes the changes from !305 of the crypto refresh:
https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/305
Also, introduce `OnePassSignaturePacket.fromSignaturePacket` to simplify
OPS generation.
---
src/message.js | 50 ++---------
src/packet/one_pass_signature.js | 88 ++++++++++++++----
src/packet/signature.js | 8 +-
test/general/signature.js | 149 ++++++++++++++++++++++++++++++-
4 files changed, 233 insertions(+), 62 deletions(-)
diff --git a/src/message.js b/src/message.js
index 2ce9f6273..bea828bfa 100644
--- a/src/message.js
+++ b/src/message.js
@@ -24,7 +24,7 @@ import crypto from './crypto';
import enums from './enums';
import util from './util';
import { Signature } from './signature';
-import { getPreferredHashAlgo, getPreferredCipherSuite, createSignaturePacket } from './key';
+import { getPreferredCipherSuite, createSignaturePacket } from './key';
import {
PacketList,
LiteralDataPacket,
@@ -514,49 +514,14 @@ export class Message {
throw new Error('No literal data packet to sign.');
}
- let i;
- let existingSigPacketlist;
- // If data packet was created from Uint8Array, use binary, otherwise use text
- const signatureType = literalDataPacket.text === null ?
- enums.signature.binary : enums.signature.text;
-
- if (signature) {
- existingSigPacketlist = signature.packets.filterByTag(enums.packet.signature);
- for (i = existingSigPacketlist.length - 1; i >= 0; i--) {
- const signaturePacket = existingSigPacketlist[i];
- const onePassSig = new OnePassSignaturePacket();
- onePassSig.signatureType = signaturePacket.signatureType;
- onePassSig.hashAlgorithm = signaturePacket.hashAlgorithm;
- onePassSig.publicKeyAlgorithm = signaturePacket.publicKeyAlgorithm;
- onePassSig.issuerKeyID = signaturePacket.issuerKeyID;
- if (!signingKeys.length && i === 0) {
- onePassSig.flags = 1;
- }
- packetlist.push(onePassSig);
- }
- }
-
- await Promise.all(Array.from(signingKeys).reverse().map(async function (primaryKey, i) {
- if (!primaryKey.isPrivate()) {
- throw new Error('Need private key for signing');
- }
- const signingKeyID = signingKeyIDs[signingKeys.length - 1 - i];
- const signingKey = await primaryKey.getSigningKey(signingKeyID, date, userIDs, config);
- const onePassSig = new OnePassSignaturePacket();
- onePassSig.signatureType = signatureType;
- onePassSig.hashAlgorithm = await getPreferredHashAlgo(primaryKey, signingKey.keyPacket, date, userIDs, config);
- onePassSig.publicKeyAlgorithm = signingKey.keyPacket.algorithm;
- onePassSig.issuerKeyID = signingKey.getKeyID();
- if (i === signingKeys.length - 1) {
- onePassSig.flags = 1;
- }
- return onePassSig;
- })).then(onePassSignatureList => {
- onePassSignatureList.forEach(onePassSig => packetlist.push(onePassSig));
- });
+ const signaturePackets = await createSignaturePackets(literalDataPacket, signingKeys, signature, signingKeyIDs, date, userIDs, notations, false, config); // this returns the existing signature packets as well
+ const onePassSignaturePackets = signaturePackets.map(
+ (signaturePacket, i) => OnePassSignaturePacket.fromSignaturePacket(signaturePacket, i === 0))
+ .reverse(); // innermost OPS refers to the first signature packet
+ packetlist.push(...onePassSignaturePackets);
packetlist.push(literalDataPacket);
- packetlist.push(...(await createSignaturePackets(literalDataPacket, signingKeys, signature, signingKeyIDs, date, userIDs, notations, false, config)));
+ packetlist.push(...signaturePackets);
return new Message(packetlist);
}
@@ -733,6 +698,7 @@ export class Message {
* @param {Date} [date] - Override the creationtime of the signature
* @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
+ * @param {Array} [signatureSalts] - A list of signature salts matching the number of signingKeys that should be used for v6 signatures
* @param {Boolean} [detached] - Whether to create detached signature packets
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} List of signature packets.
diff --git a/src/packet/one_pass_signature.js b/src/packet/one_pass_signature.js
index 54e8697d2..9018e79f6 100644
--- a/src/packet/one_pass_signature.js
+++ b/src/packet/one_pass_signature.js
@@ -16,14 +16,12 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import * as stream from '@openpgp/web-stream-tools';
-import SignaturePacket from './signature';
+import SignaturePacket, { saltLengthForHash } from './signature';
import KeyID from '../type/keyid';
import enums from '../enums';
import util from '../util';
import { UnsupportedError } from './packet';
-const VERSION = 3;
-
/**
* Implementation of the One-Pass Signature Packets (Tag 4)
*
@@ -39,8 +37,22 @@ class OnePassSignaturePacket {
return enums.packet.onePassSignature;
}
+ static fromSignaturePacket(signaturePacket, isLast) {
+ const onePassSig = new OnePassSignaturePacket();
+ onePassSig.version = signaturePacket.version === 6 ? 6 : 3;
+ onePassSig.signatureType = signaturePacket.signatureType;
+ onePassSig.hashAlgorithm = signaturePacket.hashAlgorithm;
+ onePassSig.publicKeyAlgorithm = signaturePacket.publicKeyAlgorithm;
+ onePassSig.issuerKeyID = signaturePacket.issuerKeyID;
+ onePassSig.salt = signaturePacket.salt; // v6 only
+ onePassSig.issuerFingerprint = signaturePacket.issuerFingerprint; // v6 only
+
+ onePassSig.flags = isLast ? 1 : 0;
+ return onePassSig;
+ }
+
constructor() {
- /** A one-octet version number. The current version is 3. */
+ /** A one-octet version number. The current versions are 3 and 6. */
this.version = null;
/**
* A one-octet signature type.
@@ -62,8 +74,12 @@ class OnePassSignaturePacket {
* @type {enums.publicKey}
*/
this.publicKeyAlgorithm = null;
- /** An eight-octet number holding the Key ID of the signing key. */
+ /** Only for v6, a variable-length field containing the salt. */
+ this.salt = null;
+ /** Only for v3 packets, an eight-octet number holding the Key ID of the signing key. */
this.issuerKeyID = null;
+ /** Only for v6 packets, 32 octets of the fingerprint of the signing key. */
+ this.issuerFingerprint = null;
/**
* A one-octet number holding a flag showing whether the signature is nested.
* A zero value indicates that the next packet is another One-Pass Signature packet
@@ -79,9 +95,9 @@ class OnePassSignaturePacket {
*/
read(bytes) {
let mypos = 0;
- // A one-octet version number. The current version is 3.
+ // A one-octet version number. The current versions are 3 or 6.
this.version = bytes[mypos++];
- if (this.version !== VERSION) {
+ if (this.version !== 3 && this.version !== 6) {
throw new UnsupportedError(`Version ${this.version} of the one-pass signature packet is unsupported.`);
}
@@ -95,10 +111,32 @@ class OnePassSignaturePacket {
// A one-octet number describing the public-key algorithm used.
this.publicKeyAlgorithm = bytes[mypos++];
- // An eight-octet number holding the Key ID of the signing key.
- this.issuerKeyID = new KeyID();
- this.issuerKeyID.read(bytes.subarray(mypos, mypos + 8));
- mypos += 8;
+ if (this.version === 6) {
+ // Only for v6 signatures, a variable-length field containing:
+
+ // A one-octet salt size. The value MUST match the value defined
+ // for the hash algorithm as specified in Table 23 (Hash algorithm registry).
+ const saltLength = bytes[mypos++];
+ if (saltLength !== saltLengthForHash(this.hashAlgorithm)) {
+ throw new Error('Unexpected salt size for the hash algorithm');
+ }
+
+ // The salt; a random value value of the specified size.
+ this.salt = bytes.subarray(mypos, mypos + saltLength);
+ mypos += saltLength;
+
+ // Only for v6 packets, 32 octets of the fingerprint of the signing key.
+ this.issuerFingerprint = bytes.subarray(mypos, mypos + 32);
+ mypos += 32;
+ this.issuerKeyID = new KeyID();
+ // For v6 the Key ID is the high-order 64 bits of the fingerprint.
+ this.issuerKeyID.read(this.issuerFingerprint);
+ } else {
+ // Only for v3 packets, an eight-octet number holding the Key ID of the signing key.
+ this.issuerKeyID = new KeyID();
+ this.issuerKeyID.read(bytes.subarray(mypos, mypos + 8));
+ mypos += 8;
+ }
// A one-octet number holding a flag showing whether the signature
// is nested. A zero value indicates that the next packet is
@@ -113,11 +151,23 @@ class OnePassSignaturePacket {
* @returns {Uint8Array} A Uint8Array representation of a one-pass signature packet.
*/
write() {
- const start = new Uint8Array([VERSION, this.signatureType, this.hashAlgorithm, this.publicKeyAlgorithm]);
-
- const end = new Uint8Array([this.flags]);
-
- return util.concatUint8Array([start, this.issuerKeyID.write(), end]);
+ const arr = [new Uint8Array([
+ this.version,
+ this.signatureType,
+ this.hashAlgorithm,
+ this.publicKeyAlgorithm
+ ])];
+ if (this.version === 6) {
+ arr.push(
+ new Uint8Array([this.salt.length]),
+ this.salt,
+ this.issuerFingerprint
+ );
+ } else {
+ arr.push(this.issuerKeyID.write());
+ }
+ arr.push(new Uint8Array([this.flags]));
+ return util.concatUint8Array(arr);
}
calculateTrailer(...args) {
@@ -133,7 +183,11 @@ class OnePassSignaturePacket {
correspondingSig.signatureType !== this.signatureType ||
correspondingSig.hashAlgorithm !== this.hashAlgorithm ||
correspondingSig.publicKeyAlgorithm !== this.publicKeyAlgorithm ||
- !correspondingSig.issuerKeyID.equals(this.issuerKeyID)
+ !correspondingSig.issuerKeyID.equals(this.issuerKeyID) ||
+ (this.version === 3 && correspondingSig.version === 6) ||
+ (this.version === 6 && correspondingSig.version !== 6) ||
+ (this.version === 6 && !util.equalsUint8Array(correspondingSig.issuerFingerprint, this.issuerFingerprint)) ||
+ (this.version === 6 && !util.equalsUint8Array(correspondingSig.salt, this.salt))
) {
throw new Error('Corresponding signature packet does not match one-pass signature packet');
}
diff --git a/src/packet/signature.js b/src/packet/signature.js
index eb7f8062c..6e0c0dc1f 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -214,7 +214,11 @@ class SignaturePacket {
if (this.version === 6) {
const saltLength = saltLengthForHash(this.hashAlgorithm);
- this.salt = await crypto.random.getRandomBytes(saltLength);
+ if (this.salt === null) {
+ this.salt = crypto.random.getRandomBytes(saltLength);
+ } else if (saltLength !== this.salt.length) {
+ throw new Error('Provided salt does not have the required length');
+ }
}
const toHash = this.toHash(this.signatureType, data, detached);
const hash = await this.hash(this.signatureType, data, toHash, detached);
@@ -823,7 +827,7 @@ function writeSubPacket(type, critical, data) {
* @returns {Integer} Salt length.
* @private
*/
-function saltLengthForHash(hashAlgorithm) {
+export function saltLengthForHash(hashAlgorithm) {
switch (hashAlgorithm) {
case enums.hash.sha256: return 16;
case enums.hash.sha384: return 24;
diff --git a/test/general/signature.js b/test/general/signature.js
index 1c123f751..73e1425ef 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -710,6 +710,68 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
expect(signature.getSigningKeyIDs().map(x => x.toHex())).to.include(publicKey.getKeyID().toHex());
});
+ it('Generates valid one-pass signature packets (v6 keys)', async function () {
+ const v6PrivateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const v4PrivateKey = await openpgp.readKey({
+ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xVgEZOjwQBYJKwYBBAHaRw8BAQdAIzsYHb7T7NhSFmkWKSk5ItaBYv2HET7u
+IFXhGdvOpogAAQDMk8SQlysNkLe7VRwXedX63St1a2V6/dzDG926oPyW3hJ6
+zQ48dGVzdEB0ZXN0Lml0PsKMBBAWCgA+BYJk6PBABAsJBwgJkFMSwQwprjrH
+AxUICgQWAAIBAhkBApsDAh4BFiEEwKKS1V/wldBNfwpjUxLBDCmuOscAAONc
+AQDU1gi9moPtQzh6rrpKPWZ8nMSiZzLb3LYmpqz9Tn9YFAEAmEC2uHET/Oj6
+VVxvMwvGytr5y0nuc6ZV5D0I2qoMcAHHXQRk6PBAEgorBgEEAZdVAQUBAQdA
+xeBFSxzKOtLEQ6mVO2mnxvDiiMKmq7NbOezoWkbeSjgDAQgHAAD/YMvH+eDP
+h1RplHOiaAMwhpTRGSGOaC6+pu6AMWiRLWAQ88J4BBgWCAAqBYJk6PBACZBT
+EsEMKa46xwKbDBYhBMCiktVf8JXQTX8KY1MSwQwprjrHAAD4igEAzoExR6VX
+EY9xxFKtAVdtYOT61d0FZibs0TD0VjbqzdkBAK60jT9jKefpnZ9sGv7bhSRX
+2hrIPyCF2f0R5Js3LCML
+=xyQ6
+-----END PGP PRIVATE KEY BLOCK-----`
+ });
+ const armoredSignedMessage = await openpgp.sign({
+ message: await openpgp.createMessage({ text: 'test' }),
+ signingKeys: [v6PrivateKey, v4PrivateKey, v6PrivateKey] // get multiple signature packets
+ });
+ const signedMessage = await openpgp.readMessage({ armoredMessage: armoredSignedMessage });
+ // read signature packet stream
+ signedMessage.packets.push(...await stream.readToEnd(signedMessage.packets.stream, _ => _));
+ const signature1 = signedMessage.packets[4];
+ const signature2 = signedMessage.packets[5]; // v4 sig
+ const signature3 = signedMessage.packets[6];
+ const opsSignature1 = signedMessage.packets[2];
+ const opsSignature2 = signedMessage.packets[1];
+ const opsSignature3 = signedMessage.packets[0];
+ expect(opsSignature1).to.be.instanceOf(openpgp.OnePassSignaturePacket);
+ expect(signature1).to.be.instanceOf(openpgp.SignaturePacket);
+ expect(opsSignature2).to.be.instanceOf(openpgp.OnePassSignaturePacket);
+ expect(signature2).to.be.instanceOf(openpgp.SignaturePacket);
+ expect(opsSignature3).to.be.instanceOf(openpgp.OnePassSignaturePacket);
+ expect(signature3).to.be.instanceOf(openpgp.SignaturePacket);
+ expect(opsSignature1.version).to.equal(6);
+ expect(opsSignature2.version).to.equal(3);
+ expect(opsSignature3.version).to.equal(6);
+ expect(util.uint8ArrayToHex(opsSignature1.issuerFingerprint)).to.equal(v6PrivateKey.getFingerprint());
+ expect(util.uint8ArrayToHex(opsSignature3.issuerFingerprint)).to.equal(v6PrivateKey.getFingerprint());
+ expect(opsSignature1.salt).to.deep.equal(signature1.salt);
+ expect(opsSignature2.salt).to.be.null;
+ expect(opsSignature3.salt).to.deep.equal(signature3.salt);
+ expect(opsSignature1.salt).to.not.deep.equal(opsSignature3.salt); // sanity check
+ });
+
it('Throws when reading a signature missing the creation time', async function () {
const armoredSignature = `-----BEGIN PGP SIGNATURE-----
@@ -1109,7 +1171,92 @@ Fk7EflUZzngwY4lBzYAfnNBjEjc30xD/ddo+rwE=
});
});
- it('Verify signed message with two one pass signatures', async function() {
+
+ it('Verify signed message with a v6 one pass signature', async function() {
+ // test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.7
+ const message = await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+
+xEYGAQobIHZJX1AhiJD39eLuPBgiUU9wUA9VHYblySHkBONKU/usyxhsTwYJppfk
+1S36bHIrDB8eJ8GKVnCPZSXsJ7rZrMkBy0p1AAAAAABXaGF0IHdlIG5lZWQgZnJv
+bSB0aGUgZ3JvY2VyeSBzdG9yZToKCi0gdG9mdQotIHZlZ2V0YWJsZXMKLSBub29k
+bGVzCsKYBgEbCgAAACkFgmOYo2MiIQbLGGxPBgmml+TVLfpscisMHx4nwYpWcI9l
+JewnutmsyQAAAABpNiB2SV9QIYiQ9/Xi7jwYIlFPcFAPVR2G5ckh5ATjSlP7rCfQ
+b7gKqPxbyxbhljGygHQPnqau1eBzrQD5QVplPEDnemrnfmkrpx0GmhCfokxYz9jj
+FtCgazStmsuOXF9SFQE=
+-----END PGP MESSAGE-----` });
+ const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
+GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
+KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
+gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
+QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
++eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
+BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
+j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
+I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
+-----END PGP PUBLIC KEY BLOCK-----` });
+
+ const signingKeyIDs = message.getSigningKeyIDs();
+ expect(key.getKeys(signingKeyIDs[0])).to.not.be.empty;
+
+ const { data, signatures } = await openpgp.verify({ message, verificationKeys: key });
+ expect(signatures).to.have.length(1);
+ expect(await signatures[0].verified).to.be.true;
+ expect((await signatures[0].signature).packets.length).to.equal(1);
+ expect(data.includes('What we need from the grocery store')).to.be.true;
+ });
+
+ it('Verify signed message with two one pass signatures (v3 and v6)', async function() {
+ // test vector from gopenpgp
+ const message = await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+
+xEYGAAobIBEtnAy3EeX8aDFd2bf/A1Xfi7C/D3mLIkGEwVmD0fecyxhsTwYJppfk
+1S36bHIrDB8eJ8GKVnCPZSXsJ7rZrMkAxA0DAAoW8jFVDE9H444ByxRiAAAAAABI
+ZWxsbyBXb3JsZCA6KcJ1BAAWCgAnBQJk52D2CRDyMVUMT0fjjhYhBOuFu1+jOnXh
+XpROY/IxVQxPR+OOAABOSwEA2nLYxa9ELDxwuPskKCUVs8noyT4fVEScWlWZAKqP
+ykIBAJEhqqNHFP4Gok1Ss9mvf6fE25tJkdJKD+7PIH0mCJgAwpgGABsKAAAAKQUC
+ZOdg9iKhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAA2MIBEt
+nAy3EeX8aDFd2bf/A1Xfi7C/D3mLIkGEwVmD0fecr0oTPTcMNupiH7SCY4THe3ue
+7PlRvF2WoeWKkNZT1uwcb+ilW5h9eBpp0I4Xj98C0hMA5+rHsTsME2EZM8HADA==
+-----END PGP MESSAGE-----` });
+ const v6Key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
+GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
+KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
+gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
+QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
++eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
+BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
+j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
+I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
+-----END PGP PUBLIC KEY BLOCK-----` });
+ const v4Key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: Alice's OpenPGP certificate
+
+mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
+b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
+ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
+MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
+dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
+OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
+E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
+DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
+0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
+=iIGO
+-----END PGP PUBLIC KEY BLOCK-----` });
+
+ const { data, signatures } = await openpgp.verify({ message, verificationKeys: [v4Key, v6Key] });
+ expect(signatures).to.have.length(2);
+ expect(await signatures[0].verified).to.be.true;
+ expect((await signatures[0].signature).packets.length).to.equal(1);
+ expect(await signatures[1].verified).to.be.true;
+ expect((await signatures[1].signature).packets.length).to.equal(1);
+ expect(data).to.equal('Hello World :)');
+ });
+
+ it('Verify signed message with two one pass signatures (both v3)', async function() {
const msg_armor =
['-----BEGIN PGP MESSAGE-----',
'Version: GnuPG v2.0.19 (GNU/Linux)',
From 1ddf4e151c04f869b6ce4572b83c12a86f8668e5 Mon Sep 17 00:00:00 2001
From: Lukas Burkhalter
Date: Thu, 1 Jun 2023 16:24:38 +0200
Subject: [PATCH 052/224] Accept cleartext messages without hash header
The latest version of the crypto refresh (i.e., !313, !314) specifies that
the "Hash" header is deprecated, and that an implementation that is verifying
a cleartext signed message MUST ignore this header.
However, we go against this directive, and keep the checks in place to avoid
arbitrary injection of text as part of the "Hash" header payload.
We also mandate that if the hash header is present, the declared
algorithm matches the signature algorithm. This is again to avoid
a spoofing attack where e.g. a SHA1 signature is presented as
using SHA512.
Related CVEs: CVE-2019-11841, CVE-2023-41037.
This commit does not change the writing part of cleartext messages.
# Conflicts:
# src/cleartext.js
---
src/cleartext.js | 35 +++++++++++++++------------------
test/general/armor.js | 23 ----------------------
test/general/signature.js | 41 +++++++++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+), 42 deletions(-)
diff --git a/src/cleartext.js b/src/cleartext.js
index a99155e38..77f60f7e6 100644
--- a/src/cleartext.js
+++ b/src/cleartext.js
@@ -171,30 +171,27 @@ function verifyHeaders(headers, packetlist) {
return true;
};
- let oneHeader = null;
- let hashAlgos = [];
- headers.forEach(function(header) {
- oneHeader = header.match(/^Hash: (.+)$/); // get header value
- if (oneHeader) {
- oneHeader = oneHeader[1].replace(/\s/g, ''); // remove whitespace
- oneHeader = oneHeader.split(',');
- oneHeader = oneHeader.map(function(hash) {
- hash = hash.toLowerCase();
- try {
- return enums.write(enums.hash, hash);
- } catch (e) {
- throw new Error('Unknown hash algorithm in armor header: ' + hash);
- }
- });
- hashAlgos = hashAlgos.concat(oneHeader);
+ const hashAlgos = [];
+ headers.forEach(header => {
+ const hashHeader = header.match(/^Hash: (.+)$/); // get header value
+ if (hashHeader) {
+ const parsedHashIDs = hashHeader[1]
+ .replace(/\s/g, '') // remove whitespace
+ .split(',')
+ .map(hashName => {
+ try {
+ return enums.write(enums.hash, hashName.toLowerCase());
+ } catch (e) {
+ throw new Error('Unknown hash algorithm in armor header: ' + hashName.toLowerCase());
+ }
+ });
+ hashAlgos.push(...parsedHashIDs);
} else {
throw new Error('Only "Hash" header allowed in cleartext signed message');
}
});
- if (!hashAlgos.length && !checkHashAlgos([enums.hash.md5])) {
- throw new Error('If no "Hash" header in cleartext signed message, then only MD5 signatures allowed');
- } else if (hashAlgos.length && !checkHashAlgos(hashAlgos)) {
+ if (hashAlgos.length && !checkHashAlgos(hashAlgos)) {
throw new Error('Hash algorithm mismatch in armor header and signature');
}
}
diff --git a/test/general/armor.js b/test/general/armor.js
index 2c620d350..627737920 100644
--- a/test/general/armor.js
+++ b/test/general/armor.js
@@ -36,12 +36,6 @@ export default () => describe('ASCII armor', function() {
await expect(msg).to.be.rejectedWith(Error, /Hash algorithm mismatch in armor header and signature/);
});
- it('Exception if no header and non-MD5 signature', async function () {
- let msg = getArmor(null);
- msg = openpgp.readCleartextMessage({ cleartextMessage: msg });
- await expect(msg).to.be.rejectedWith(Error, /If no "Hash" header in cleartext signed message, then only MD5 signatures allowed/);
- });
-
it('Exception if unknown hash algorithm', async function () {
let msg = getArmor(['Hash: LAV750']);
msg = openpgp.readCleartextMessage({ cleartextMessage: msg });
@@ -66,18 +60,6 @@ export default () => describe('ASCII armor', function() {
await expect(msg).to.be.rejectedWith(Error, /Only "Hash" header allowed in cleartext signed message/);
});
- it('Multiple wrong hash values', async function () {
- let msg = getArmor(['Hash: SHA512, SHA256']);
- msg = openpgp.readCleartextMessage({ cleartextMessage: msg });
- await expect(msg).to.be.rejectedWith(Error, /Hash algorithm mismatch in armor header and signature/);
- });
-
- it('Multiple wrong hash values', async function () {
- let msg = getArmor(['Hash: SHA512, SHA256']);
- msg = openpgp.readCleartextMessage({ cleartextMessage: msg });
- await expect(msg).to.be.rejectedWith(Error, /Hash algorithm mismatch in armor header and signature/);
- });
-
it('Filter whitespace in blank line', async function () {
let msg = [
'-----BEGIN PGP SIGNED MESSAGE-----',
@@ -99,11 +81,6 @@ export default () => describe('ASCII armor', function() {
expect(msg).to.be.an.instanceof(openpgp.CleartextMessage);
});
- it('Exception if header is not Hash in cleartext signed message', async function () {
- const msg = openpgp.readCleartextMessage({ cleartextMessage: getArmor(['Ha sh: SHA256']) });
- await expect(msg).to.be.rejectedWith(Error, /Only "Hash" header allowed in cleartext signed message/);
- });
-
it('Ignore improperly formatted armor header', async function () {
await Promise.all(['Space : trailing', 'Space :switched', ': empty', 'none', 'Space:missing'].map(async function (invalidHeader) {
expect(await openpgp.readCleartextMessage({ cleartextMessage: getArmor(['Hash: SHA1'], [invalidHeader]) })).to.be.an.instanceof(openpgp.CleartextMessage);
diff --git a/test/general/signature.js b/test/general/signature.js
index 73e1425ef..c94acd8fe 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1365,6 +1365,47 @@ DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
expect(notations[1].critical).to.be.false;
});
+ it('Verify v6 cleartext signed message with openpgp.verify', async function() {
+ // test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-08.html#name-sample-v6-certificate-trans
+ const cleartextMessage = `-----BEGIN PGP SIGNED MESSAGE-----
+
+What we need from the grocery store:
+
+- - tofu
+- - vegetables
+- - noodles
+
+-----BEGIN PGP SIGNATURE-----
+
+wpgGARsKAAAAKQWCY5ijYyIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAGk2IHZJX1AhiJD39eLuPBgiUU9wUA9VHYblySHkBONKU/usJ9BvuAqo
+/FvLFuGWMbKAdA+epq7V4HOtAPlBWmU8QOd6aud+aSunHQaaEJ+iTFjP2OMW0KBr
+NK2ay45cX1IVAQ==
+-----END PGP SIGNATURE-----`;
+
+ const publicKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
+GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
+KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
+gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
+QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
++eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
+BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
+j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
+I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
+-----END PGP PUBLIC KEY BLOCK-----` });
+
+ const plaintext = 'What we need from the grocery store:\n\n- tofu\n- vegetables\n- noodles\n';
+ const message = await openpgp.readCleartextMessage({ cleartextMessage });
+
+ const { signatures, data } = await openpgp.verify({ message, verificationKeys: publicKey });
+ expect(data).to.equal(plaintext);
+ expect(signatures).to.have.length(1);
+ expect(await signatures[0].verified).to.be.true;
+ expect((await signatures[0].signature).packets.length).to.equal(1);
+ });
+
it('Verify cleartext signed message with two signatures with openpgp.verify', async function() {
const cleartextMessage =
['-----BEGIN PGP SIGNED MESSAGE-----',
From 79b3687424a8289d4c173585a498df5dec97901f Mon Sep 17 00:00:00 2001
From: Lukas Burkhalter
Date: Thu, 8 Jun 2023 10:05:01 +0200
Subject: [PATCH 053/224] Only emit Hash header below V6 for cleartext messages
The latest version of the crypto refresh (i.e., !313, !314) specifies that
the "Hash" header is depricated. This commit changes that the Hash header
is only generated if a cleartext message contains a non-V6 signature.
---
src/cleartext.js | 14 +++++++++-----
src/encoding/armor.js | 6 +++---
test/general/signature.js | 32 ++++++++++++++++++++++++++++++++
3 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/src/cleartext.js b/src/cleartext.js
index 77f60f7e6..34b1bc68b 100644
--- a/src/cleartext.js
+++ b/src/cleartext.js
@@ -111,12 +111,16 @@ export class CleartextMessage {
* @returns {String | ReadableStream} ASCII armor.
*/
armor(config = defaultConfig) {
- let hashes = this.signature.packets.map(function(packet) {
- return enums.read(enums.hash, packet.hashAlgorithm).toUpperCase();
- });
- hashes = hashes.filter(function(item, i, ar) { return ar.indexOf(item) === i; });
+ // emit header if one of the signatures has a version not 6
+ const emitHeader = this.signature.packets.some(packet => packet.version !== 6);
+ const hash = emitHeader ?
+ Array.from(new Set(this.signature.packets.map(
+ packet => enums.read(enums.hash, packet.hashAlgorithm).toUpperCase()
+ ))).join() :
+ null;
+
const body = {
- hash: hashes.join(),
+ hash,
text: this.text,
data: this.signature.packets.write()
};
diff --git a/src/encoding/armor.js b/src/encoding/armor.js
index 0e0aa5aed..2177683f4 100644
--- a/src/encoding/armor.js
+++ b/src/encoding/armor.js
@@ -190,12 +190,12 @@ export function unarmor(input) {
} else {
verifyHeaders(lastHeaders);
headersDone = true;
- if (textDone || type !== 2) {
+ if (textDone || type !== enums.armor.signed) {
resolve({ text, data, headers, type });
break;
}
}
- } else if (!textDone && type === 2) {
+ } else if (!textDone && type === enums.armor.signed) {
if (!reSplit.test(line)) {
// Reverse dash-escaping for msg
text.push(line.replace(/^- /, ''));
@@ -289,7 +289,7 @@ export function armor(messageType, body, partIndex, partTotal, customComment, co
break;
case enums.armor.signed:
result.push('-----BEGIN PGP SIGNED MESSAGE-----\n');
- result.push('Hash: ' + hash + '\n\n');
+ result.push(hash ? `Hash: ${hash}\n\n` : '\n');
result.push(text.replace(/^-/mg, '- -'));
result.push('\n-----BEGIN PGP SIGNATURE-----\n');
result.push(addheader(customComment, config));
diff --git a/test/general/signature.js b/test/general/signature.js
index c94acd8fe..5a58dd1b6 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1594,6 +1594,38 @@ ${armoredSignature}
expect(await signatures[0].verified).to.be.true;
});
+ it('Does not emit headers for v6 cleartext message', async function() {
+ const v6PrivateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const v4PrivateKey = await openpgp.decryptKey({
+ privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
+ passphrase: 'hello world'
+ });
+
+ const message = await openpgp.createCleartextMessage({ text: 'check header message' });
+
+ const cleartextMessageV6 = await openpgp.sign({ message, signingKeys: v6PrivateKey });
+ const cleartextMessageV4 = await openpgp.sign({
+ message,
+ signingKeys: [v4PrivateKey, v6PrivateKey],
+ config: { minRSABits: 1024 }
+ });
+ expect(cleartextMessageV6).to.not.contain('Hash:');
+ expect(cleartextMessageV4).to.contain('Hash:');
+ });
+
function tests() {
it('Verify signed message with trailing spaces from GPG', async function() {
const armoredMessage =
From 1423bdd56482bf761de40cc781020a4e141207d9 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 7 Aug 2023 21:45:50 +0200
Subject: [PATCH 054/224] Add PKESK.fromObject
---
src/message.js | 26 ++++++-------
.../public_key_encrypted_session_key.js | 26 ++++++++++++-
test/general/openpgp.js | 37 ++++++++++---------
3 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/src/message.js b/src/message.js
index bea828bfa..7afb2fd9a 100644
--- a/src/message.js
+++ b/src/message.js
@@ -17,7 +17,6 @@
import * as stream from '@openpgp/web-stream-tools';
import { armor, unarmor } from './encoding/armor';
-import KeyID from './type/keyid';
import { Argon2OutOfMemoryError } from './type/s2k';
import defaultConfig from './config';
import crypto from './crypto';
@@ -431,24 +430,21 @@ export class Message {
*/
static async encryptSessionKey(sessionKey, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], config = defaultConfig) {
const packetlist = new PacketList();
- const algorithm = enums.write(enums.symmetric, algorithmName);
+ const symmetricAlgorithm = enums.write(enums.symmetric, algorithmName);
const aeadAlgorithm = aeadAlgorithmName && enums.write(enums.aead, aeadAlgorithmName);
if (encryptionKeys) {
const results = await Promise.all(encryptionKeys.map(async function(primaryKey, i) {
const encryptionKey = await primaryKey.getEncryptionKey(encryptionKeyIDs[i], date, userIDs, config);
- const pkESKeyPacket = new PublicKeyEncryptedSessionKeyPacket();
- if (aeadAlgorithm) {
- pkESKeyPacket.version = 6;
- pkESKeyPacket.publicKeyVersion = wildcard ? 0 : encryptionKey.keyPacket.version;
- pkESKeyPacket.publicKeyFingerprint = wildcard ? null : encryptionKey.keyPacket.getFingerprintBytes();
- } else {
- pkESKeyPacket.version = 3;
- pkESKeyPacket.publicKeyID = wildcard ? KeyID.wildcard() : encryptionKey.getKeyID();
- }
- pkESKeyPacket.publicKeyAlgorithm = encryptionKey.keyPacket.algorithm;
- pkESKeyPacket.sessionKey = sessionKey;
- pkESKeyPacket.sessionKeyAlgorithm = algorithm;
+
+ const pkESKeyPacket = PublicKeyEncryptedSessionKeyPacket.fromObject({
+ version: aeadAlgorithm ? 6 : 3,
+ encryptionKeyPacket: encryptionKey.keyPacket,
+ anonymousRecipient: wildcard,
+ sessionKey,
+ sessionKeyAlgorithm: symmetricAlgorithm
+ });
+
await pkESKeyPacket.encrypt(encryptionKey.keyPacket);
delete pkESKeyPacket.sessionKey; // delete plaintext session key after encryption
return pkESKeyPacket;
@@ -487,7 +483,7 @@ export class Message {
return symEncryptedSessionKeyPacket;
};
- const results = await Promise.all(passwords.map(pwd => encryptPassword(sessionKey, algorithm, aeadAlgorithm, pwd)));
+ const results = await Promise.all(passwords.map(pwd => encryptPassword(sessionKey, symmetricAlgorithm, aeadAlgorithm, pwd)));
packetlist.push(...results);
}
diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js
index 02828b5ed..8121e32c8 100644
--- a/src/packet/public_key_encrypted_session_key.js
+++ b/src/packet/public_key_encrypted_session_key.js
@@ -45,7 +45,7 @@ class PublicKeyEncryptedSessionKeyPacket {
constructor() {
this.version = null;
- // For version 3:
+ // For version 3, but also used internally by v6 in e.g. `getEncryptionKeyIDs()`
this.publicKeyID = new KeyID();
// For version 6:
@@ -66,6 +66,30 @@ class PublicKeyEncryptedSessionKeyPacket {
this.encrypted = {};
}
+ static fromObject({
+ version, encryptionKeyPacket, anonymousRecipient, sessionKey, sessionKeyAlgorithm
+ }) {
+ const pkesk = new PublicKeyEncryptedSessionKeyPacket();
+
+ if (version !== 3 && version !== 6) {
+ throw new Error('Unsupported PKESK version');
+ }
+
+ pkesk.version = version;
+
+ if (version === 6) {
+ pkesk.publicKeyVersion = anonymousRecipient ? null : encryptionKeyPacket.version;
+ pkesk.publicKeyFingerprint = anonymousRecipient ? null : encryptionKeyPacket.getFingerprintBytes();
+ }
+
+ pkesk.publicKeyID = anonymousRecipient ? KeyID.wildcard() : encryptionKeyPacket.getKeyID();
+ pkesk.publicKeyAlgorithm = encryptionKeyPacket.algorithm;
+ pkesk.sessionKey = sessionKey;
+ pkesk.sessionKeyAlgorithm = sessionKeyAlgorithm;
+
+ return pkesk;
+ }
+
/**
* Parsing function for a publickey encrypted session key packet (tag 1).
*
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 98c6a3c67..b73653053 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -2581,27 +2581,30 @@ XfA3pqV4mTzF
});
});
- it('should encrypt then decrypt with wildcard', async function () {
- const encOpt = {
+ it('should encrypt then decrypt with wildcard (anonymous recipient)', async function () {
+ const { privateKey: privateKeyV4orV6 } = await openpgp.generateKey({ userIDs: { email: 'test@test.it' }, format: 'object' });
+ const plaintext = 'hello world';
+
+ const encryptedMessage = await openpgp.encrypt({
message: await openpgp.createMessage({ text: plaintext }),
- encryptionKeys: publicKey,
- wildcard: true
- };
- const decOpt = {
- decryptionKeys: privateKey
- };
- return openpgp.encrypt(encOpt).then(async function (encrypted) {
- expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
- decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
- return openpgp.decrypt(decOpt);
- }).then(function (decrypted) {
- expect(decrypted.data).to.equal(plaintext);
- expect(decrypted.signatures).to.exist;
- expect(decrypted.signatures.length).to.equal(0);
+ encryptionKeys: privateKeyV4orV6,
+ wildcard: true,
+ format: 'object'
});
+
+ expect(encryptedMessage.getEncryptionKeyIDs().every(keyID => keyID.isWildcard())).to.be.true;
+ const armoredMessage = encryptedMessage.armor();
+
+ const parsedEncryptedMessage = await openpgp.readMessage({ armoredMessage });
+ expect(parsedEncryptedMessage.getEncryptionKeyIDs().every(keyID => keyID.isWildcard())).to.be.true;
+
+ const decrypted = await openpgp.decrypt({ message: parsedEncryptedMessage, decryptionKeys: privateKeyV4orV6 });
+ expect(decrypted.data).to.equal(plaintext);
+ expect(decrypted.signatures).to.exist;
+ expect(decrypted.signatures.length).to.equal(0);
});
- it('should encrypt then decrypt with wildcard with multiple private keys', async function () {
+ it('should encrypt then decrypt with wildcard with multiple private keys (anonymous recipient)', async function () {
const privKeyDE = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
passphrase
From 278a61adaba8b8245b308be4cf021da4969bb8bf Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 28 Aug 2023 15:31:00 +0200
Subject: [PATCH 055/224] Add SEIP.fromObject
To avoid defaulting to v1
---
src/message.js | 10 ++++------
.../sym_encrypted_integrity_protected_data.js | 16 +++++++++++++++-
test/general/packet.js | 2 ++
3 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/src/message.js b/src/message.js
index 7afb2fd9a..8e5c725fc 100644
--- a/src/message.js
+++ b/src/message.js
@@ -397,12 +397,10 @@ export class Message {
const msg = await Message.encryptSessionKey(sessionKeyData, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, userIDs, config);
- const symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
- if (aeadAlgorithmName) {
- symEncryptedPacket.version = 2;
- symEncryptedPacket.aeadAlgorithm = enums.write(enums.aead, aeadAlgorithmName);
- }
-
+ const symEncryptedPacket = SymEncryptedIntegrityProtectedDataPacket.fromObject({
+ version: aeadAlgorithmName ? 2 : 1,
+ aeadAlgorithm: aeadAlgorithmName ? enums.write(enums.aead, aeadAlgorithmName) : null
+ });
symEncryptedPacket.packets = this.packets;
const algorithm = enums.write(enums.symmetric, algorithmName);
diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js
index 8aedf18d3..f7c70646d 100644
--- a/src/packet/sym_encrypted_integrity_protected_data.js
+++ b/src/packet/sym_encrypted_integrity_protected_data.js
@@ -52,8 +52,22 @@ class SymEncryptedIntegrityProtectedDataPacket {
return enums.packet.symEncryptedIntegrityProtectedData;
}
+ static fromObject({ version, aeadAlgorithm }) {
+ if (version !== 1 && version !== 2) {
+ throw new Error('Unsupported SEIPD version');
+ }
+
+ const seip = new SymEncryptedIntegrityProtectedDataPacket();
+ seip.version = version;
+ if (version === 2) {
+ seip.aeadAlgorithm = aeadAlgorithm;
+ }
+
+ return seip;
+ }
+
constructor() {
- this.version = 1;
+ this.version = null;
// The following 4 fields are for V2 only.
/** @type {enums.symmetric} */
diff --git a/test/general/packet.js b/test/general/packet.js
index 696d2846a..f3a4e9b73 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -137,6 +137,7 @@ export default () => describe('Packet', function() {
const literal = new openpgp.LiteralDataPacket();
const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ enc.version = 1;
enc.packets = new openpgp.PacketList();
enc.packets.push(literal);
const msg = new openpgp.PacketList();
@@ -616,6 +617,7 @@ export default () => describe('Packet', function() {
literal.setText(testText);
const skesk = new openpgp.SymEncryptedSessionKeyPacket();
const seip = new openpgp.SymEncryptedIntegrityProtectedDataPacket();
+ seip.version = 1;
seip.packets = new openpgp.PacketList();
seip.packets.push(literal);
const msg = new openpgp.PacketList();
From 8fe04c99c62a4807d9bb5bbf1b4b931d67a274e4 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 11 Sep 2023 13:57:02 +0200
Subject: [PATCH 056/224] Remove unused `enums.symmetric.plaintext`
This special cipher value can be relevant for unencrypted private keys:
https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-12.2.1 .
However, it is no longer used internally, and on the contrary it could cause
confusion on SKESK decryption, where "random" cipher algos are returned in case
of wrong password.
This change also fixes a flaky test on password-based decryption, caused by the
PKESK v6 changes which add support for `null` cipher algos. The code did not
distinguish between a `null` and a `0` (plaintext) algo identifier, and would
break when the latter was returned on SKESK decryption.
---
openpgp.d.ts | 10 +++++--
src/enums.js | 1 -
test/general/openpgp.js | 65 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index 19a681a19..d38bd10d9 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -181,7 +181,7 @@ export function generateSessionKey(options: { encryptionKeys: MaybeArray;
export function encryptSessionKey(options: EncryptSessionKeyOptions & { format: 'binary' }): Promise;
export function encryptSessionKey(options: EncryptSessionKeyOptions & { format: 'object' }): Promise>;
-export function decryptSessionKeys>(options: { message: Message, decryptionKeys?: MaybeArray, passwords?: MaybeArray, date?: Date, config?: PartialConfig }): Promise;
+export function decryptSessionKeys>(options: { message: Message, decryptionKeys?: MaybeArray, passwords?: MaybeArray, date?: Date, config?: PartialConfig }): Promise;
export function readMessage>(options: { armoredMessage: T, config?: PartialConfig }): Promise>;
export function readMessage>(options: { binaryMessage: T, config?: PartialConfig }): Promise>;
@@ -578,6 +578,11 @@ export interface SessionKey {
aeadAlgorithm?: enums.aeadNames;
}
+export interface DecryptedSessionKey {
+ data: Uint8Array;
+ algorithm: enums.symmetricNames | null; // `null` if the session key is associated with a SEIPDv2 packet
+}
+
export interface ReasonForRevocation { flag?: enums.reasonForRevocation, string?: string }
interface EncryptOptions {
@@ -843,9 +848,8 @@ export namespace enums {
brainpoolP512r1 = 'brainpoolP512r1'
}
- export type symmetricNames = 'plaintext' | 'idea' | 'tripledes' | 'cast5' | 'blowfish' | 'aes128' | 'aes192' | 'aes256' | 'twofish';
+ export type symmetricNames = 'idea' | 'tripledes' | 'cast5' | 'blowfish' | 'aes128' | 'aes192' | 'aes256' | 'twofish';
enum symmetric {
- plaintext = 0,
idea = 1,
tripledes = 2,
cast5 = 3,
diff --git a/src/enums.js b/src/enums.js
index 8b98ad177..210c380b0 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -140,7 +140,6 @@ export default {
* @readonly
*/
symmetric: {
- plaintext: 0,
/** Not implemented! */
idea: 1,
tripledes: 2,
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index b73653053..41533bdf3 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -2250,6 +2250,71 @@ XfA3pqV4mTzF
});
});
+ describe('decryptSessionKeys - unit tests', function() {
+ it('should decrypt message with two SKESKs where the wrong password returns a symmetric algo equal to 0', async function () {
+ // SKESK packets do not have an intrisic integrity check, and the session key must be used to check its validity.
+ // This message is such that when the password is used to try and decrypt the first (mismatching) SKESK, the result returns a '0' byte for
+ // the session key algo. This corresponds to the 'plaintext' algo identifier (https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-12.2.1),
+ // now removed from OpenPGP.js .
+ // This test guards against regressions caused by mishandling this value on SKESK decryption.
+ const message = await openpgp.readMessage({ armoredMessage:`-----BEGIN PGP MESSAGE-----
+
+wy4ECQMIf6HA/a6XkOAAlaU1z+uVfU5kmHmqNqahQH859nAMresQ6w1uIjsL
+ZE5bwy4ECQMIKVfCf+GWBesA5KFPuIDa6kLLn/AvEgbCi5DOg2xdIf73SNSN
+Tqy7nfex0sANAVtHHRkHVTRVTVa3MFjjiWeBEDtnfyVMntWJ21ihrIU9eb9p
+qS7UljZZ0u++xSWclU2IGBXCIdO0wLuS6hYk3q5OFexWj8OIoYJX88nkA2iW
+5xyGd9EFRWVsR4CREt8lwrIE2t/h8XpRlhJmY6Iefg8+2DeN8vDdhNs/B02o
+0zAE0hF+3xvwZTLi4hDrhBZEgBedPaeX4jlmDc3qzh2wlgV/Mq/FUakYfSLl
+bc1PCpfqkLZSuCfv4eoTrWohWi9lS/pRXY9hzzHtlnjo6w==
+-----END PGP MESSAGE-----` });
+ const sessionKeys = await openpgp.decryptSessionKeys({ message, passwords: 'I am another password' });
+ expect(sessionKeys).to.have.length(1); // first SKESK dropped due to '0' being treated as invalid algo identifier
+ expect(sessionKeys[0].algorithm).to.equal('aes256');
+
+ // decrypt() used to fail on this type of input
+ const decrypted = await openpgp.decrypt({ message, passwords: 'I am another password', format: 'binary' });
+ expect(decrypted.data).to.deep.equal(
+ util.hexToUint8Array('e280872009d699e0b5bae18ba1e28c86d280d184e1b888e1a8b3e28ab7e0afa8e0b98be283bde28db5e1b1afd48de1b5b2e280a7e199b0e1a487e185afd3a1e18ca5e0bfb4e28892e19e98e29bb8e29594e0baaae0b681e1929af09f9882f09f9897f09f9882f09f98abf09f988ff09f98b6f09f98bcf09f98bcf09f9981f09f9982e2808720090d0aed959ceab5adec96b42feca1b0ec84a0eba790')
+ );
+ expect(decrypted.signatures.length).to.equal(0);
+ });
+
+ it('should decrypt PKESK v6 and return a null symmetric algorithm', async function() {
+ // test vector https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.8
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
+WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
+aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
+yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
+bhF30A+IitsxxA==
+-----END PGP MESSAGE-----`;
+
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const sessionKeys = await openpgp.decryptSessionKeys({
+ message: await openpgp.readMessage({ armoredMessage }),
+ decryptionKeys: privateKey
+ });
+
+ expect(sessionKeys).to.have.length(1);
+ expect(sessionKeys[0].algorithm).to.equal(null); // PKESK v6 does not include the algo info
+ });
+ });
+
describe('encrypt, decrypt, sign, verify - integration tests', function() {
let privateKey_2000_2008;
let publicKey_2000_2008;
From 53e1ec023f4ebf45911c3a078e8dfe3f715d02bf Mon Sep 17 00:00:00 2001
From: Ryan
Date: Mon, 25 Sep 2023 05:17:21 -0400
Subject: [PATCH 057/224] Add SHA-3 signature support (#1680)
To support parsing, signing and verifying SHA3 signatures over messages and
keys.
---
src/crypto/hash/index.js | 15 ++++++++++++++-
src/enums.js | 4 +++-
src/packet/signature.js | 2 ++
test/crypto/hash/sha.js | 4 ++++
test/general/openpgp.js | 36 ++++++++++++++++++++++++++++++++++++
5 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index bdf6d60bf..617b59a9c 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -8,6 +8,7 @@
import { sha1 } from '@openpgp/noble-hashes/sha1';
import { sha224, sha256 } from '@openpgp/noble-hashes/sha256';
import { sha384, sha512 } from '@openpgp/noble-hashes/sha512';
+import { sha3_256, sha3_512 } from '@openpgp/noble-hashes/sha3';
import { ripemd160 } from '@openpgp/noble-hashes/ripemd160';
import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5';
@@ -55,7 +56,9 @@ const hashFunctions = {
sha256: nodeHash('sha256') || nobleHash(sha256, 'SHA-256'),
sha384: nodeHash('sha384') || nobleHash(sha384, 'SHA-384'),
sha512: nodeHash('sha512') || nobleHash(sha512, 'SHA-512'),
- ripemd: nodeHash('ripemd160') || nobleHash(ripemd160)
+ ripemd: nodeHash('ripemd160') || nobleHash(ripemd160),
+ sha3_256: nodeHash('sha3-256') || nobleHash(sha3_256),
+ sha3_512: nodeHash('sha3-512') || nobleHash(sha3_512)
};
export default {
@@ -68,6 +71,8 @@ export default {
sha384: hashFunctions.sha384,
sha512: hashFunctions.sha512,
ripemd: hashFunctions.ripemd,
+ sha3_256: hashFunctions.sha3_256,
+ sha3_512: hashFunctions.sha3_512,
/**
* Create a hash on the specified data using the specified algorithm
@@ -91,6 +96,10 @@ export default {
return this.sha512(data);
case enums.hash.sha224:
return this.sha224(data);
+ case enums.hash.sha3_256:
+ return this.sha3_256(data);
+ case enums.hash.sha3_512:
+ return this.sha3_512(data);
default:
throw new Error('Invalid hash function.');
}
@@ -116,6 +125,10 @@ export default {
return 64;
case enums.hash.sha224:
return 28;
+ case enums.hash.sha3_256:
+ return 32;
+ case enums.hash.sha3_512:
+ return 64;
default:
throw new Error('Invalid hash algorithm.');
}
diff --git a/src/enums.js b/src/enums.js
index 210c380b0..5dbbffcc0 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -175,7 +175,9 @@ export default {
sha256: 8,
sha384: 9,
sha512: 10,
- sha224: 11
+ sha224: 11,
+ sha3_256: 12,
+ sha3_512: 14
},
/** A list of hash names as accepted by webCrypto functions.
diff --git a/src/packet/signature.js b/src/packet/signature.js
index 6e0c0dc1f..6ab5a6a43 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -833,6 +833,8 @@ export function saltLengthForHash(hashAlgorithm) {
case enums.hash.sha384: return 24;
case enums.hash.sha512: return 32;
case enums.hash.sha224: return 16;
+ case enums.hash.sha3_256: return 16;
+ case enums.hash.sha3_512: return 32;
default: throw new Error('Unsupported hash function for V6 signatures');
}
}
diff --git a/test/crypto/hash/sha.js b/test/crypto/hash/sha.js
index dc5284f08..5297aca5e 100644
--- a/test/crypto/hash/sha.js
+++ b/test/crypto/hash/sha.js
@@ -14,4 +14,8 @@ export default () => it('SHA* with test vectors from NIST FIPS 180-2', async fun
expect(util.uint8ArrayToHex(await hash.sha384(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b')).to.equal('3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b');
expect(util.uint8ArrayToHex(await hash.sha512(util.stringToUint8Array('abc')), 'hash.sha512("abc") = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')).to.equal('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f');
expect(util.uint8ArrayToHex(await hash.sha512(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445')).to.equal('204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445');
+ expect(util.uint8ArrayToHex(await hash.sha3_256(util.stringToUint8Array('abc')), 'hash.sha3_256("abc") = 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532')).to.equal('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532');
+ expect(util.uint8ArrayToHex(await hash.sha3_256(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha3_256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376')).to.equal('41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376');
+ expect(util.uint8ArrayToHex(await hash.sha3_512(util.stringToUint8Array('abc')), 'hash.sha3_512("abc") = b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0')).to.equal('b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0');
+ expect(util.uint8ArrayToHex(await hash.sha3_512(util.stringToUint8Array('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')), 'hash.sha3_512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e')).to.equal('04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e');
});
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 41533bdf3..948e88624 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -297,6 +297,25 @@ DECl1Qu4QyeXin29uEXWiekMpNlZVsEuc8icCw6ABhIZ
=/7PI
-----END PGP PRIVATE KEY BLOCK-----`;
+const priv_key_sha3 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGZN8edBsAAAAgdUMlFMFCVKNo7sdUd6FVBos6NNjpUpSdrodk6BfPb/kA+3bu
+A2+WY2LwyxlX5o07WR2VSn+wuegC3v28yO0tClHCtwYfGw4AAABIBYJk3x50BAsJ
+CAcHFQ4MCgkICwIWAAIXgAKbAwIeCSIhBpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3W
+pW1U6svHvCUiBScJAgcCAAAAACMZIP8aHixoyC9wS3q/TNV/IfOQa81f+U5Ucz6H
+4I+c5bWRYUzH/piBB4n5FoYlld+/SViCQIBCQ+fynLmaj5wlf22+mISTt/9je1Zf
+YWlJ+WSJyi5gY5EH9DubfuIU3VaqCM0aQmVybmFkZXR0ZSA8YkBleGFtcGxlLm9y
+Zz7CugYTGw4AAABLBYJk3x50BAsJCAcHFQ4MCgkICwIWAAIXgAIZAQKbAwIeCSIh
+BpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3WpW1U6svHvCUiBScJAgcCAAAAAMMGIJEi
+9+yqkFKsNwX1H5II0riPudFpwBx2ypVjNk4aNb7Exl56Aac4tXEhz4fH41q0dAzF
+ww2erZaiUqmohQ4AFSw1jN/WOiDfb1DkjT/HJ8vXMGpwWdgFPoqsWzTNhd5VCcdL
+BmTfHnQZAAAAIAGMcsqVCXLclRhVamWciSxmnYF1FFs80W7dNUH07HUOAHh/S601
+If+/eZKDIj3jq7oOe2PzHSYEK+mpQD1hBpF2wpsGGBsOAAAALAWCZN8edAKbDCIh
+BpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3WpW1U6svHvCUiAAAAANj3IBknZTPsMpWA
+we0Jl5gw/Dj4lWAGoJfWfk+6s3Q86Hag3Hu8VBsapzmul+vzy0KJa+ZRcZz2n8aj
+0vTl4sOZ0EcCdFDfkh/tR//gKkT6BiSBG86WoFq3f6U/RC+z0Ym7Dw==
+-----END PGP PRIVATE KEY BLOCK-----`;
+
const passphrase = 'hello world';
const plaintext = input.createSomeMessage();
const password1 = 'I am a password';
@@ -1821,6 +1840,23 @@ aOU=
})).to.be.rejectedWith(/No signing keys provided/);
});
+ it('Signing with key which uses sha3 should generate a valid sha3 signature', async function() {
+ const privKey = await openpgp.readKey({ armoredKey: priv_key_sha3 });
+ const pubKey = privKey.toPublic();
+ const text = 'Hello, world.';
+ const message = await openpgp.createCleartextMessage({ text });
+
+ const cleartextMessage = await openpgp.sign({ message, signingKeys: privKey, format: 'armored' });
+ const parsedArmored = await openpgp.readCleartextMessage({ cleartextMessage });
+ expect(parsedArmored.signature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
+ expect(
+ parsedArmored.signature.packets.filterByTag(openpgp.enums.packet.signature)[0].hashAlgorithm
+ ).to.equal(openpgp.enums.hash.sha3_512);
+
+ const verified = await openpgp.verify({ message: parsedArmored, verificationKeys: pubKey, expectSigned: true });
+ expect(verified.data).to.equal(text);
+ });
+
it('should output cleartext message of expected format', async function() {
const text = 'test';
const message = await openpgp.createCleartextMessage({ text });
From 97ebd14829ee1226280bfb7183db0be346ca9662 Mon Sep 17 00:00:00 2001
From: larabr
Date: Mon, 25 Sep 2023 20:04:56 +0200
Subject: [PATCH 058/224] Fix parsing of v6 signatures with unknown hash
algorithm (#1683)
Fail on verification rather than parsing, also for unexpected salt size.
---
src/crypto/hash/index.js | 2 +-
src/packet/one_pass_signature.js | 6 ++--
src/packet/signature.js | 13 ++++---
test/general/signature.js | 62 ++++++++++++++++++++++++++++++--
4 files changed, 70 insertions(+), 13 deletions(-)
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index 617b59a9c..0943b82f7 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -101,7 +101,7 @@ export default {
case enums.hash.sha3_512:
return this.sha3_512(data);
default:
- throw new Error('Invalid hash function.');
+ throw new Error('Unsupported hash function');
}
},
diff --git a/src/packet/one_pass_signature.js b/src/packet/one_pass_signature.js
index 9018e79f6..5676c8e62 100644
--- a/src/packet/one_pass_signature.js
+++ b/src/packet/one_pass_signature.js
@@ -16,7 +16,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import * as stream from '@openpgp/web-stream-tools';
-import SignaturePacket, { saltLengthForHash } from './signature';
+import SignaturePacket from './signature';
import KeyID from '../type/keyid';
import enums from '../enums';
import util from '../util';
@@ -116,10 +116,8 @@ class OnePassSignaturePacket {
// A one-octet salt size. The value MUST match the value defined
// for the hash algorithm as specified in Table 23 (Hash algorithm registry).
+ // To allow parsing unknown hash algos, we only check the expected salt length when verifying.
const saltLength = bytes[mypos++];
- if (saltLength !== saltLengthForHash(this.hashAlgorithm)) {
- throw new Error('Unexpected salt size for the hash algorithm');
- }
// The salt; a random value value of the specified size.
this.salt = bytes.subarray(mypos, mypos + saltLength);
diff --git a/src/packet/signature.js b/src/packet/signature.js
index 6ab5a6a43..a66fbd493 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -145,10 +145,8 @@ class SignaturePacket {
if (this.version === 6) {
// A one-octet salt size. The value MUST match the value defined
// for the hash algorithm as specified in Table 23 (Hash algorithm registry).
+ // To allow parsing unknown hash algos, we only check the expected salt length when verifying.
const saltLength = bytes[i++];
- if (saltLength !== saltLengthForHash(this.hashAlgorithm)) {
- throw new Error('Unexpected salt size for the hash algorithm');
- }
// The salt; a random value value of the specified size.
this.salt = bytes.subarray(i, i + saltLength);
@@ -699,6 +697,11 @@ class SignaturePacket {
}
async hash(signatureType, data, toHash, detached = false) {
+ if (this.version === 6 && this.salt.length !== saltLengthForHash(this.hashAlgorithm)) {
+ // avoid hashing unexpected salt size
+ throw new Error('Signature salt does not have the expected length');
+ }
+
if (!toHash) toHash = this.toHash(signatureType, data, detached);
return crypto.hash.digest(this.hashAlgorithm, toHash);
}
@@ -827,7 +830,7 @@ function writeSubPacket(type, critical, data) {
* @returns {Integer} Salt length.
* @private
*/
-export function saltLengthForHash(hashAlgorithm) {
+function saltLengthForHash(hashAlgorithm) {
switch (hashAlgorithm) {
case enums.hash.sha256: return 16;
case enums.hash.sha384: return 24;
@@ -835,6 +838,6 @@ export function saltLengthForHash(hashAlgorithm) {
case enums.hash.sha224: return 16;
case enums.hash.sha3_256: return 16;
case enums.hash.sha3_512: return 32;
- default: throw new Error('Unsupported hash function for V6 signatures');
+ default: throw new Error('Unsupported hash function');
}
}
diff --git a/test/general/signature.js b/test/general/signature.js
index 5a58dd1b6..5580fedd5 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -790,6 +790,31 @@ kCNcH9WI6idSzFjuYegECf+ZA1xOCjS9oLTGbSeT7jNfC8dH5+E92qlBLq4Ctt7k
await expect(openpgp.readSignature({ armoredSignature })).to.be.rejectedWith(/Missing signature creation time/);
});
+ it('Supports parsing v6 signature with unknown hash algo', async function () {
+ // v6 signatures must check that the salt size is correct.
+ // but we want to support parsing signatures with unknown hash algos.
+ // this test checks that the parsing succeeds, while signing/verification fails.
+
+ // key with direct signature of unknown hash algo 99
+ const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGZN8edBsAAAAgdUMlFMFCVKNo7sdUd6FVBos6NNjpUpSdrodk6BfPb/kA
++3buA2+WY2LwyxlX5o07WR2VSn+wuegC3v28yO0tClHCtwYfG2MAAABIBYJk
+3x50BAsJCAcHFQ4MCgkICwIWAAIXgAKbAwIeCSIhBpbSe0QWuaCNSSLaePhX
+EP3BxQ2VHX3WpW1U6svHvCUiBScJAgcCAAAAACMZIP8aHixoyC9wS3q/TNV/
+IfOQa81f+U5Ucz6H4I+c5bWRYUzH/piBB4n5FoYlld+/SViCQIBCQ+fynLma
+j5wlf22+mISTt/9je1ZfYWlJ+WSJyi5gY5EH9DubfuIU3VaqCM0aQmVybmFk
+ZXR0ZSA8YkBleGFtcGxlLm9yZz7CugYTGw4AAABLBYJk3x50BAsJCAcHFQ4M
+CgkICwIWAAIXgAIZAQKbAwIeCSIhBpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3W
+pW1U6svHvCUiBScJAgcCAAAAAMMGIJEi9+yqkFKsNwX1H5II0riPudFpwBx2
+ypVjNk4aNb7Exl56Aac4tXEhz4fH41q0dAzFww2erZaiUqmohQ4AFSw1jN/W
+OiDfb1DkjT/HJ8vXMGpwWdgFPoqsWzTNhd5VCQ==
+-----END PGP PRIVATE KEY BLOCK-----`;
+
+ const key = await openpgp.readKey({ armoredKey });
+ await expect(key.getSigningKey()).to.be.rejectedWith(/Unsupported hash function/);
+ });
+
it('Ignores marker packets when verifying signatures', async function () {
const signatureWithMarkerPacket = `-----BEGIN PGP SIGNATURE-----
@@ -914,9 +939,7 @@ SlcdMBDgwngEGBYIAAkFAmFppjQCGwwAIQkQDmTSjoPv10MWIQRqj/4SGmAk
ibGeE60OZNKOg+/XQx/EAQCM0UYrObp60YbOCxu07Dm6XjCVylbOcsaxCnE7
2eMU4AD+OkgajZgbqSIdAR1ud76FW+W+3xlDi/SMFdU7D49SbQI=
=ASQu
------END PGP PRIVATE KEY BLOCK-----
-
-`;
+-----END PGP PRIVATE KEY BLOCK-----`;
const armoredMessage = `-----BEGIN PGP MESSAGE-----
xA0DAQoWDmTSjoPv10MByw91AGFpplFwbGFpbnRleHTCdQQBFgoABgUCYWml
@@ -1062,6 +1085,39 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
expect(await sigInfo.verified).to.be.true;
});
+ it('Verification fails if v6 signature has unexpected salt length', async function() {
+ // signature with salt shorter than expected
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+xEQGAQoWHgTCf3OkPcYPPB6GmoMeaOz1wYXbuSvHxW/PVbRIynPv5yU3YApt
+KDJPb4mCbmxvCoKjGx6CMjDpDsVB+wDFAcsLdQBlEWcKaGVsbG/CmgYBFgoA
+AAApBYJlEWcKIqEGc+/nJTdgCm0oMk9viYJubG8KgqMbHoIyMOkOxUH7AMUA
+AAAA5GYeBMJ/c6Q9xg88Hoaagx5o7PXBhdu5K8fFb89VtEjKAQCW/XwAPo2V
+ugvc1634oGA/74j7KonU2qdl0LvxVJuB2wEAtutHh3wry/SNkc+japCGO4u4
+XjIVmkzQNtymmOECUwI=
+-----END PGP MESSAGE-----`;
+ const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xVoGZRFjtxYAAAAtCSsGAQQB2kcPAQEHQJRcfAi8wlCCWAeBcvpRO6iL5YK8
+1e8BVcOkAGVXKDguAAEAxIUb1xswIKPfVEyOZkqSFukVOegoArxIeEuDaoK0
+feXCrQYfFgoAAAA6BYJlEWO3AwsJBwMVCAoCFgACmwMCHgEioQZz7+clN2AK
+bSgyT2+Jgm5sbwqCoxsegjIw6Q7FQfsAxQAAAACBKyDA5Ih9cWlc9o5NUzmo
+jSCtKhy54bBzfRX0t9Jha4BfZwD9FvmhOEpJAnYRDmBrEiaO4okM3D6eNZz9
+rmGZkLT9oJMBAI6UbwsjgWw42W85Kb57tfYdF/779TrLHcNRZLNV0p8NzQDC
+nwYQFgoAAAAsBYJlEWO3AhkBIqEGc+/nJTdgCm0oMk9viYJubG8KgqMbHoIy
+MOkOxUH7AMUAAAAAV2kgOkNvj/g+Q6hFcHcpRFekCUxOons+JgXE+lxuKnbt
+l10BAO7pYlHAee5dxkzQI3WPiiYFt/OYrnr7fT5QadRZhAutAP9n5bvQaoLX
+vfHp79dKJnU1qDnSTEshB7ytt9I3Ze+DAQ==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const { signatures } = await openpgp.verify({
+ message: await openpgp.readMessage({ armoredMessage }),
+ verificationKeys: key
+ });
+ expect(signatures).to.have.length(1);
+ await expect(signatures[0].verified).to.be.rejectedWith(/Signature salt does not have the expected length/);
+ });
+
it('Reject cleartext message with arbitrary text added around hash headers (spoofed cleartext message)', async function() {
await expect(openpgp.readCleartextMessage({ cleartextMessage: `-----BEGIN PGP SIGNED MESSAGE-----
This is not signed but you might think it is Hash: SHA512
From 105b3cdde4af84088ec10a6a01363bb24537f7b2 Mon Sep 17 00:00:00 2001
From: larabr
Date: Thu, 19 Oct 2023 14:22:31 +0200
Subject: [PATCH 059/224] Disregard `config.aeadProtect` when encrypting to
public keys (#1678)
Determine whether AEAD should be used for encryption solely based the encryption key preferences.
Previously, the config flag was also used to control the behaviour, since AEAD messages were not standardised nor widely supported.
To generate keys that declare AEAD in their preferences, use `generateKey` with `config.aeadProtect = true`.
---
src/config/config.js | 9 ++--
src/key/helper.js | 6 ++-
test/general/openpgp.js | 111 +++++++++++++++++++++++++++-------------
3 files changed, 87 insertions(+), 39 deletions(-)
diff --git a/src/config/config.js b/src/config/config.js
index 2b8c35f1c..3f93e7200 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -42,12 +42,15 @@ export default {
* @property {Integer} deflateLevel Default zip/zlib compression level, between 1 and 9
*/
deflateLevel: 6,
-
/**
* Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption.
+ * This option is applicable to:
+ * - key generation (encryption key preferences),
+ * - password-based message encryption, and
+ * - private key encryption.
+ * In the case of message encryption using public keys, the encryption key preferences are respected instead.
* Note: not all OpenPGP implementations are compatible with this option.
- * **FUTURE OPENPGP.JS VERSIONS MAY BREAK COMPATIBILITY WHEN USING THIS OPTION**
- * @see {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07|RFC4880bis-07}
+ * @see {@link https://tools.ietf.org/html/draft-ietf-openpgp-crypto-refresh-10.html|draft-crypto-refresh-10}
* @memberof module:config
* @property {Boolean} aeadProtect
*/
diff --git a/src/key/helper.js b/src/key/helper.js
index 15ed43701..852a0c403 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -168,7 +168,11 @@ export async function getPreferredCompressionAlgo(keys = [], date = new Date(),
*/
export async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [], config = defaultConfig) {
const selfSigs = await Promise.all(keys.map((key, i) => key.getPrimarySelfSignature(date, userIDs[i], config)));
- if (config.aeadProtect && selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2)) {
+ const withAEAD = keys.length ?
+ selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2) :
+ config.aeadProtect;
+
+ if (withAEAD) {
const defaultCipherSuite = { symmetricAlgo: enums.symmetric.aes128, aeadAlgo: enums.aead.ocb };
const desiredCipherSuite = { symmetricAlgo: config.preferredSymmetricAlgorithm, aeadAlgo: config.preferredAEADAlgorithm };
return selfSigs.every(selfSig => selfSig.preferredCipherSuites && selfSig.preferredCipherSuites.some(
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 948e88624..2ca7bdbd9 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -2040,13 +2040,6 @@ aOU=
});
describe('encrypt - unit tests', function() {
- it('Does not encrypt to expired key (expiration time subpacket on a direct-key signature)', async function() {
- const expiredKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature });
- await expect(
- openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey })
- ).to.be.rejectedWith(/Primary key is expired/);
- });
-
it('should output message of expected format', async function() {
const passwords = 'password';
const text = 'test';
@@ -2213,6 +2206,55 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
});
expect(decrypted.data).to.equal('test');
});
+
+ it('does not encrypt to expired key (expiration time subpacket on a direct-key signature)', async function() {
+ const expiredKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature });
+ await expect(
+ openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey })
+ ).to.be.rejectedWith(/Primary key is expired/);
+ });
+
+ it('uses AEAD when the encryption key prefs support it (SEIPv2', async function() {
+ const v4PrivateKeyWithOCBPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const v6PrivateKeyWithOCBPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const encrypted = await openpgp.encrypt({
+ message: await openpgp.createMessage({ text: 'test' }),
+ encryptionKeys: [v4PrivateKeyWithOCBPref, v6PrivateKeyWithOCBPref],
+ format: 'object'
+ });
+
+ const seipd = encrypted.packets[2];
+ expect(seipd).to.be.instanceOf(openpgp.SymEncryptedIntegrityProtectedDataPacket);
+ expect(seipd.version).to.equal(2);
+ expect(seipd.aeadAlgorithm).to.equal(openpgp.enums.aead.ocb);
+ });
});
describe('encryptSessionKey - unit tests', function() {
@@ -2241,34 +2283,6 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
})).to.be.rejectedWith(/No encryption keys or passwords provided/);
});
- it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
- const passwords = 'password';
- // Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
- const armoredMessage = `-----BEGIN PGP MESSAGE-----
-Comment: Encrypted using AES with 128-bit key
-Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
-
-wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
-YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
-XfA3pqV4mTzF
------END PGP MESSAGE-----`;
- const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
-
- try {
- const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
- message: await openpgp.readMessage({ armoredMessage }),
- passwords
- });
- expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
- expect(decryptedSessionKey.algorithm).to.equal('aes128');
- } catch (err) {
- if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
- expect(err.message).to.match(/Could not allocate required memory/);
- }
- }
-
- });
-
// keep this after the 'memory-heavy' test to confirm that the Wasm module was successfully reloaded
it('supports encrypting with argon2 s2k', async function() {
const config = { s2kType: openpgp.enums.s2k.argon2 };
@@ -2349,6 +2363,33 @@ k0mXubZvyl4GBg==
expect(sessionKeys).to.have.length(1);
expect(sessionKeys[0].algorithm).to.equal(null); // PKESK v6 does not include the algo info
});
+
+ it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
+ const passwords = 'password';
+ // Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+Comment: Encrypted using AES with 128-bit key
+Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
+
+wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
+YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
+XfA3pqV4mTzF
+-----END PGP MESSAGE-----`;
+ const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
+
+ try {
+ const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
+ message: await openpgp.readMessage({ armoredMessage }),
+ passwords
+ });
+ expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
+ expect(decryptedSessionKey.algorithm).to.equal('aes128');
+ } catch (err) {
+ if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
+ expect(err.message).to.match(/Could not allocate required memory/);
+ }
+ }
+ });
});
describe('encrypt, decrypt, sign, verify - integration tests', function() {
From 1ebf7034f57d717be361461654c9d5c4d0dcc293 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 28 Mar 2023 19:26:40 +0200
Subject: [PATCH 060/224] `crypto-refresh`: add support for Ed448
---
package-lock.json | 36 ++++++++++++---
package.json | 3 +-
src/crypto/crypto.js | 49 ++++++++++++++++-----
src/crypto/public_key/elliptic/ecdh_x.js | 13 ++++++
src/crypto/public_key/elliptic/eddsa.js | 46 +++++++++++++++----
src/crypto/signature.js | 15 +++++--
src/key/helper.js | 3 ++
test/crypto/crypto.js | 15 +++++++
test/general/key.js | 28 ++++++++++++
test/general/openpgp.js | 56 ++++++++++++++++++++++++
10 files changed, 232 insertions(+), 32 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f1439c747..feafc4e0c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,8 @@
"@openpgp/asmcrypto.js": "^3.0.0",
"@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
- "@openpgp/noble-hashes": "^1.3.2-1",
+ "@openpgp/noble-curves": "^1.2.1-0",
+ "@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
"@openpgp/web-stream-tools": "^0.0.14",
@@ -660,10 +661,22 @@
"node": ">=10"
}
},
+ "node_modules/@openpgp/noble-curves": {
+ "version": "1.2.1-0",
+ "resolved": "https://registry.npmjs.org/@openpgp/noble-curves/-/noble-curves-1.2.1-0.tgz",
+ "integrity": "sha512-RUJ3NIGJ04VbUHEOXYxXKKgD+u7D5fJYUox3Ewu1mPbgdjEUvS96nq6xZrCPCCyOTJlyh7jR1tcbOUzWJFiJbQ==",
+ "dev": true,
+ "dependencies": {
+ "@openpgp/noble-hashes": "1.3.3-0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/@openpgp/noble-hashes": {
- "version": "1.3.2-1",
- "resolved": "https://registry.npmjs.org/@openpgp/noble-hashes/-/noble-hashes-1.3.2-1.tgz",
- "integrity": "sha512-4pmVh5O+bq1vO4xIAQXh0m7AxasEidFmHA1zm3Fk46IsLObz8pI43EyuLdwqs/6cmL6vAUCde/Xh2MYrVZd5bw==",
+ "version": "1.3.3-0",
+ "resolved": "https://registry.npmjs.org/@openpgp/noble-hashes/-/noble-hashes-1.3.3-0.tgz",
+ "integrity": "sha512-2MOWNAzEm5fMu3u90HSLxddYU6Fr8P7/7knXrPHyS7DiJevOlDmPES/AZxcWQfhHrwdNLL0fRVdOHkftvIcXVQ==",
"dev": true,
"dependencies": {
"@types/bn.js": "^4.11.6",
@@ -8145,10 +8158,19 @@
}
}
},
+ "@openpgp/noble-curves": {
+ "version": "1.2.1-0",
+ "resolved": "https://registry.npmjs.org/@openpgp/noble-curves/-/noble-curves-1.2.1-0.tgz",
+ "integrity": "sha512-RUJ3NIGJ04VbUHEOXYxXKKgD+u7D5fJYUox3Ewu1mPbgdjEUvS96nq6xZrCPCCyOTJlyh7jR1tcbOUzWJFiJbQ==",
+ "dev": true,
+ "requires": {
+ "@openpgp/noble-hashes": "1.3.3-0"
+ }
+ },
"@openpgp/noble-hashes": {
- "version": "1.3.2-1",
- "resolved": "https://registry.npmjs.org/@openpgp/noble-hashes/-/noble-hashes-1.3.2-1.tgz",
- "integrity": "sha512-4pmVh5O+bq1vO4xIAQXh0m7AxasEidFmHA1zm3Fk46IsLObz8pI43EyuLdwqs/6cmL6vAUCde/Xh2MYrVZd5bw==",
+ "version": "1.3.3-0",
+ "resolved": "https://registry.npmjs.org/@openpgp/noble-hashes/-/noble-hashes-1.3.3-0.tgz",
+ "integrity": "sha512-2MOWNAzEm5fMu3u90HSLxddYU6Fr8P7/7knXrPHyS7DiJevOlDmPES/AZxcWQfhHrwdNLL0fRVdOHkftvIcXVQ==",
"dev": true,
"requires": {
"@types/bn.js": "^4.11.6",
diff --git a/package.json b/package.json
index d73390ece..c8b4f351b 100644
--- a/package.json
+++ b/package.json
@@ -63,9 +63,10 @@
},
"devDependencies": {
"@openpgp/asmcrypto.js": "^3.0.0",
+ "@openpgp/noble-curves": "^1.2.1-0",
"@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
- "@openpgp/noble-hashes": "^1.3.2-1",
+ "@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.3",
"@openpgp/web-stream-tools": "^0.0.14",
diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js
index fa252a09f..bdb3fd287 100644
--- a/src/crypto/crypto.js
+++ b/src/crypto/crypto.js
@@ -32,7 +32,6 @@ import KDFParams from '../type/kdf_params';
import enums from '../enums';
import util from '../util';
import OID from '../type/oid';
-import { CurveWithOID } from './public_key/elliptic/oid_curves';
import { UnsupportedError } from '../packet/packet';
import ECDHXSymmetricKey from '../type/ecdh_x_symkey';
@@ -182,8 +181,9 @@ export function parsePublicKeyParams(algo, bytes) {
return { read: read, publicParams: { oid, Q, kdfParams } };
}
case enums.publicKey.ed25519:
+ case enums.publicKey.ed448:
case enums.publicKey.x25519: {
- const A = bytes.subarray(read, read + 32); read += A.length;
+ const A = bytes.subarray(read, read + getCurvePayloadSize(algo)); read += A.length;
return { read, publicParams: { A } };
}
default:
@@ -217,19 +217,21 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) {
}
case enums.publicKey.ecdsa:
case enums.publicKey.ecdh: {
- const curve = new CurveWithOID(publicParams.oid);
+ const payloadSize = getCurvePayloadSize(algo, publicParams.oid);
let d = util.readMPI(bytes.subarray(read)); read += d.length + 2;
- d = util.leftPad(d, curve.payloadSize);
+ d = util.leftPad(d, payloadSize);
return { read, privateParams: { d } };
}
case enums.publicKey.eddsaLegacy: {
- const curve = new CurveWithOID(publicParams.oid);
+ const payloadSize = getCurvePayloadSize(algo, publicParams.oid);
let seed = util.readMPI(bytes.subarray(read)); read += seed.length + 2;
- seed = util.leftPad(seed, curve.payloadSize);
+ seed = util.leftPad(seed, payloadSize);
return { read, privateParams: { seed } };
}
- case enums.publicKey.ed25519: {
- const seed = bytes.subarray(read, read + 32); read += seed.length;
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448: {
+ const payloadSize = getCurvePayloadSize(algo);
+ const seed = bytes.subarray(read, read + payloadSize); read += seed.length;
return { read, privateParams: { seed } };
}
case enums.publicKey.x25519: {
@@ -296,7 +298,7 @@ export function parseEncSessionKeyParams(algo, bytes) {
*/
export function serializeParams(algo, params) {
// Some algorithms do not rely on MPIs to store the binary params
- const algosWithNativeRepresentation = new Set([enums.publicKey.ed25519, enums.publicKey.x25519]);
+ const algosWithNativeRepresentation = new Set([enums.publicKey.ed25519, enums.publicKey.x25519, enums.publicKey.ed448]);
const orderedParams = Object.keys(params).map(name => {
const param = params[name];
if (!util.isUint8Array(param)) return param.write();
@@ -343,6 +345,7 @@ export function generateParams(algo, bits, oid) {
}
}));
case enums.publicKey.ed25519:
+ case enums.publicKey.ed448:
return publicKey.elliptic.eddsa.generate(algo).then(({ A, seed }) => ({
privateParams: { seed },
publicParams: { A }
@@ -402,7 +405,8 @@ export async function validateParams(algo, publicParams, privateParams) {
const { seed } = privateParams;
return publicKey.elliptic.eddsaLegacy.validateParams(oid, Q, seed);
}
- case enums.publicKey.ed25519: {
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448: {
const { A } = publicParams;
const { seed } = privateParams;
return publicKey.elliptic.eddsa.validateParams(algo, A, seed);
@@ -469,7 +473,29 @@ function checkSupportedCurve(oid) {
}
/**
- * Get preferred hash algo for a given elliptic algo
+ * Get encoded secret size for a given elliptic algo
+ * @param {module:enums.publicKey} algo - alrogithm identifier
+ * @param {module:type/oid} [oid] - curve OID if needed by algo
+ */
+export function getCurvePayloadSize(algo, oid) {
+ switch (algo) {
+ case enums.publicKey.ecdsa:
+ case enums.publicKey.ecdh:
+ case enums.publicKey.eddsaLegacy:
+ return new publicKey.elliptic.CurveWithOID(oid).payloadSize;
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448:
+ return publicKey.elliptic.eddsa.getPayloadSize(algo);
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448:
+ return publicKey.elliptic.ecdhX.getPayloadSize(algo);
+ default:
+ throw new Error('Unknown elliptic algo');
+ }
+}
+
+/**
+ * Get preferred signing hash algo for a given elliptic algo
* @param {module:enums.publicKey} algo - alrogithm identifier
* @param {module:type/oid} [oid] - curve OID if needed by algo
*/
@@ -479,6 +505,7 @@ export function getPreferredCurveHashAlgo(algo, oid) {
case enums.publicKey.eddsaLegacy:
return publicKey.elliptic.getPreferredHashAlgo(oid);
case enums.publicKey.ed25519:
+ case enums.publicKey.ed448:
return publicKey.elliptic.eddsa.getPreferredHashAlgo(algo);
default:
throw new Error('Unknown elliptic signing algo');
diff --git a/src/crypto/public_key/elliptic/ecdh_x.js b/src/crypto/public_key/elliptic/ecdh_x.js
index 1e0b38611..d5d3f10e1 100644
--- a/src/crypto/public_key/elliptic/ecdh_x.js
+++ b/src/crypto/public_key/elliptic/ecdh_x.js
@@ -120,3 +120,16 @@ export async function decrypt(algo, ephemeralPublicKey, wrappedKey, A, k) {
throw new Error('Unsupported ECDH algorithm');
}
}
+
+export function getPayloadSize(algo) {
+ switch (algo) {
+ case enums.publicKey.x25519:
+ return 32;
+
+ case enums.publicKey.x448:
+ return 56;
+
+ default:
+ throw new Error('Unsupported ECDH algorithm');
+ }
+}
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index 002f3f294..bcab724f7 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -21,13 +21,14 @@
*/
import { sha512 } from '@openpgp/noble-hashes/sha512';
-import nacl from '@openpgp/tweetnacl/nacl-fast-light';
+import ed25519 from '@openpgp/tweetnacl/nacl-fast-light';
+import { ed448 } from '@openpgp/noble-curves/ed448';
import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
import { getRandomBytes } from '../../random';
-nacl.hash = bytes => sha512(bytes);
+ed25519.hash = bytes => sha512(bytes);
/**
* Generate (non-legacy) EdDSA key
@@ -35,10 +36,15 @@ nacl.hash = bytes => sha512(bytes);
* @returns {Promise<{ A: Uint8Array, seed: Uint8Array }>}
*/
export async function generate(algo) {
+ const seed = getRandomBytes(getPayloadSize(algo));
+
switch (algo) {
case enums.publicKey.ed25519: {
- const seed = getRandomBytes(32);
- const { publicKey: A } = nacl.sign.keyPair.fromSeed(seed);
+ const { publicKey: A } = ed25519.sign.keyPair.fromSeed(seed);
+ return { A, seed };
+ }
+ case enums.publicKey.ed448: {
+ const A = ed448.getPublicKey(seed);
return { A, seed };
}
default:
@@ -66,10 +72,13 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
switch (algo) {
case enums.publicKey.ed25519: {
const secretKey = util.concatUint8Array([privateKey, publicKey]);
- const signature = nacl.sign.detached(hashed, secretKey);
+ const signature = ed25519.sign.detached(hashed, secretKey);
+ return { RS: signature };
+ }
+ case enums.publicKey.ed448: {
+ const signature = ed448.sign(hashed, privateKey);
return { RS: signature };
}
- case enums.publicKey.ed448:
default:
throw new Error('Unsupported EdDSA algorithm');
}
@@ -93,9 +102,10 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
}
switch (algo) {
case enums.publicKey.ed25519: {
- return nacl.sign.detached.verify(hashed, RS, publicKey);
+ return ed25519.sign.detached.verify(hashed, RS, publicKey);
}
case enums.publicKey.ed448:
+ return ed448.verify(RS, hashed, publicKey);
default:
throw new Error('Unsupported EdDSA algorithm');
}
@@ -116,20 +126,38 @@ export async function validateParams(algo, A, seed) {
* Derive public point A' from private key
* and expect A == A'
*/
- const { publicKey } = nacl.sign.keyPair.fromSeed(seed);
+ const { publicKey } = ed25519.sign.keyPair.fromSeed(seed);
return util.equalsUint8Array(A, publicKey);
}
- case enums.publicKey.ed448: // unsupported
+ case enums.publicKey.ed448: {
+ const publicKey = ed448.getPublicKey(seed);
+ return util.equalsUint8Array(A, publicKey);
+ }
default:
return false;
}
}
+export function getPayloadSize(algo) {
+ switch (algo) {
+ case enums.publicKey.ed25519:
+ return 32;
+
+ case enums.publicKey.ed448:
+ return 57;
+
+ default:
+ throw new Error('Unsupported EdDSA algorithm');
+ }
+}
+
export function getPreferredHashAlgo(algo) {
switch (algo) {
case enums.publicKey.ed25519:
return enums.hash.sha256;
+ case enums.publicKey.ed448:
+ return enums.hash.sha512;
default:
throw new Error('Unknown EdDSA algo');
}
diff --git a/src/crypto/signature.js b/src/crypto/signature.js
index 00c7086c1..5d3db48de 100644
--- a/src/crypto/signature.js
+++ b/src/crypto/signature.js
@@ -56,10 +56,15 @@ export function parseSignatureParams(algo, signature) {
}
// Algorithm-Specific Fields for Ed25519 signatures:
// - 64 octets of the native signature
- case enums.publicKey.ed25519: {
- const RS = signature.subarray(read, read + 64); read += RS.length;
+ // Algorithm-Specific Fields for Ed448 signatures:
+ // - 114 octets of the native signature
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448: {
+ const rsSize = 2 * publicKey.elliptic.eddsa.getPayloadSize(algo);
+ const RS = signature.subarray(read, read + rsSize); read += RS.length;
return { RS };
}
+
default:
throw new UnsupportedError('Unknown signature algorithm.');
}
@@ -106,7 +111,8 @@ export async function verify(algo, hashAlgo, signature, publicParams, data, hash
// signature already padded on parsing
return publicKey.elliptic.eddsaLegacy.verify(oid, hashAlgo, signature, data, Q, hashed);
}
- case enums.publicKey.ed25519: {
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448: {
const { A } = publicParams;
return publicKey.elliptic.eddsa.verify(algo, hashAlgo, signature, data, A, hashed);
}
@@ -160,7 +166,8 @@ export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, da
const { seed } = privateKeyParams;
return publicKey.elliptic.eddsaLegacy.sign(oid, hashAlgo, data, Q, seed, hashed);
}
- case enums.publicKey.ed25519: {
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448: {
const { A } = publicKeyParams;
const { seed } = privateKeyParams;
return publicKey.elliptic.eddsa.sign(algo, hashAlgo, data, A, seed, hashed);
diff --git a/src/key/helper.js b/src/key/helper.js
index 852a0c403..d2795a89a 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -127,8 +127,10 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us
case enums.publicKey.ecdsa:
case enums.publicKey.eddsaLegacy:
case enums.publicKey.ed25519:
+ case enums.publicKey.ed448:
prefAlgo = crypto.getPreferredCurveHashAlgo(keyPacket.algorithm, keyPacket.publicParams.oid);
}
+
return crypto.hash.getHashByteLength(hashAlgo) <= crypto.hash.getHashByteLength(prefAlgo) ?
prefAlgo : hashAlgo;
}
@@ -365,6 +367,7 @@ export function isValidEncryptionKeyPacket(keyPacket, signature) {
keyAlgo !== enums.publicKey.ecdsa &&
keyAlgo !== enums.publicKey.eddsaLegacy &&
keyAlgo !== enums.publicKey.ed25519 &&
+ keyAlgo !== enums.publicKey.ed448 &&
(!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0);
diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js
index e5bbeaf92..1d017d84d 100644
--- a/test/crypto/crypto.js
+++ b/test/crypto/crypto.js
@@ -229,6 +229,21 @@ export default () => describe('API functional testing', function() {
return expect(success).to.be.true;
});
+
+ it('Ed448', async function () {
+ // key data from https://www.rfc-editor.org/rfc/rfc8032#section-7.4
+ const seed = util.hexToUint8Array('d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bff21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01');
+ const A = util.hexToUint8Array('df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00');
+ const toSign = await crypto.hash.digest(openpgp.enums.hash.sha512, data);
+ const signedData = await crypto.signature.sign(
+ openpgp.enums.publicKey.ed448, openpgp.enums.hash.sha512, { A }, { seed }, data, toSign
+ );
+ const success = await crypto.signature.verify(
+ openpgp.enums.publicKey.ed448, openpgp.enums.hash.sha512, signedData, { A }, data, toSign
+ );
+
+ return expect(success).to.be.true;
+ });
});
describe('Encrypt and decrypt', function () {
diff --git a/test/general/key.js b/test/general/key.js
index 68d956d5f..0a2fb66ac 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -3220,6 +3220,34 @@ aU71tdtNBQ==
expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x25519' });
});
+ it('Parsing V4 key using curve448 format', async function() {
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT
++hLeV6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVs
+IU7QqLv1hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoA
+AAA9BQJlGotiIqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUC
+GwMCHgkCCwcDFQoIAhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vH
+z43Wb++AkmpWL1HQmrJE3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiW
+QSeMeexCTy+Gdr6j0wb4FhFNnoIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmK
+gQTSOzJEvyO0ACR5L4vV3ADceOAdG8/sqhE89rTSevFXng4JAM0XVXNlckEg
+PFVzZXJBQHRlc3QudGVzdD7CwA0GExwKAAAALAUCZRqLYiKhBgMYnbB0Rw7M
+hU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkBAAAAAFw/IH72M1iyzMWhbgtw
+v0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOjm7VAeOSfSdxt1xSKnoAL
+RsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qAmc+K5jdA2xcl9iW5
+bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGvgqe00ohRKiQA
+-----END PGP PRIVATE KEY BLOCK-----` });
+ // sanity checks
+ await expect(privateKey.validate()).to.be.fulfilled;
+ const signingKey = await privateKey.getSigningKey();
+ expect(signingKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.ed448);
+ expect(signingKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'ed448' });
+
+ // const encryptionKey = await privateKey.getEncryptionKey();
+ // expect(encryptionKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.x25519);
+ // expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x25519' });
+ });
+
it('Testing key ID and fingerprint for V4 keys', async function() {
const pubKeysV4 = await openpgp.readKeys({ armoredKeys: twoKeys });
expect(pubKeysV4).to.exist;
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index 2ca7bdbd9..e159f30b6 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -4423,6 +4423,62 @@ J/qaHc+qmcEpIMmPNvLQ7n4F4kEXk8Zwz+OXovVWLQ+Njl5gzooF
expect(signatures).to.have.length(1);
expect(await signatures[0].verified).to.be.true;
});
+
+ it('sign/verify with Ed448', async function () {
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT
++hLeV6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVs
+IU7QqLv1hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoA
+AAA9BQJlGotiIqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUC
+GwMCHgkCCwcDFQoIAhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vH
+z43Wb++AkmpWL1HQmrJE3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiW
+QSeMeexCTy+Gdr6j0wb4FhFNnoIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmK
+gQTSOzJEvyO0ACR5L4vV3ADceOAdG8/sqhE89rTSevFXng4JAM0XVXNlckEg
+PFVzZXJBQHRlc3QudGVzdD7CwA0GExwKAAAALAUCZRqLYiKhBgMYnbB0Rw7M
+hU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkBAAAAAFw/IH72M1iyzMWhbgtw
+v0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOjm7VAeOSfSdxt1xSKnoAL
+RsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qAmc+K5jdA2xcl9iW5
+bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGvgqe00ohRKiQA
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const plaintext = 'plaintext';
+
+ const signed = await openpgp.sign({
+ message: await openpgp.createMessage({ text: plaintext }),
+ signingKeys: privateKey
+ });
+
+ const { signatures, data } = await openpgp.verify({
+ message: await openpgp.readMessage({ armoredMessage: signed }),
+ verificationKeys: privateKey
+ });
+ expect(data).to.equal(plaintext);
+ expect(signatures).to.have.length(1);
+ expect(await signatures[0].verified).to.be.true;
+ });
+
+ it('should enforce using 512-bit signature digest', async function () {
+ // X448 key using sha256 for self signatures
+ const privateKeySHA256 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
+5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
+x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
+HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
+BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
+Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
+8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
+tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
+y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
+ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
+BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
+6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
+JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
+x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ await expect(privateKeySHA256.getSigningKey()).to.be.rejectedWith(/Hash algorithm too weak for EdDSA/);
+ });
});
describe('Errors', function() {
From 56cd448a3219a4174ca29a51734a41f26620047e Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 30 Mar 2023 15:35:50 +0200
Subject: [PATCH 061/224] `crypto-refresh`: add support for X448
---
src/crypto/crypto.js | 38 ++++++---
src/crypto/public_key/elliptic/ecdh_x.js | 54 +++++++++++--
src/key/helper.js | 1 +
src/message.js | 5 +-
.../public_key_encrypted_session_key.js | 9 ++-
test/crypto/ecdh.js | 10 +++
test/crypto/validate.js | 55 +++++++++++++
test/general/key.js | 43 ++++++----
test/general/openpgp.js | 80 ++++++++++++++++++-
9 files changed, 253 insertions(+), 42 deletions(-)
diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js
index bdb3fd287..a9293e758 100644
--- a/src/crypto/crypto.js
+++ b/src/crypto/crypto.js
@@ -64,10 +64,11 @@ export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, dat
oid, kdfParams, data, Q, fingerprint);
return { V, C: new ECDHSymkey(C) };
}
- case enums.publicKey.x25519: {
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
if (!util.isAES(symmetricAlgo)) {
// see https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/276
- throw new Error('X25519 keys can only encrypt AES session keys');
+ throw new Error('X25519 and X448 keys can only encrypt AES session keys');
}
const { A } = publicParams;
const { ephemeralPublicKey, wrappedKey } = await publicKey.elliptic.ecdhX.encrypt(
@@ -116,7 +117,8 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
return publicKey.elliptic.ecdh.decrypt(
oid, kdfParams, V, C.data, Q, d, fingerprint);
}
- case enums.publicKey.x25519: {
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
const { A } = publicKeyParams;
const { k } = privateKeyParams;
const { ephemeralPublicKey, C } = sessionKeyParams;
@@ -182,7 +184,8 @@ export function parsePublicKeyParams(algo, bytes) {
}
case enums.publicKey.ed25519:
case enums.publicKey.ed448:
- case enums.publicKey.x25519: {
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
const A = bytes.subarray(read, read + getCurvePayloadSize(algo)); read += A.length;
return { read, publicParams: { A } };
}
@@ -234,8 +237,10 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) {
const seed = bytes.subarray(read, read + payloadSize); read += seed.length;
return { read, privateParams: { seed } };
}
- case enums.publicKey.x25519: {
- const k = bytes.subarray(read, read + 32); read += k.length;
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
+ const payloadSize = getCurvePayloadSize(algo);
+ const k = bytes.subarray(read, read + payloadSize); read += k.length;
return { read, privateParams: { k } };
}
default:
@@ -275,13 +280,15 @@ export function parseEncSessionKeyParams(algo, bytes) {
const C = new ECDHSymkey(); C.read(bytes.subarray(read));
return { V, C };
}
- // Algorithm-Specific Fields for X25519 encrypted session keys:
- // - 32 octets representing an ephemeral X25519 public key.
+ // Algorithm-Specific Fields for X25519 or X448 encrypted session keys:
+ // - 32 octets representing an ephemeral X25519 public key (or 57 octets for X448).
// - A one-octet size of the following fields.
// - The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet).
// - The encrypted session key.
- case enums.publicKey.x25519: {
- const ephemeralPublicKey = bytes.subarray(read, read + 32); read += ephemeralPublicKey.length;
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
+ const pointSize = getCurvePayloadSize(algo);
+ const ephemeralPublicKey = bytes.subarray(read, read + pointSize); read += ephemeralPublicKey.length;
const C = new ECDHXSymmetricKey(); C.read(bytes.subarray(read));
return { ephemeralPublicKey, C };
}
@@ -298,7 +305,12 @@ export function parseEncSessionKeyParams(algo, bytes) {
*/
export function serializeParams(algo, params) {
// Some algorithms do not rely on MPIs to store the binary params
- const algosWithNativeRepresentation = new Set([enums.publicKey.ed25519, enums.publicKey.x25519, enums.publicKey.ed448]);
+ const algosWithNativeRepresentation = new Set([
+ enums.publicKey.ed25519,
+ enums.publicKey.x25519,
+ enums.publicKey.ed448,
+ enums.publicKey.x448
+ ]);
const orderedParams = Object.keys(params).map(name => {
const param = params[name];
if (!util.isUint8Array(param)) return param.write();
@@ -351,6 +363,7 @@ export function generateParams(algo, bits, oid) {
publicParams: { A }
}));
case enums.publicKey.x25519:
+ case enums.publicKey.x448:
return publicKey.elliptic.ecdhX.generate(algo).then(({ A, k }) => ({
privateParams: { k },
publicParams: { A }
@@ -411,7 +424,8 @@ export async function validateParams(algo, publicParams, privateParams) {
const { seed } = privateParams;
return publicKey.elliptic.eddsa.validateParams(algo, A, seed);
}
- case enums.publicKey.x25519: {
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
const { A } = publicParams;
const { k } = privateParams;
return publicKey.elliptic.ecdhX.validateParams(algo, A, k);
diff --git a/src/crypto/public_key/elliptic/ecdh_x.js b/src/crypto/public_key/elliptic/ecdh_x.js
index d5d3f10e1..decdeaab3 100644
--- a/src/crypto/public_key/elliptic/ecdh_x.js
+++ b/src/crypto/public_key/elliptic/ecdh_x.js
@@ -3,7 +3,8 @@
* @module crypto/public_key/elliptic/ecdh
*/
-import nacl from '@openpgp/tweetnacl/nacl-fast-light';
+import x25519 from '@openpgp/tweetnacl/nacl-fast-light';
+import { x448 } from '@openpgp/noble-curves/ed448';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
@@ -13,7 +14,8 @@ import getCipher from '../../cipher/getCipher';
import computeHKDF from '../../hkdf';
const HKDF_INFO = {
- x25519: util.encodeUTF8('OpenPGP X25519')
+ x25519: util.encodeUTF8('OpenPGP X25519'),
+ x448: util.encodeUTF8('OpenPGP X448')
};
/**
@@ -26,7 +28,12 @@ export async function generate(algo) {
case enums.publicKey.x25519: {
// k stays in little-endian, unlike legacy ECDH over curve25519
const k = getRandomBytes(32);
- const { publicKey: A } = nacl.box.keyPair.fromSecretKey(k);
+ const { publicKey: A } = x25519.box.keyPair.fromSecretKey(k);
+ return { A, k };
+ }
+ case enums.publicKey.x448: {
+ const k = x448.utils.randomPrivateKey();
+ const A = x448.getPublicKey(k);
return { A, k };
}
default:
@@ -49,7 +56,15 @@ export async function validateParams(algo, A, k) {
* Derive public point A' from private key
* and expect A == A'
*/
- const { publicKey } = nacl.box.keyPair.fromSecretKey(k);
+ const { publicKey } = x25519.box.keyPair.fromSecretKey(k);
+ return util.equalsUint8Array(A, publicKey);
+ }
+ case enums.publicKey.x448: {
+ /**
+ * Derive public point A' from private key
+ * and expect A == A'
+ */
+ const publicKey = x448.getPublicKey(k);
return util.equalsUint8Array(A, publicKey);
}
@@ -74,8 +89,8 @@ export async function encrypt(algo, data, recipientA) {
switch (algo) {
case enums.publicKey.x25519: {
const ephemeralSecretKey = getRandomBytes(32);
- const sharedSecret = nacl.scalarMult(ephemeralSecretKey, recipientA);
- const { publicKey: ephemeralPublicKey } = nacl.box.keyPair.fromSecretKey(ephemeralSecretKey);
+ const sharedSecret = x25519.scalarMult(ephemeralSecretKey, recipientA);
+ const { publicKey: ephemeralPublicKey } = x25519.box.keyPair.fromSecretKey(ephemeralSecretKey);
const hkdfInput = util.concatUint8Array([
ephemeralPublicKey,
recipientA,
@@ -86,6 +101,20 @@ export async function encrypt(algo, data, recipientA) {
const wrappedKey = aesKW.wrap(encryptionKey, data);
return { ephemeralPublicKey, wrappedKey };
}
+ case enums.publicKey.x448: {
+ const ephemeralSecretKey = x448.utils.randomPrivateKey();
+ const sharedSecret = x448.getSharedSecret(ephemeralSecretKey, recipientA);
+ const ephemeralPublicKey = x448.getPublicKey(ephemeralSecretKey);
+ const hkdfInput = util.concatUint8Array([
+ ephemeralPublicKey,
+ recipientA,
+ sharedSecret
+ ]);
+ const { keySize } = getCipher(enums.symmetric.aes256);
+ const encryptionKey = await computeHKDF(enums.hash.sha512, hkdfInput, new Uint8Array(), HKDF_INFO.x448, keySize);
+ const wrappedKey = aesKW.wrap(encryptionKey, data);
+ return { ephemeralPublicKey, wrappedKey };
+ }
default:
throw new Error('Unsupported ECDH algorithm');
@@ -106,7 +135,7 @@ export async function encrypt(algo, data, recipientA) {
export async function decrypt(algo, ephemeralPublicKey, wrappedKey, A, k) {
switch (algo) {
case enums.publicKey.x25519: {
- const sharedSecret = nacl.scalarMult(k, ephemeralPublicKey);
+ const sharedSecret = x25519.scalarMult(k, ephemeralPublicKey);
const hkdfInput = util.concatUint8Array([
ephemeralPublicKey,
A,
@@ -116,6 +145,17 @@ export async function decrypt(algo, ephemeralPublicKey, wrappedKey, A, k) {
const encryptionKey = await computeHKDF(enums.hash.sha256, hkdfInput, new Uint8Array(), HKDF_INFO.x25519, keySize);
return aesKW.unwrap(encryptionKey, wrappedKey);
}
+ case enums.publicKey.x448: {
+ const sharedSecret = x448.getSharedSecret(k, ephemeralPublicKey);
+ const hkdfInput = util.concatUint8Array([
+ ephemeralPublicKey,
+ A,
+ sharedSecret
+ ]);
+ const { keySize } = getCipher(enums.symmetric.aes256);
+ const encryptionKey = await computeHKDF(enums.hash.sha512, hkdfInput, new Uint8Array(), HKDF_INFO.x448, keySize);
+ return aesKW.unwrap(encryptionKey, wrappedKey);
+ }
default:
throw new Error('Unsupported ECDH algorithm');
}
diff --git a/src/key/helper.js b/src/key/helper.js
index d2795a89a..e887ed193 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -356,6 +356,7 @@ export function isValidSigningKeyPacket(keyPacket, signature) {
keyAlgo !== enums.publicKey.elgamal &&
keyAlgo !== enums.publicKey.ecdh &&
keyAlgo !== enums.publicKey.x25519 &&
+ keyAlgo !== enums.publicKey.x448 &&
(!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.signData) !== 0);
}
diff --git a/src/message.js b/src/message.js
index 8e5c725fc..159c003e4 100644
--- a/src/message.js
+++ b/src/message.js
@@ -357,8 +357,9 @@ export class Message {
await Promise.all(encryptionKeys.map(key => key.getEncryptionKey()
.catch(() => null) // ignore key strength requirements
.then(maybeKey => {
- if (maybeKey && (maybeKey.keyPacket.algorithm === enums.publicKey.x25519) && !aeadAlgoName && !util.isAES(symmetricAlgo)) { // if AEAD is defined, then PKESK v6 are used, and the algo info is encrypted
- throw new Error('Could not generate a session key compatible with the given `encryptionKeys`: X22519 keys can only be used to encrypt AES session keys; change `config.preferredSymmetricAlgorithm` accordingly.');
+ if (maybeKey && (maybeKey.keyPacket.algorithm === enums.publicKey.x25519 || maybeKey.keyPacket.algorithm === enums.publicKey.x448) &&
+ !aeadAlgoName && !util.isAES(symmetricAlgo)) { // if AEAD is defined, then PKESK v6 are used, and the algo info is encrypted
+ throw new Error('Could not generate a session key compatible with the given `encryptionKeys`: X22519 and X448 keys can only be used to encrypt AES session keys; change `config.preferredSymmetricAlgorithm` accordingly.');
}
})
));
diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js
index 8121e32c8..2618ce321 100644
--- a/src/packet/public_key_encrypted_session_key.js
+++ b/src/packet/public_key_encrypted_session_key.js
@@ -128,7 +128,8 @@ class PublicKeyEncryptedSessionKeyPacket {
}
this.publicKeyAlgorithm = bytes[offset++];
this.encrypted = crypto.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(offset));
- if (this.version === 3 && this.publicKeyAlgorithm === enums.publicKey.x25519) {
+ if (this.version === 3 && (
+ this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448)) {
this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
}
}
@@ -200,7 +201,9 @@ class PublicKeyEncryptedSessionKeyPacket {
const { sessionKey, sessionKeyAlgorithm } = decodeSessionKey(this.version, this.publicKeyAlgorithm, decryptedData, randomSessionKey);
// v3 Montgomery curves have cleartext cipher algo
- if (this.version === 3 && this.publicKeyAlgorithm !== enums.publicKey.x25519) {
+ if (this.version === 3 && (
+ this.publicKeyAlgorithm !== enums.publicKey.x25519 && this.publicKeyAlgorithm !== enums.publicKey.x448)
+ ) {
this.sessionKeyAlgorithm = sessionKeyAlgorithm;
}
this.sessionKey = sessionKey;
@@ -224,6 +227,7 @@ function encodeSessionKey(version, keyAlgo, cipherAlgo, sessionKeyData) {
]);
}
case enums.publicKey.x25519:
+ case enums.publicKey.x448:
return sessionKeyData;
default:
throw new Error('Unsupported public key algorithm');
@@ -270,6 +274,7 @@ function decodeSessionKey(version, keyAlgo, decryptedData, randomSessionKey) {
}
}
case enums.publicKey.x25519:
+ case enums.publicKey.x448:
return {
sessionKey: decryptedData
};
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index 501f04814..4f211386e 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -189,6 +189,16 @@ export default () => describe('ECDH key exchange @lightweight', function () {
expect(await ecdhX.decrypt(openpgp.enums.publicKey.x25519, ephemeralPublicKey, wrappedKey, K_B, b)).to.deep.equal(data);
});
+ it('Successful exchange x448', async function () {
+ const { ecdhX } = elliptic_curves;
+ const data = random.getRandomBytes();
+ // Bob's keys from https://www.rfc-editor.org/rfc/rfc7748#section-6.2
+ const b = util.hexToUint8Array('1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d');
+ const K_B = util.hexToUint8Array('3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609');
+ const { ephemeralPublicKey, wrappedKey } = await ecdhX.encrypt(openpgp.enums.publicKey.x448, data, K_B);
+ expect(await ecdhX.decrypt(openpgp.enums.publicKey.x448, ephemeralPublicKey, wrappedKey, K_B, b)).to.deep.equal(data);
+ });
+
['p256', 'p384', 'p521'].forEach(curveName => {
it(`NIST ${curveName} - Successful exchange`, async function () {
const curve = new elliptic_curves.CurveWithOID(curveName);
diff --git a/test/crypto/validate.js b/test/crypto/validate.js
index 54d79ca38..3388f26b6 100644
--- a/test/crypto/validate.js
+++ b/test/crypto/validate.js
@@ -247,6 +247,61 @@ export default () => {
});
});
+ describe('Ed448/X448 parameter validation', function() {
+ let eddsaKey;
+ let ecdhXKey;
+ before(async () => {
+ eddsaKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
+5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
+x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
+HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
+BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
+Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
+8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
+tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
+y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
+ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
+BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
+6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
+JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
+x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
+-----END PGP PRIVATE KEY BLOCK-----` });
+ ecdhXKey = eddsaKey.subkeys[0];
+ });
+
+ it('Ed448 params should be valid', async function() {
+ await expect(eddsaKey.keyPacket.validate()).to.not.be.rejected;
+ });
+
+ it('detect invalid Ed448 public point', async function() {
+ const eddsaKeyPacket = await cloneKeyPacket(eddsaKey);
+ const A = eddsaKeyPacket.publicParams.A;
+ A[0]++;
+ await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+
+ const infA = new Uint8Array(A.length);
+ eddsaKeyPacket.publicParams.A = infA;
+ await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ });
+
+ it('X448 params should be valid', async function() {
+ await expect(ecdhXKey.keyPacket.validate()).to.not.be.rejected;
+ });
+
+ it('detect invalid x448 public point', async function() {
+ const ecdhXKeyPacket = await cloneKeyPacket(ecdhXKey);
+ const A = ecdhXKeyPacket.publicParams.A;
+ A[0]++;
+ await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+
+ const infA = new Uint8Array(A.length);
+ ecdhXKeyPacket.publicParams.A = infA;
+ await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ });
+ });
+
describe('RSA parameter validation', function() {
let rsaKey;
before(async () => {
diff --git a/test/general/key.js b/test/general/key.js
index 0a2fb66ac..0e5dc5ae4 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -3223,29 +3223,38 @@ aU71tdtNBQ==
it('Parsing V4 key using curve448 format', async function() {
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT
-+hLeV6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVs
-IU7QqLv1hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoA
-AAA9BQJlGotiIqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUC
-GwMCHgkCCwcDFQoIAhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vH
-z43Wb++AkmpWL1HQmrJE3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiW
-QSeMeexCTy+Gdr6j0wb4FhFNnoIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmK
-gQTSOzJEvyO0ACR5L4vV3ADceOAdG8/sqhE89rTSevFXng4JAM0XVXNlckEg
-PFVzZXJBQHRlc3QudGVzdD7CwA0GExwKAAAALAUCZRqLYiKhBgMYnbB0Rw7M
-hU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkBAAAAAFw/IH72M1iyzMWhbgtw
-v0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOjm7VAeOSfSdxt1xSKnoAL
-RsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qAmc+K5jdA2xcl9iW5
-bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGvgqe00ohRKiQA
------END PGP PRIVATE KEY BLOCK-----` });
+xX0GZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
+Y1E04mBai0pCoDiFVokwsKt3F5sAAC8lDYfVP/p3atbXJDTJB2W9WmZxIS7pUGhS
+bjlWpZB/OVTBsoIfP/2J+Hi4ESwBRfDUDgwK4aJVKsLAIAYfHAoAAAA/BQJlGoti
+IqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwMCHgkCCwcDFQoI
+AhYABScHAwcCAAAAAPiGIG2qmhCULQ/+H4rKV0XEM1x0uVY3l878Pa6ijZLouZU/
+VRd5PnbGyLPL++q3LDViUUdZ1uusRc01f677Q6wpUU90k8MH/oULwI0+KPtqe1N4
+6nr1NTERsAmAaPjUdf4ZUXX/GWiTd/AlsS5JqGnAQxKRJkzCJacOTOElRMjzGUX7
+CGaAnhSC86YRZ68ocTPfZysAzRdVc2VyQiA8VXNlckJAdGVzdC50ZXN0PsLADQYT
+HAoAAAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUC
+GQEAAAAASKwgVzMoPb2Hbr3lbNI1CRWECokYLokL7F8MbYiMnlg+v6QXLdStvT13
+ZjxdrWQAx3MbihSOUSXbdAys90yMOAdtognj+x418J/TaYFMtIGBHwoHv8gQVnx9
+9ICv8ezx1T5VvGBYNuKZ5Ww0WPEpYMf1VA+Y9JxpohdcRenNBdSug4tLWla2y8NH
+aO28Fltpb4AuGQDHewZlGotiGgAAADjdabr1ohAOnbSUUkVhtUM/LVdnYgDLhmaj
+YZ1N7TWY0fqEpMk2LLo2165HOmhddRPeTB1TWbuwBwB8lKc3czFUzYcAgvZ08T5S
+UUHjfIhjeJeY4yd0OZDfzPw1vbegCc7t94bT+XGoIQbC/Bl7HCyAiMLADQYYHAoA
+AAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwwA
+AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
+6UCpJYYk3o3hYUYzIHmCIZGVYe1pxRgIUNqxydXEfzylJmN5NbiJNkjJizrI7oAR
+1mIcEEb/hmRMOUs1V2mcGuoeALBI/r/SyqDE2GRjH6d6g1RS7ZARPPHlZlY4CTqC
+4a7L+8odDwA=
+=chx0
+-----END PGP PRIVATE KEY BLOCK-----
+ ` });
// sanity checks
await expect(privateKey.validate()).to.be.fulfilled;
const signingKey = await privateKey.getSigningKey();
expect(signingKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.ed448);
expect(signingKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'ed448' });
- // const encryptionKey = await privateKey.getEncryptionKey();
- // expect(encryptionKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.x25519);
- // expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x25519' });
+ const encryptionKey = await privateKey.getEncryptionKey();
+ expect(encryptionKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.x448);
+ expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x448' });
});
it('Testing key ID and fingerprint for V4 keys', async function() {
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index e159f30b6..c84ccd54c 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -2131,7 +2131,7 @@ mNwbfFbSNhZYWjFada77EKBn60j8QT/xCQzLR1clci7ieW2knw==
expect(data).to.equal('Hello World!');
});
- it('supports encrypting new x25519 format', async function () {
+ it('supports encrypting/decrypting new x25519 format', async function () {
// v4 key
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
@@ -2160,6 +2160,40 @@ yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
expect(data).to.equal(plaintext);
});
+ it('supports encrypting/decrypting with x448', async function () {
+ // v4 key
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZRqJ5BwHESfKnw5YJly5WobjigVm0kKY84NxrP6JKeIvIWiFqqSlozGpKZyR
+50YbVTHmxpUCuJ7YNwX0UoAAoSO8IXmMM/XMd4ph00ju+fbSHdtQfyNhfFTi3UoM
+V5DiFT+uOYDP+zwAwLWCR86csxmCWn6O10DNHcDNF1VzZXJBIDxVc2VyQUB0ZXN0
+LnRlc3Q+wroEExwKAD4FAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXA
+ivFIz7kCGwMCHgkCGQECCwcDFQoIAhYAAycHAgAA21/PqAuGDL5+3qrf3YoVOP+5
+0BoJ+ZMhzcgax+cQTyndmOZYBfOqV/SJ8mf6CRhbB76JhGIvmRMtyYDQgDMVvcoA
+yojVNs6e/Jco16bVJxM85wKDXJuq6AhtPQ8w/0WaCJtEf1uxqeQPEbOM+KtT/xY2
+KgDHeQRlGonkGuOtAhogSIU3z/+gFzF8U7JQe7QDRYr9VWfi2WXFFarzg/3DMRur
+oIB7mqkaaSatrvVuud1ZmRCWAMM4f57dvSdCKsVqSe+tlS225OmdWmnGLqyErBb6
+44E2oENhDUom9OUGUPm8dXUjQbrmw6ec9hNLHWXCpgQYHAoAKgUCZRqJ5AkQLyXA
+ivFIz7kWIQQZHazkGPlZUM3Q/HovJcCK8UjPuQIbDAAAZka10c8KlmwftJuboIV5
+DalGWrZhbywJpEZRfoikcebSYi5++w1SbpXZGu27sl+BznGyyyqAfxyJjoCZaqCs
+ewbKh04DNAg4v4v0W0a8UvD3j/CuciEMXjK9nUErt91zEwxNZy43yrQY2aAayDs8
+94FqMAA=
+=GBh1
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const plaintext = 'plaintext';
+
+ const signed = await openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKey
+ });
+
+ const { data } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage: signed }),
+ decryptionKeys: privateKey
+ });
+ expect(data).to.equal(plaintext);
+ });
+
it('should support encrypting with encrypted key with unknown s2k (unparseableKeyMaterial)', async function() {
const originalDecryptedKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
@@ -4370,7 +4404,7 @@ kl0L
message: await openpgp.createMessage({ text: plaintext }),
encryptionKeys: privateKeyCast5,
sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
- })).to.be.rejectedWith(/X25519 keys can only encrypt AES session keys/);
+ })).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
await expect(openpgp.decryptSessionKeys({
message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
@@ -4383,6 +4417,48 @@ A7sB7uYCTVCLIMfPFwVZH+c29gpCzPxSXQ==
})).to.be.rejectedWith(/AES session key expected/);
});
+ it('should enforce using AES session keys with x448 keys', async function () {
+ // X448 key (v4) with cast5 as preferred cipher
+ const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZRrtaRyScvyNjK0o5ccICztnWhA1MSij7WdzPfuNy7ryUzB+kqzpziBR
+IIKp5PN0NW3mOYRDnUyo7QHBl4AA30tR5ED8u5v/rNIzKz/mKsD6XeYy+d0Q
+5utwuR8BUxx9mcIUGdS65z9H6PUMGnfCwqAGVCTzBrSCHgTNAMK3BBAcCgA7
+BYJlGu1pAwsDBwmQkFi4G9HqQDwDFQgKAhYAAhkBApsDAh4BFiEE7kZAI1Dd
+SVlLtf4QkFi4G9HqQDwAAPA7E+p0vwVLtUCfT0aBFzapFn8xjoow6jrUNTo3
+8EtaN0fqP2vaeQwW/vv26wobD+hbL2RwyFtAEV6AeeDsPVhbx7WA7yKHPzvl
+GOYEGw0h57DuhvSxGciuyt0Y5PR2Vrz/2/wHGcEHzsrhTNysUetluxEAx3kE
+ZRrtaRrySCLAqKQSATJOXdoRoNKVasJHlKrG3qgMbt1U6uSdctHBitTiHHTf
+GU/Jg0ADA3Eg0bCyDupWNACmHJGu7q0o7O7BTAm0AsMbHxoIkNN9JsijwAp5
+FLtdXK9cAOkNaXPMkEGQkt1hmoW50lUq0iWcGBpzwqYEGBwKACoFgmUa7WkJ
+kJBYuBvR6kA8ApsMFiEE7kZAI1DdSVlLtf4QkFi4G9HqQDwAAD3uf3qdwHY8
+65W22GR17PbqF+9uvkPpXLBi32FVPFkxJqYvIN5/LAQ33xdEE0mzO4As4+Oi
+x8fsFb2AEXLEwlSnL+Eo0O+iUQd3/94yMbMFRlNxrdaqZ3+7CehbnieI/vby
+LIEnN38XBi0HE70uoU5prxUA
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ await expect(openpgp.generateSessionKey({
+ encryptionKeys: privateKeyCast5,
+ config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
+ })).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
+
+ await expect(openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKeyCast5,
+ sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
+ })).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
+
+ await expect(openpgp.decryptSessionKeys({
+ message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+
+wVwD2k7TUuqJwZkaXvEGk7B3pklJ5uRcRdKwwDJ40yKT0m5ic1e/2F+Se3xQ
+zDE+N2DZ0B37pu4NUzTGBRo0oLD9EwwZA9+oJpBBOOry3cGmBYWvQHbvBpNE
+5X5l8A==
+-----END PGP MESSAGE-----` }),
+ decryptionKeys: privateKeyCast5
+ })).to.be.rejectedWith(/AES session key expected/);
+ });
+
describe('Sign and verify with each curve', function() {
const curves = ['secp256k1' , 'p256', 'p384', 'p521', 'curve25519', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
curves.forEach(curve => {
From 089a14f9e0e9451e2cde6103efa4d1eac4282b88 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 30 Mar 2023 13:27:16 +0200
Subject: [PATCH 062/224] Internal: refactor `uint8ArrayToHex` for performance
and to avoid branching
---
src/util.js | 16 ++++------------
test/crypto/cipher/des.js | 2 +-
2 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/src/util.js b/src/util.js
index 25ba5cd0d..a1d5c3d2b 100644
--- a/src/util.js
+++ b/src/util.js
@@ -154,18 +154,10 @@ const util = {
* @returns {String} Hexadecimal representation of the array.
*/
uint8ArrayToHex: function (bytes) {
- const r = [];
- const e = bytes.length;
- let c = 0;
- let h;
- while (c < e) {
- h = bytes[c++].toString(16);
- while (h.length < 2) {
- h = '0' + h;
- }
- r.push('' + h);
- }
- return r.join('');
+ const hexAlphabet = '0123456789abcdef';
+ let s = '';
+ bytes.forEach(v => { s += hexAlphabet[v >> 4] + hexAlphabet[v & 15]; });
+ return s;
},
/**
diff --git a/test/crypto/cipher/des.js b/test/crypto/cipher/des.js
index e3a002858..8cfc03b58 100644
--- a/test/crypto/cipher/des.js
+++ b/test/crypto/cipher/des.js
@@ -80,7 +80,7 @@ export default () => describe('TripleDES (EDE) cipher test with test vectors fro
expect(encr, 'vector with block ' + util.uint8ArrayToHex(testvectors[i][0]) +
' and key ' + util.uint8ArrayToHex(key) +
' should be ' + util.uint8ArrayToHex(testvectors[i][1]) +
- ' != ' + util.uint8ArrayToHex(encr)).to.be.equal(util.uint8ArrayToString(testvectors[i][1]));
+ ' != ' + encr).to.be.equal(util.uint8ArrayToString(testvectors[i][1]));
}
done();
});
From d291ce6d0f8813542781643c28bfba44bf0a46ec Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:22:47 +0200
Subject: [PATCH 063/224] Update Curve448 tests using inputs from gopenpgp
---
test/general/openpgp.js | 630 ++++++++++++++++++++++++++++------------
1 file changed, 446 insertions(+), 184 deletions(-)
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index c84ccd54c..e2ff31289 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1329,40 +1329,6 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
await expect(openpgp.decrypt(decOpt)).to.be.rejectedWith('Error decrypting message: Decryption key is not decrypted.');
});
- it('should decrypt test vector X25519-AEAD-OCB (PKESK v6, SEIPDv2)', async function() {
- // test vector https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.8
- const armoredMessage = `-----BEGIN PGP MESSAGE-----
-
-wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
-WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
-aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
-yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
-bhF30A+IitsxxA==
------END PGP MESSAGE-----`;
-
- const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
-exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
-BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
-2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
-RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
-7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
-LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
-GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
-2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
-M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
-k0mXubZvyl4GBg==
------END PGP PRIVATE KEY BLOCK-----` });
-
- const { data: decryptedData } = await openpgp.decrypt({
- message: await openpgp.readMessage({ armoredMessage }),
- decryptionKeys: privateKey
- });
-
- expect(decryptedData).to.equal('Hello, world!');
- });
-
it('decrypt/verify should succeed with valid signature (expectSigned=true)', async function () {
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
const privateKey = await openpgp.decryptKey({
@@ -2101,99 +2067,6 @@ aOU=
expect(await stream.readToEnd(streamedData)).to.equal(text);
});
- it('supports decrypting new x25519 format', async function () {
- // v4 key
- const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2
-GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz
-dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0
-iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo
-BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG
-0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT
-nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh
-BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH
-yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
-=bJqd
------END PGP PRIVATE KEY BLOCK-----` });
-
- const messageToDecrypt = `-----BEGIN PGP MESSAGE-----
-
-wUQDYc6clYlCdtoZ3rAsvBDIwvoLmvM0zwViG8Ec0PgFfN5R6C4BqEZD53UZB1WM
-J68hXSj1Sa235XAUYE1pZerTKhglvdI9Aeve8+L0w5RDMjmBBA50Yv/YT8liqhNi
-mNwbfFbSNhZYWjFada77EKBn60j8QT/xCQzLR1clci7ieW2knw==
-=NKye
------END PGP MESSAGE-----`;
- const { data } = await openpgp.decrypt({
- message: await openpgp.readMessage({ armoredMessage: messageToDecrypt }),
- decryptionKeys: privateKey
- });
- expect(data).to.equal('Hello World!');
- });
-
- it('supports encrypting/decrypting new x25519 format', async function () {
- // v4 key
- const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2
-GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz
-dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0
-iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo
-BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG
-0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT
-nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh
-BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH
-yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
-=bJqd
------END PGP PRIVATE KEY BLOCK-----` });
- const plaintext = 'plaintext';
-
- const signed = await openpgp.encrypt({
- message: await openpgp.createMessage({ text: plaintext }),
- encryptionKeys: privateKey
- });
-
- const { data } = await openpgp.decrypt({
- message: await openpgp.readMessage({ armoredMessage: signed }),
- decryptionKeys: privateKey
- });
- expect(data).to.equal(plaintext);
- });
-
- it('supports encrypting/decrypting with x448', async function () {
- // v4 key
- const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xXsEZRqJ5BwHESfKnw5YJly5WobjigVm0kKY84NxrP6JKeIvIWiFqqSlozGpKZyR
-50YbVTHmxpUCuJ7YNwX0UoAAoSO8IXmMM/XMd4ph00ju+fbSHdtQfyNhfFTi3UoM
-V5DiFT+uOYDP+zwAwLWCR86csxmCWn6O10DNHcDNF1VzZXJBIDxVc2VyQUB0ZXN0
-LnRlc3Q+wroEExwKAD4FAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXA
-ivFIz7kCGwMCHgkCGQECCwcDFQoIAhYAAycHAgAA21/PqAuGDL5+3qrf3YoVOP+5
-0BoJ+ZMhzcgax+cQTyndmOZYBfOqV/SJ8mf6CRhbB76JhGIvmRMtyYDQgDMVvcoA
-yojVNs6e/Jco16bVJxM85wKDXJuq6AhtPQ8w/0WaCJtEf1uxqeQPEbOM+KtT/xY2
-KgDHeQRlGonkGuOtAhogSIU3z/+gFzF8U7JQe7QDRYr9VWfi2WXFFarzg/3DMRur
-oIB7mqkaaSatrvVuud1ZmRCWAMM4f57dvSdCKsVqSe+tlS225OmdWmnGLqyErBb6
-44E2oENhDUom9OUGUPm8dXUjQbrmw6ec9hNLHWXCpgQYHAoAKgUCZRqJ5AkQLyXA
-ivFIz7kWIQQZHazkGPlZUM3Q/HovJcCK8UjPuQIbDAAAZka10c8KlmwftJuboIV5
-DalGWrZhbywJpEZRfoikcebSYi5++w1SbpXZGu27sl+BznGyyyqAfxyJjoCZaqCs
-ewbKh04DNAg4v4v0W0a8UvD3j/CuciEMXjK9nUErt91zEwxNZy43yrQY2aAayDs8
-94FqMAA=
-=GBh1
------END PGP PRIVATE KEY BLOCK-----` });
- const plaintext = 'plaintext';
-
- const signed = await openpgp.encrypt({
- message: await openpgp.createMessage({ text: plaintext }),
- encryptionKeys: privateKey
- });
-
- const { data } = await openpgp.decrypt({
- message: await openpgp.readMessage({ armoredMessage: signed }),
- decryptionKeys: privateKey
- });
- expect(data).to.equal(plaintext);
- });
-
it('should support encrypting with encrypted key with unknown s2k (unparseableKeyMaterial)', async function() {
const originalDecryptedKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
@@ -4378,9 +4251,10 @@ bsZgJWVlAa5eil6J9ePX2xbo1vVAkLQdzE9+1jL+l7PRIZuVBQ==
expect(data).to.equal('test');
});
- it('should enforce using AES session keys with x25519 keys (new format)', async function () {
- // x25519 key (v4) with cast5 as preferred cipher
- const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+ describe('X25519/Ed25519 (new format)', async function () {
+ it('should enforce using AES session keys with x25519 keys (v4 key)', async function () {
+ // x25519 key (v4) with cast5 as preferred cipher
+ const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
xUkEZK8BixuMghYwdEgHl+3ASI4VZkn048KG4DVuugT1bMe4QTtFtQCoKBOG
JxrZh8E+7I5nK7McXP2U9gyC0+RFcD46AxSmRA46zQDCiAQQGwgAPgWCZK8B
@@ -4395,31 +4269,126 @@ kl0L
=SYJZ
-----END PGP PRIVATE KEY BLOCK-----` });
- await expect(openpgp.generateSessionKey({
- encryptionKeys: privateKeyCast5,
- config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
- })).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
-
- await expect(openpgp.encrypt({
- message: await openpgp.createMessage({ text: plaintext }),
- encryptionKeys: privateKeyCast5,
- sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
- })).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
+ await expect(openpgp.generateSessionKey({
+ encryptionKeys: privateKeyCast5,
+ config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
+ })).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
- await expect(openpgp.decryptSessionKeys({
- message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+ await expect(openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKeyCast5,
+ sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
+ })).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
+ await expect(openpgp.decryptSessionKeys({
+ message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+
wUQD66NYAXF0vfYZNWpc7s9eihtgj7EhHBeLOq2Ktw79artbhN5JMs+9aCIZ
A7sB7uYCTVCLIMfPFwVZH+c29gpCzPxSXQ==
=Dr02
-----END PGP MESSAGE-----` }),
- decryptionKeys: privateKeyCast5
- })).to.be.rejectedWith(/AES session key expected/);
+ decryptionKeys: privateKeyCast5
+ })).to.be.rejectedWith(/AES session key expected/);
+ });
+
+ it('supports decrypting new x25519 format (v4 key)', async function () {
+ // v4 key
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2
+GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz
+dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0
+iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo
+BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG
+0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT
+nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh
+BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH
+yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
+=bJqd
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const messageToDecrypt = `-----BEGIN PGP MESSAGE-----
+
+wUQDYc6clYlCdtoZ3rAsvBDIwvoLmvM0zwViG8Ec0PgFfN5R6C4BqEZD53UZB1WM
+J68hXSj1Sa235XAUYE1pZerTKhglvdI9Aeve8+L0w5RDMjmBBA50Yv/YT8liqhNi
+mNwbfFbSNhZYWjFada77EKBn60j8QT/xCQzLR1clci7ieW2knw==
+=NKye
+-----END PGP MESSAGE-----`;
+ const { data } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage: messageToDecrypt }),
+ decryptionKeys: privateKey
+ });
+ expect(data).to.equal('Hello World!');
+ });
+
+ it('supports encrypting/decrypting new x25519 format (v4 key)', async function () {
+ // v4 key
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2
+GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz
+dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0
+iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo
+BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG
+0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT
+nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh
+BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH
+yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
+=bJqd
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const plaintext = 'plaintext';
+
+ const signed = await openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKey
+ });
+
+ const { data } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage: signed }),
+ decryptionKeys: privateKey
+ });
+ expect(data).to.equal(plaintext);
+ });
+
+ it('should decrypt test vector X25519-AEAD-OCB (PKESK v6, SEIPD v2)', async function() {
+ // test vector https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.8
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
+WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
+aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
+yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
+bhF30A+IitsxxA==
+-----END PGP MESSAGE-----`;
+
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
+exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
+BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
+RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
+7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
+LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
+GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
+2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
+M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
+k0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const { data: decryptedData } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage }),
+ decryptionKeys: privateKey
+ });
+
+ expect(decryptedData).to.equal('Hello, world!');
+ });
});
- it('should enforce using AES session keys with x448 keys', async function () {
- // X448 key (v4) with cast5 as preferred cipher
- const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+ describe('X448/Ed448', async function () {
+ it('should enforce using AES session keys with x448 keys (v4 key)', async function () {
+ // X448 key (v4) with cast5 as preferred cipher
+ const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
xXsEZRrtaRyScvyNjK0o5ccICztnWhA1MSij7WdzPfuNy7ryUzB+kqzpziBR
IIKp5PN0NW3mOYRDnUyo7QHBl4AA30tR5ED8u5v/rNIzKz/mKsD6XeYy+d0Q
@@ -4437,26 +4406,342 @@ x8fsFb2AEXLEwlSnL+Eo0O+iUQd3/94yMbMFRlNxrdaqZ3+7CehbnieI/vby
LIEnN38XBi0HE70uoU5prxUA
-----END PGP PRIVATE KEY BLOCK-----` });
- await expect(openpgp.generateSessionKey({
- encryptionKeys: privateKeyCast5,
- config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
- })).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
-
- await expect(openpgp.encrypt({
- message: await openpgp.createMessage({ text: plaintext }),
- encryptionKeys: privateKeyCast5,
- sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
- })).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
+ await expect(openpgp.generateSessionKey({
+ encryptionKeys: privateKeyCast5,
+ config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
+ })).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
- await expect(openpgp.decryptSessionKeys({
- message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+ await expect(openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKeyCast5,
+ sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
+ })).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
+ await expect(openpgp.decryptSessionKeys({
+ message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
+
wVwD2k7TUuqJwZkaXvEGk7B3pklJ5uRcRdKwwDJ40yKT0m5ic1e/2F+Se3xQ
zDE+N2DZ0B37pu4NUzTGBRo0oLD9EwwZA9+oJpBBOOry3cGmBYWvQHbvBpNE
5X5l8A==
-----END PGP MESSAGE-----` }),
- decryptionKeys: privateKeyCast5
- })).to.be.rejectedWith(/AES session key expected/);
+ decryptionKeys: privateKeyCast5
+ })).to.be.rejectedWith(/AES session key expected/);
+ });
+
+ it('should enforce using 512-bit signature digest', async function () {
+ // X448 key using sha256 for self signatures
+ const privateKeySHA256 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
+5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
+x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
+HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
+BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
+Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
+8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
+tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
+y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
+ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
+BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
+6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
+JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
+x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ await expect(privateKeySHA256.getSigningKey()).to.be.rejectedWith(/Hash algorithm too weak for EdDSA/);
+ });
+
+ it('supports encrypting/decrypting with x448 (v4 key)', async function () {
+ // v4 key
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZRqJ5BwHESfKnw5YJly5WobjigVm0kKY84NxrP6JKeIvIWiFqqSlozGpKZyR
+50YbVTHmxpUCuJ7YNwX0UoAAoSO8IXmMM/XMd4ph00ju+fbSHdtQfyNhfFTi3UoM
+V5DiFT+uOYDP+zwAwLWCR86csxmCWn6O10DNHcDNF1VzZXJBIDxVc2VyQUB0ZXN0
+LnRlc3Q+wroEExwKAD4FAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXA
+ivFIz7kCGwMCHgkCGQECCwcDFQoIAhYAAycHAgAA21/PqAuGDL5+3qrf3YoVOP+5
+0BoJ+ZMhzcgax+cQTyndmOZYBfOqV/SJ8mf6CRhbB76JhGIvmRMtyYDQgDMVvcoA
+yojVNs6e/Jco16bVJxM85wKDXJuq6AhtPQ8w/0WaCJtEf1uxqeQPEbOM+KtT/xY2
+KgDHeQRlGonkGuOtAhogSIU3z/+gFzF8U7JQe7QDRYr9VWfi2WXFFarzg/3DMRur
+oIB7mqkaaSatrvVuud1ZmRCWAMM4f57dvSdCKsVqSe+tlS225OmdWmnGLqyErBb6
+44E2oENhDUom9OUGUPm8dXUjQbrmw6ec9hNLHWXCpgQYHAoAKgUCZRqJ5AkQLyXA
+ivFIz7kWIQQZHazkGPlZUM3Q/HovJcCK8UjPuQIbDAAAZka10c8KlmwftJuboIV5
+DalGWrZhbywJpEZRfoikcebSYi5++w1SbpXZGu27sl+BznGyyyqAfxyJjoCZaqCs
+ewbKh04DNAg4v4v0W0a8UvD3j/CuciEMXjK9nUErt91zEwxNZy43yrQY2aAayDs8
+94FqMAA=
+=GBh1
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const plaintext = 'plaintext';
+
+ const signed = await openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKey
+ });
+
+ const { data } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage: signed }),
+ decryptionKeys: privateKey
+ });
+ expect(data).to.equal(plaintext);
+ });
+
+ it('supports encrypting/decrypting with x448 (v6 key)', async function () {
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xX0GZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
+Y1E04mBai0pCoDiFVokwsKt3F5sAAC8lDYfVP/p3atbXJDTJB2W9WmZxIS7pUGhS
+bjlWpZB/OVTBsoIfP/2J+Hi4ESwBRfDUDgwK4aJVKsLAIAYfHAoAAAA/BQJlGoti
+IqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwMCHgkCCwcDFQoI
+AhYABScHAwcCAAAAAPiGIG2qmhCULQ/+H4rKV0XEM1x0uVY3l878Pa6ijZLouZU/
+VRd5PnbGyLPL++q3LDViUUdZ1uusRc01f677Q6wpUU90k8MH/oULwI0+KPtqe1N4
+6nr1NTERsAmAaPjUdf4ZUXX/GWiTd/AlsS5JqGnAQxKRJkzCJacOTOElRMjzGUX7
+CGaAnhSC86YRZ68ocTPfZysAzRdVc2VyQiA8VXNlckJAdGVzdC50ZXN0PsLADQYT
+HAoAAAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUC
+GQEAAAAASKwgVzMoPb2Hbr3lbNI1CRWECokYLokL7F8MbYiMnlg+v6QXLdStvT13
+ZjxdrWQAx3MbihSOUSXbdAys90yMOAdtognj+x418J/TaYFMtIGBHwoHv8gQVnx9
+9ICv8ezx1T5VvGBYNuKZ5Ww0WPEpYMf1VA+Y9JxpohdcRenNBdSug4tLWla2y8NH
+aO28Fltpb4AuGQDHewZlGotiGgAAADjdabr1ohAOnbSUUkVhtUM/LVdnYgDLhmaj
+YZ1N7TWY0fqEpMk2LLo2165HOmhddRPeTB1TWbuwBwB8lKc3czFUzYcAgvZ08T5S
+UUHjfIhjeJeY4yd0OZDfzPw1vbegCc7t94bT+XGoIQbC/Bl7HCyAiMLADQYYHAoA
+AAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwwA
+AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
+6UCpJYYk3o3hYUYzIHmCIZGVYe1pxRgIUNqxydXEfzylJmN5NbiJNkjJizrI7oAR
+1mIcEEb/hmRMOUs1V2mcGuoeALBI/r/SyqDE2GRjH6d6g1RS7ZARPPHlZlY4CTqC
+4a7L+8odDwA=
+=chx0
+-----END PGP PRIVATE KEY BLOCK-----` });
+ const plaintext = 'plaintext';
+
+ const signed = await openpgp.encrypt({
+ message: await openpgp.createMessage({ text: plaintext }),
+ encryptionKeys: privateKey
+ });
+
+ const { data } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage: signed }),
+ decryptionKeys: privateKey
+ });
+ expect(data).to.equal(plaintext);
+ });
+
+ it('decrypt/verify should succeed using X448/Ed448 (PKESK v4, SEIPD v2, GCM)', async function() {
+ // data generated by gopenpgp
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+wWkGFQQ70agVm6o5r3tEzY5mrYaOV8yHChpUetZ33zrKGtw1F4PeFrE4bYkcTMQM
+IcGoXcZj/0GJDCkOLLleSwrvuAuUwZV11bHBZ6eNTyj+XxhLdVflV/zqPmBhTHY9
+SMn0YYHwgiQFk6PSwGICBwMMRYkTpsy0dE4YKasf6b4Oh9cn6HYY5rjnrtvrwD+F
+LrsELfudYwpwHBA5jnO11Hl5mUyXhhWSdPoLGdeiYP5R/vZjqoZr3P6FL4dCdVni
+fGChUUSYmpO4HIFrRBt2gAxl+f0Q8GCOG8c7EQ7c5600kJOlHM7SuoLqsxd482V1
+H/1Rxd3cPwTDfOjH26KuDv60p0XjdCGyQXcDQMCPV+ZTs0TQl4wTFogZGaRMd9GC
+5D5t/guKzR+H1ipXSFjFdWWTEehx8m0RKKKT3Bl81awKZb8ulR6YKI5x39nwOySN
+azDRR3gn9xlKjcpa83k5sSZbUTxC8lzTeuMP0PkDrU2IpZUZOlzOhGYOGrtTFATK
+PSoZU33h2h3hJqiX9aKrnw==
+=Is5l
+-----END PGP MESSAGE-----`;
+
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZRqJ5BxV/xdxR4KvPofk3EzKaIZqM0Wlw904q+2S6Z84OmXN6Q1xCYurcwN1
+wLOlGJ/CO2QhByEdGlUldwAAIQSMnMITcmXQU3EWK5S81FS+u1IZFP55j51bA5mS
+HZ/A7MOpyN40ybW8mhMIXXUYB7kC/bOTmwVHGt3NF1VzZXJCIDxVc2VyQkB0ZXN0
+LnRlc3Q+wrwEExwKAEAFAmUaieQJEP3WralmOT0PFiEEq4zuQzIBSh+Nk6G9/dat
+qWY5PQ8CGwMCHgkCGQECCwcDFQoIAhYABScHAwcCAADAvnnhLp0DJYk7E0GfksCg
+pUnnCjEePMVvRPVY3dwr9wLpdL/7T70fz541XVE8giYiZD7eiKvfc/nMgOhu1eqK
+uXGUtDGBeabitJcrbquy2Tp/ENuW6rRHP7sAbu0mj6XxYEeCzKjGRT5Iq25AMevm
+yeoIAMd5BGUaieQaqj/dF+uZGt9QLuji2eOlDC0/quq/sAtdJTbI1xj04aF0X7kJ
+lVhEKeWZeAEpD4rVOCsrhMvr21gAu/BaFVKGUOuf0+ZE5jGcFcBvEP7OGyO296ry
+zV7ONWS/FuoZ/NZmgWo9m9ftPtwqKDsgOWxiIj4cesKmBBgcCgAqBQJlGonkCRD9
+1q2pZjk9DxYhBKuM7kMyAUofjZOhvf3WralmOT0PAhsMAADWb+0aY+NblShwsym/
+2geh6XaqQUCJgdRfEl8xYLau/o8QQAzRp0ZBA+KeK3uwhRW3RizuqIw5iribAK3+
+30Si5nvv0TivalPK2C9yAqzh9rkNNUQa9b17IHYs/WwQrvP3F5EZ3V+StqdveAEo
+FecSL/wTAA==
+=FANS
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const senderKey = await openpgp.readKey({
+ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xj8EZRqJ5BwHESfKnw5YJly5WobjigVm0kKY84NxrP6JKeIvIWiFqqSlozGpKZyR
+50YbVTHmxpUCuJ7YNwX0UoDNF1VzZXJBIDxVc2VyQUB0ZXN0LnRlc3Q+wroEExwK
+AD4FAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXAivFIz7kCGwMCHgkC
+GQECCwcDFQoIAhYAAycHAgAA21/PqAuGDL5+3qrf3YoVOP+50BoJ+ZMhzcgax+cQ
+TyndmOZYBfOqV/SJ8mf6CRhbB76JhGIvmRMtyYDQgDMVvcoAyojVNs6e/Jco16bV
+JxM85wKDXJuq6AhtPQ8w/0WaCJtEf1uxqeQPEbOM+KtT/xY2KgDOPgRlGonkGuOt
+AhogSIU3z/+gFzF8U7JQe7QDRYr9VWfi2WXFFarzg/3DMRuroIB7mqkaaSatrvVu
+ud1ZmRCWwqYEGBwKACoFAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXA
+ivFIz7kCGwwAAGZGtdHPCpZsH7Sbm6CFeQ2pRlq2YW8sCaRGUX6IpHHm0mIufvsN
+Um6V2Rrtu7Jfgc5xsssqgH8ciY6AmWqgrHsGyodOAzQIOL+L9FtGvFLw94/wrnIh
+DF4yvZ1BK7fdcxMMTWcuN8q0GNmgGsg7PPeBajAA
+=VA/P
+-----END PGP PUBLIC KEY BLOCK-----` });
+
+ const { data: decryptedData, signatures } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage }),
+ decryptionKeys: privateKey,
+ verificationKeys: senderKey
+ });
+
+ expect(decryptedData).to.equal('Hello there');
+ expect(signatures).to.have.length(1);
+ expect(await signatures[0].verified).to.be.true;
+ });
+
+
+ it('decrypt/verify should succeed using X448/Ed448 (PKESK v6, SEIPD v2, GCM)', async function() {
+ // data generated by gopenpgp
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+wXUGIQZh4qTsn8glFgGNbIdCTl8gH2OtkI/PAGCQ0gi9s9k/rhrDhXo7kUKDJ39F
+fNp3kmAaM24Ce3bcYXwLy0gF2i6rxfL20D+g3cxv0i3CuXQCgcbojTN/8KY8ExiV
+Xdfo+OWIZ5XndtyMpJW28BiLHru+n9bSwM8CBwMMENh7cT8lILXteh885FrUUD1Q
+JMtD7xJUn2y78cVGgFSIkLbvFPDerB37xuhtMRkykuWgbUoJH/kcgBPdeCoYzJmf
+LV9FyATv0/AYq0yWpQ0VUfNLTFyeHIGxz7NHvrzJSrOy1Gm31PXqWvb4sBROjnOX
+oAk12JdPudz3l1QZT/DX947f4h6hwkVv7RRT0oOS2pMaz/mekRuD6utUcpsjFQ/M
+EDphnhOsB4RH0il8YPVc9DCnf3GhSs66h+Z699MXHBaUmdtiN1IgoEgLfb/900U2
+TfI6dvrvC56WIMA8EA1COvLGc9Ge4owW0UE8jIuqWLzA2nVg5belbzhNnOEh9b1c
+OcDUh8CfBuXqHEi/ANMUOMmaIGfcHfQFVu5v/UMcLxcH/fSVF6DvtOxEoUxASWBS
+mp6yC4A778BFuDFXb+/T8FjuJBaUj9rCSkYqt1TYVKG1XZPI4OdIvGtneo+vH/Cq
+F6bxlLWU6oskZ5SE+xJblmmO01ObM9JRi9D8jZnXedTHExAnXHXIb8I=
+=5RQw
+-----END PGP MESSAGE-----`;
+
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xX0GZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
+Y1E04mBai0pCoDiFVokwsKt3F5sAAC8lDYfVP/p3atbXJDTJB2W9WmZxIS7pUGhS
+bjlWpZB/OVTBsoIfP/2J+Hi4ESwBRfDUDgwK4aJVKsLAIAYfHAoAAAA/BQJlGoti
+IqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwMCHgkCCwcDFQoI
+AhYABScHAwcCAAAAAPiGIG2qmhCULQ/+H4rKV0XEM1x0uVY3l878Pa6ijZLouZU/
+VRd5PnbGyLPL++q3LDViUUdZ1uusRc01f677Q6wpUU90k8MH/oULwI0+KPtqe1N4
+6nr1NTERsAmAaPjUdf4ZUXX/GWiTd/AlsS5JqGnAQxKRJkzCJacOTOElRMjzGUX7
+CGaAnhSC86YRZ68ocTPfZysAzRdVc2VyQiA8VXNlckJAdGVzdC50ZXN0PsLADQYT
+HAoAAAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUC
+GQEAAAAASKwgVzMoPb2Hbr3lbNI1CRWECokYLokL7F8MbYiMnlg+v6QXLdStvT13
+ZjxdrWQAx3MbihSOUSXbdAys90yMOAdtognj+x418J/TaYFMtIGBHwoHv8gQVnx9
+9ICv8ezx1T5VvGBYNuKZ5Ww0WPEpYMf1VA+Y9JxpohdcRenNBdSug4tLWla2y8NH
+aO28Fltpb4AuGQDHewZlGotiGgAAADjdabr1ohAOnbSUUkVhtUM/LVdnYgDLhmaj
+YZ1N7TWY0fqEpMk2LLo2165HOmhddRPeTB1TWbuwBwB8lKc3czFUzYcAgvZ08T5S
+UUHjfIhjeJeY4yd0OZDfzPw1vbegCc7t94bT+XGoIQbC/Bl7HCyAiMLADQYYHAoA
+AAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwwA
+AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
+6UCpJYYk3o3hYUYzIHmCIZGVYe1pxRgIUNqxydXEfzylJmN5NbiJNkjJizrI7oAR
+1mIcEEb/hmRMOUs1V2mcGuoeALBI/r/SyqDE2GRjH6d6g1RS7ZARPPHlZlY4CTqC
+4a7L+8odDwA=
+=chx0
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const senderKey = await openpgp.readKey({
+ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xkMGZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT+hLe
+V6puyC/PeSEfaanqTuo31vvsti2AwsAeBh8cCgAAAD0FAmUai2IioQYDGJ2wdEcO
+zIVPDVDs6gYQASdGfG2EozBUGqEgvaj4dQIbAwIeCQILBwMVCggCFgADJwcCAAAA
+ADYqIL5j5+FD/jwKRP1atdNf1IKfe8fPjdZv74CSalYvUdCaskTdLiAaW17NkrYT
+2i9qDPErFWsvXi4LqGzqQnQkiJZBJ4x57EJPL4Z2vqPTBvgWEU2egi7fK7YAGZmk
+Vf/n/X3Vh5ZSvIoUMChRmYqBBNI7MkS/I7QAJHkvi9XcANx44B0bz+yqETz2tNJ6
+8VeeDgkAzRdVc2VyQSA8VXNlckFAdGVzdC50ZXN0PsLADQYTHAoAAAAsBQJlGoti
+IqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUCGQEAAAAAXD8gfvYz
+WLLMxaFuC3C/RJH9fG84hb9mtPgjH3bfqW+g4Ti1ov8PjoJtk6ObtUB45J9J3G3X
+FIqegAtGwI1Dy1U+M9dyXOqvpHwxs8iAFbEpwxLZ5K1ikFsbmoCZz4rmN0DbFyX2
+JbltaV5nUtNqHiUXqoKIPvch98ANe3PDyIAxNf7TAzk3W0lQQa+Cp7TSiFEqJADO
+QgZlGotiGgAAADjKb5lwMEt0ubSvwydaAF89wsn6H8NJO7kox5ioWW2Grn88CUZD
+YaRBZj3ZH8HMdaih5kN4hJAeCMLADQYYHAoAAAAsBQJlGotiIqEGAxidsHRHDsyF
+Tw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUCGwwAAAAAFIQgGYYweuBej4XHAgZrcez8
+8VoTbIZDjMv6Qbj9g6jjW16Fyp10DKda10FFmbY+YjbNvQNYksF9bN/KFSS/PTYt
+AVaOZDfW4fiN5s1QaYmA/xCT/zLHEYGryYCJLoLd7KLw28LS1KAWrC9h5cY6+fZE
+05cavO/D/WqBLVPuA+5bftXnDvGcVS1p7buaMtQjKz4hAwA=
+=GUIG
+-----END PGP PUBLIC KEY BLOCK-----` });
+
+ const { data: decryptedData, signatures } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage }),
+ decryptionKeys: privateKey,
+ verificationKeys: senderKey
+ });
+
+ expect(decryptedData).to.equal('Hello there');
+ expect(signatures).to.have.length(1);
+ expect(await signatures[0].verified).to.be.true;
+ });
+
+ it('decrypt/verify should succeed using X448/Ed448 (PKESK v6, SEIPD v2, OCB)', async function() {
+ // data generated by gopenpgp
+ const armoredMessage = `-----BEGIN PGP MESSAGE-----
+
+wXUGIQaYemlYu2ObOZ2IjFbL77NygqexwaCgtb0COZ0EnXfXlBri0wADNxbvwCnJ
+GDlRX9VhIy46oPAvVJjm2d7ZC6wqxNfFuzQEB8KzwYBkExmZuAfO5KJ8la6+DRhc
+OUH3A9cBGzq0eiKaKRqjHkiLHY5pFNPSwNoCBwIM98RL63I8iMyxcXpXQlBrYlBx
+5uegrENlleNg6UJFr7rBT4eJH+Qeksb//V87eZymzqXZBsrTYmUjsFgYd5kL8NlU
+wovy+qQnZmEaUKieDx3w+orR8b32ub5CNjHJa5lCdNWsIK825S5JUifZDd3hR6lC
+EgtZRwxY/1CyQU94LR9j6w/YVF0W31+LxGGkL+uJEx0khJUzpxUM9QSEREOY7Frs
+EegHNwDvxvxEwWpfkJOPIDME6Y7UcpsNp6xgiZ/XF06IRsliCRbeYaH1IWW+y0OS
+CmPvvTFUzjwTxWogDccHz8YLHU0y6TKxf14YMvVLg2tf2P/BVVZSg0ejz6pfDKA5
+AP+Q/eXBAH272SpBjKo7YcVpTsz0KpWyhB6Jra4xaUFkt6pg39ydR3RJMvxbQVlR
+aZqV/+1rwIiIauyHKiJFdCiXYPDU3xibVkFIFhuk5JwHm29XvOV1r8FFx7d78X5P
+yJnXcXsl+GxwOojcLXSL0CEIU/iRqyAIyyhvUyyss3glehhgx0fENV2P/Ygi/naN
+nJUJgg==
+=m19C
+-----END PGP MESSAGE-----`;
+
+ const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT+hLe
+V6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVsIU7QqLv1
+hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoAAAA9BQJlGoti
+IqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUCGwMCHgkCCwcDFQoI
+AhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vHz43Wb++AkmpWL1HQmrJE
+3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiWQSeMeexCTy+Gdr6j0wb4FhFN
+noIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmKgQTSOzJEvyO0ACR5L4vV3ADceOAd
+G8/sqhE89rTSevFXng4JAM0XVXNlckEgPFVzZXJBQHRlc3QudGVzdD7CwA0GExwK
+AAAALAUCZRqLYiKhBgMYnbB0Rw7MhU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkB
+AAAAAFw/IH72M1iyzMWhbgtwv0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOj
+m7VAeOSfSdxt1xSKnoALRsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qA
+mc+K5jdA2xcl9iW5bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGv
+gqe00ohRKiQAx3sGZRqLYhoAAAA4ym+ZcDBLdLm0r8MnWgBfPcLJ+h/DSTu5KMeY
+qFlthq5/PAlGQ2GkQWY92R/BzHWooeZDeISQHggAuraV/u+CE642fcbcq90OY+qg
+n739wkHcBps/s/MgMI+Q2H13vEsFpYZ/kuBIIYP39xkdU48/1GbCwA0GGBwKAAAA
+LAUCZRqLYiKhBgMYnbB0Rw7MhU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhsMAAAA
+ABSEIBmGMHrgXo+FxwIGa3Hs/PFaE2yGQ4zL+kG4/YOo41tehcqddAynWtdBRZm2
+PmI2zb0DWJLBfWzfyhUkvz02LQFWjmQ31uH4jebNUGmJgP8Qk/8yxxGBq8mAiS6C
+3eyi8NvC0tSgFqwvYeXGOvn2RNOXGrzvw/1qgS1T7gPuW37V5w7xnFUtae27mjLU
+Iys+IQMA
+=iwhO
+-----END PGP PRIVATE KEY BLOCK-----` });
+
+ const senderKey = await openpgp.readKey({
+ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xkMGZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
+Y1E04mBai0pCoDiFVokwsKt3F5sAwsAgBh8cCgAAAD8FAmUai2IioQahuzG3xYqw
+y4lYA3JNelYx0LVA3/sTIkKV9yz6cGCp1QIbAwIeCQILBwMVCggCFgAFJwcDBwIA
+AAAA+IYgbaqaEJQtD/4fispXRcQzXHS5VjeXzvw9rqKNkui5lT9VF3k+dsbIs8v7
+6rcsNWJRR1nW66xFzTV/rvtDrClRT3STwwf+hQvAjT4o+2p7U3jqevU1MRGwCYBo
++NR1/hlRdf8ZaJN38CWxLkmoacBDEpEmTMIlpw5M4SVEyPMZRfsIZoCeFILzphFn
+ryhxM99nKwDNF1VzZXJCIDxVc2VyQkB0ZXN0LnRlc3Q+wsANBhMcCgAAACwFAmUa
+i2IioQahuzG3xYqwy4lYA3JNelYx0LVA3/sTIkKV9yz6cGCp1QIZAQAAAABIrCBX
+Myg9vYduveVs0jUJFYQKiRguiQvsXwxtiIyeWD6/pBct1K29PXdmPF2tZADHcxuK
+FI5RJdt0DKz3TIw4B22iCeP7HjXwn9NpgUy0gYEfCge/yBBWfH30gK/x7PHVPlW8
+YFg24pnlbDRY8Slgx/VUD5j0nGmiF1xF6c0F1K6Di0taVrbLw0do7bwWW2lvgC4Z
+AM5CBmUai2IaAAAAON1puvWiEA6dtJRSRWG1Qz8tV2diAMuGZqNhnU3tNZjR+oSk
+yTYsujbXrkc6aF11E95MHVNZu7AHwsANBhgcCgAAACwFAmUai2IioQahuzG3xYqw
+y4lYA3JNelYx0LVA3/sTIkKV9yz6cGCp1QIbDAAAAAAeHSB/aR2ouhd0Vf5o1U5G
+vlUJWBybaAHDyXryUMnV+0DvVsyWUWLpDmws9SvpQKklhiTejeFhRjMgeYIhkZVh
+7WnFGAhQ2rHJ1cR/PKUmY3k1uIk2SMmLOsjugBHWYhwQRv+GZEw5SzVXaZwa6h4A
+sEj+v9LKoMTYZGMfp3qDVFLtkBE88eVmVjgJOoLhrsv7yh0PAA==
+=2Usy
+-----END PGP PUBLIC KEY BLOCK-----` });
+
+ const { data: decryptedData, signatures } = await openpgp.decrypt({
+ message: await openpgp.readMessage({ armoredMessage }),
+ decryptionKeys: privateKey,
+ verificationKeys: senderKey
+ });
+
+ expect(decryptedData).to.equal('Hello nice to meet you');
+ expect(signatures).to.have.length(1);
+ expect(await signatures[0].verified).to.be.true;
+ });
});
describe('Sign and verify with each curve', function() {
@@ -4532,29 +4817,6 @@ bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGvgqe00ohRKiQA
expect(signatures).to.have.length(1);
expect(await signatures[0].verified).to.be.true;
});
-
- it('should enforce using 512-bit signature digest', async function () {
- // X448 key using sha256 for self signatures
- const privateKeySHA256 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
-5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
-x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
-HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
-BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
-Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
-8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
-tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
-y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
-ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
-BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
-6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
-JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
-x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
------END PGP PRIVATE KEY BLOCK-----` });
-
- await expect(privateKeySHA256.getSigningKey()).to.be.rejectedWith(/Hash algorithm too weak for EdDSA/);
- });
});
describe('Errors', function() {
From 2afa19db01c2ca4b2cf75e60be1324a39cc52412 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Fri, 29 Sep 2023 22:21:43 +0200
Subject: [PATCH 064/224] Run npm audit
---
package-lock.json | 300 ++++++++++------------------------------------
1 file changed, 66 insertions(+), 234 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index feafc4e0c..a12641177 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -411,18 +411,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/@eslint/eslintrc/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/@eslint/eslintrc/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -460,18 +448,6 @@
}
}
},
- "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/@humanwhocodes/config-array/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2171,9 +2147,9 @@
}
},
"node_modules/engine.io": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz",
- "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==",
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz",
+ "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==",
"dev": true,
"dependencies": {
"@types/cookie": "^0.4.1",
@@ -2453,9 +2429,9 @@
}
},
"node_modules/eslint-config-airbnb-base/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -2569,18 +2545,6 @@
"ms": "^2.1.1"
}
},
- "node_modules/eslint-plugin-import/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/eslint-plugin-import/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -2588,9 +2552,9 @@
"dev": true
},
"node_modules/eslint-plugin-import/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -2631,23 +2595,10 @@
"dev": true,
"peer": true
},
- "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true,
"bin": {
@@ -2696,19 +2647,6 @@
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
}
},
- "node_modules/eslint-plugin-react/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/eslint-plugin-react/node_modules/resolve": {
"version": "2.0.0-next.4",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
@@ -2728,9 +2666,9 @@
}
},
"node_modules/eslint-plugin-react/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true,
"bin": {
@@ -2872,18 +2810,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/eslint/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/eslint/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -3370,9 +3296,9 @@
}
},
"node_modules/get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true,
"engines": {
"node": "*"
@@ -3440,18 +3366,6 @@
"node": ">= 6"
}
},
- "node_modules/glob/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -4179,9 +4093,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -4934,15 +4848,6 @@
"node": ">=6"
}
},
- "node_modules/make-dir/node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -5077,9 +4982,9 @@
"dev": true
},
"node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -6361,9 +6266,9 @@
"dev": true
},
"node_modules/semver": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
- "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@@ -6485,9 +6390,9 @@
}
},
"node_modules/socket.io-parser": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
- "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
@@ -7423,9 +7328,9 @@
"dev": true
},
"node_modules/word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -7959,15 +7864,6 @@
"argparse": "^2.0.1"
}
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -7996,15 +7892,6 @@
"ms": "2.1.2"
}
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -9333,9 +9220,9 @@
"dev": true
},
"engine.io": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz",
- "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==",
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz",
+ "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==",
"dev": true,
"requires": {
"@types/cookie": "^0.4.1",
@@ -9595,15 +9482,6 @@
"argparse": "^2.0.1"
}
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -9636,9 +9514,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -9736,15 +9614,6 @@
"ms": "^2.1.1"
}
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -9752,9 +9621,9 @@
"dev": true
},
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -9788,20 +9657,10 @@
"dev": true,
"peer": true
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "peer": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true
}
@@ -9830,16 +9689,6 @@
"string.prototype.matchall": "^4.0.7"
},
"dependencies": {
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "peer": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
"resolve": {
"version": "2.0.0-next.4",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
@@ -9853,9 +9702,9 @@
}
},
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true
}
@@ -10271,9 +10120,9 @@
"dev": true
},
"get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true
},
"get-intrinsic": {
@@ -10309,17 +10158,6 @@
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
- },
- "dependencies": {
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- }
}
},
"glob-parent": {
@@ -10866,9 +10704,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -11483,12 +11321,6 @@
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
}
}
},
@@ -11600,9 +11432,9 @@
"dev": true
},
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
@@ -12561,9 +12393,9 @@
"dev": true
},
"semver": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
- "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"set-blocking": {
@@ -12677,9 +12509,9 @@
}
},
"socket.io-parser": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
- "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dev": true,
"requires": {
"@socket.io/component-emitter": "~3.1.0",
@@ -13375,9 +13207,9 @@
"dev": true
},
"word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true
},
"workerpool": {
From 1509364a4987353b6c071fb11aecc4963d83e90f Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 3 Oct 2023 13:36:05 +0200
Subject: [PATCH 065/224] Throw on unexpected param sizes in secret keys,
session keys and signatures
Detect extra bytes in secret key material, as well as missing bytes in other parameters.
---
src/config/config.js | 7 ++++++-
src/crypto/crypto.js | 8 ++++----
src/crypto/signature.js | 16 ++++++++--------
src/packet/secret_key.js | 5 ++++-
src/packet/signature.js | 7 ++++++-
src/type/ecdh_x_symkey.js | 2 +-
src/util.js | 21 ++++++++++++++++++++-
test/general/key.js | 23 +++++++++++++++++++++++
8 files changed, 72 insertions(+), 17 deletions(-)
diff --git a/src/config/config.js b/src/config/config.js
index 3f93e7200..e448cbda6 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -128,7 +128,12 @@ export default {
* process large streams while limiting memory usage by releasing the decrypted chunks as soon as possible
* and deferring checking their integrity until the decrypted stream has been read in full.
*
- * This setting is **insecure** if the partially decrypted message is processed further or displayed to the user.
+ * This setting is **insecure** if the encrypted data has been corrupted by a malicious entity:
+ * - if the partially decrypted message is processed further or displayed to the user, it opens up the possibility of attacks such as EFAIL
+ * (see https://efail.de/).
+ * - an attacker with access to traces or timing info of internal processing errors could learn some info about the data.
+ *
+ * NB: this setting does not apply to AEAD-encrypted data, where the AEAD data chunk is never released until integrity is confirmed.
* @memberof module:config
* @property {Boolean} allowUnauthenticatedStream
*/
diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js
index a9293e758..2576bd882 100644
--- a/src/crypto/crypto.js
+++ b/src/crypto/crypto.js
@@ -186,7 +186,7 @@ export function parsePublicKeyParams(algo, bytes) {
case enums.publicKey.ed448:
case enums.publicKey.x25519:
case enums.publicKey.x448: {
- const A = bytes.subarray(read, read + getCurvePayloadSize(algo)); read += A.length;
+ const A = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(algo)); read += A.length;
return { read, publicParams: { A } };
}
default:
@@ -234,13 +234,13 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) {
case enums.publicKey.ed25519:
case enums.publicKey.ed448: {
const payloadSize = getCurvePayloadSize(algo);
- const seed = bytes.subarray(read, read + payloadSize); read += seed.length;
+ const seed = util.readExactSubarray(bytes, read, read + payloadSize); read += seed.length;
return { read, privateParams: { seed } };
}
case enums.publicKey.x25519:
case enums.publicKey.x448: {
const payloadSize = getCurvePayloadSize(algo);
- const k = bytes.subarray(read, read + payloadSize); read += k.length;
+ const k = util.readExactSubarray(bytes, read, read + payloadSize); read += k.length;
return { read, privateParams: { k } };
}
default:
@@ -288,7 +288,7 @@ export function parseEncSessionKeyParams(algo, bytes) {
case enums.publicKey.x25519:
case enums.publicKey.x448: {
const pointSize = getCurvePayloadSize(algo);
- const ephemeralPublicKey = bytes.subarray(read, read + pointSize); read += ephemeralPublicKey.length;
+ const ephemeralPublicKey = util.readExactSubarray(bytes, read, read + pointSize); read += ephemeralPublicKey.length;
const C = new ECDHXSymmetricKey(); C.read(bytes.subarray(read));
return { ephemeralPublicKey, C };
}
diff --git a/src/crypto/signature.js b/src/crypto/signature.js
index 5d3db48de..5f0ceeabe 100644
--- a/src/crypto/signature.js
+++ b/src/crypto/signature.js
@@ -27,10 +27,10 @@ export function parseSignatureParams(algo, signature) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaSign: {
- const s = util.readMPI(signature.subarray(read));
+ const s = util.readMPI(signature.subarray(read)); read += s.length + 2;
// The signature needs to be the same length as the public key modulo n.
// We pad s on signature verification, where we have access to n.
- return { s };
+ return { read, signatureParams: { s } };
}
// Algorithm-Specific Fields for DSA or ECDSA signatures:
// - MPI of DSA or ECDSA value r.
@@ -39,8 +39,8 @@ export function parseSignatureParams(algo, signature) {
case enums.publicKey.ecdsa:
{
const r = util.readMPI(signature.subarray(read)); read += r.length + 2;
- const s = util.readMPI(signature.subarray(read));
- return { r, s };
+ const s = util.readMPI(signature.subarray(read)); read += s.length + 2;
+ return { read, signatureParams: { r, s } };
}
// Algorithm-Specific Fields for legacy EdDSA signatures:
// - MPI of an EC point r.
@@ -50,9 +50,9 @@ export function parseSignatureParams(algo, signature) {
// https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-3.2-9
let r = util.readMPI(signature.subarray(read)); read += r.length + 2;
r = util.leftPad(r, 32);
- let s = util.readMPI(signature.subarray(read));
+ let s = util.readMPI(signature.subarray(read)); read += s.length + 2;
s = util.leftPad(s, 32);
- return { r, s };
+ return { read, signatureParams: { r, s } };
}
// Algorithm-Specific Fields for Ed25519 signatures:
// - 64 octets of the native signature
@@ -61,8 +61,8 @@ export function parseSignatureParams(algo, signature) {
case enums.publicKey.ed25519:
case enums.publicKey.ed448: {
const rsSize = 2 * publicKey.elliptic.eddsa.getPayloadSize(algo);
- const RS = signature.subarray(read, read + rsSize); read += RS.length;
- return { RS };
+ const RS = util.readExactSubarray(signature, read, read + rsSize); read += RS.length;
+ return { read, signatureParams: { RS } };
}
default:
diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js
index dc5b853d2..6dbb3b72a 100644
--- a/src/packet/secret_key.js
+++ b/src/packet/secret_key.js
@@ -195,7 +195,10 @@ class SecretKeyPacket extends PublicKeyPacket {
}
}
try {
- const { privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
+ const { read, privateParams } = crypto.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
+ if (read < cleartext.length) {
+ throw new Error('Error reading MPIs');
+ }
this.privateParams = privateParams;
} catch (err) {
if (err instanceof UnsupportedError) throw err;
diff --git a/src/packet/signature.js b/src/packet/signature.js
index a66fbd493..b650ca99a 100644
--- a/src/packet/signature.js
+++ b/src/packet/signature.js
@@ -153,7 +153,12 @@ class SignaturePacket {
i += saltLength;
}
- this.params = crypto.signature.parseSignatureParams(this.publicKeyAlgorithm, bytes.subarray(i, bytes.length));
+ const signatureMaterial = bytes.subarray(i, bytes.length);
+ const { read, signatureParams } = crypto.signature.parseSignatureParams(this.publicKeyAlgorithm, signatureMaterial);
+ if (read < signatureMaterial.length) {
+ throw new Error('Error reading MPIs');
+ }
+ this.params = signatureParams;
}
/**
diff --git a/src/type/ecdh_x_symkey.js b/src/type/ecdh_x_symkey.js
index ecef5715c..2f3ee8c9e 100644
--- a/src/type/ecdh_x_symkey.js
+++ b/src/type/ecdh_x_symkey.js
@@ -27,7 +27,7 @@ class ECDHXSymmetricKey {
let followLength = bytes[read++];
this.algorithm = followLength % 2 ? bytes[read++] : null; // session key size is always even
followLength -= followLength % 2;
- this.wrappedKey = bytes.subarray(read, read + followLength); read += followLength;
+ this.wrappedKey = util.readExactSubarray(bytes, read, read + followLength); read += followLength;
}
/**
diff --git a/src/util.js b/src/util.js
index a1d5c3d2b..f0ee7f637 100644
--- a/src/util.js
+++ b/src/util.js
@@ -89,7 +89,26 @@ const util = {
readMPI: function (bytes) {
const bits = (bytes[0] << 8) | bytes[1];
const bytelen = (bits + 7) >>> 3;
- return bytes.subarray(2, 2 + bytelen);
+ // There is a decryption oracle risk here by enforcing the MPI length using `readExactSubarray` in the context of SEIPDv1 encrypted signatures,
+ // where unauthenticated streamed decryption is done (via `config.allowUnauthenticatedStream`), since the decrypted signature data being processed
+ // has not been authenticated (yet).
+ // However, such config setting is known to be insecure, and there are other packet parsing errors that can cause similar issues.
+ // Also, AEAD is also not affected.
+ return util.readExactSubarray(bytes, 2, 2 + bytelen);
+ },
+
+ /**
+ * Read exactly `end - start` bytes from input.
+ * This is a stricter version of `.subarray`.
+ * @param {Uint8Array} input - Input data to parse
+ * @returns {Uint8Array} subarray of size always equal to `end - start`
+ * @throws if the input array is too short.
+ */
+ readExactSubarray: function (input, start, end) {
+ if (input.length < (end - start)) {
+ throw new Error('Input array too short');
+ }
+ return input.subarray(start, end);
},
/**
diff --git a/test/general/key.js b/test/general/key.js
index 0e5dc5ae4..adc11528b 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -3257,6 +3257,29 @@ AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x448' });
});
+ it('Throw when parsing x448 key with unexpected secret param size', async function() {
+ // x448 subkey with secret seed of 57 bytes instead of 56
+ const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xXsEZRwKeRx0854v253kTyH54UIFSy3dLbMLTSIGh+UeC6IWXvxt2551rUee
+wn9y5hJbJwm/f2eA3vkOUqhKbAAAy7hGpOu61AMTr6w9G9VLStDR9Int/vgi
+cNSl1LTvF8f5lqBrpMFFPUHwi4igNMqb7I/c7J2Uc+4uInvNAMK3BBAcCgA7
+BYJlHAp5AwsJBwmQ+2DdQup2xx8DFQgKAhYAAhkBApsDAh4BFiEE5NkqBdRy
+GYLB7cPm+2DdQup2xx8AAIuONFkN6wRtRJA9EJvwhj7DkzNRjFNw8OE/ENzj
+3XcN/WtZYCnLZ+ih9HSar9+CZzI+4mHtvOunq7sAjuvPbGndbbdg46DSy0Ac
+wIVxSeIMNpwpktMyUx/ugIZeu7VvcnW4SbQOEB5KPlja/qjapWwg4wIAx3oE
+ZRwKeRogjMz3j2jL4X1Zhk+i/EK09BTU/2zuYuB+Pl9Y+RKDaxuOmZ4zzx+S
+xa/RYWEVKkcIY9pBAxd4RgDZs0rJP9DRIe69vix1Wd/LxuSctG2SMfcjzyAl
+5mmCsb+sgubDduEBotTv3qFnNTYMUUHEFojWC4EfjcKmBBgcCgAqBYJlHAp5
+CZD7YN1C6nbHHwKbDBYhBOTZKgXUchmCwe3D5vtg3ULqdscfAAD/uWh1fZy7
+hMeb7552mWqB0eGXpOJR9K/rLDj8woLkXJMyyhfYU5PTwmRpowsGwbm7TMku
+gXxMryvfgBDKTN8tkgJ4BJUsDDwU7aJE1fzOZ5TP4iNHpPOY1qqpmaAtTh6Q
+PzIEeL7UH3trraFmi+Gq8u4kAA==
+-----END PGP PRIVATE KEY BLOCK-----`;
+
+ await expect(openpgp.readKey({ armoredKey })).to.be.rejectedWith(/Error reading MPIs/);
+ });
+
it('Testing key ID and fingerprint for V4 keys', async function() {
const pubKeysV4 = await openpgp.readKeys({ armoredKeys: twoKeys });
expect(pubKeysV4).to.exist;
From 24c644207d5d5fba6534010bcb38795568510134 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 7 Sep 2023 19:34:44 +0200
Subject: [PATCH 066/224] Support generating Curve448 and Curve25519 keys (new
format)
Neither type is set as default for now, since they are not widely supported.
---
openpgp.d.ts | 6 +-
src/crypto/public_key/elliptic/eddsa.js | 4 +-
src/key/factory.js | 4 +-
src/key/helper.js | 8 ++-
src/key/private_key.js | 29 ++++++++-
src/openpgp.js | 6 +-
test/crypto/validate.js | 83 +++++++++++--------------
test/general/key.js | 58 +++++++++++++++++
test/general/openpgp.js | 31 ++-------
9 files changed, 143 insertions(+), 86 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index d38bd10d9..6a2e54181 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -816,7 +816,7 @@ export namespace enums {
aeadEncryptedData = 20,
}
- export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsa' | 'aedh' | 'aedsa';
+ export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsa' | 'ed25519Legacy' | 'aedh' | 'aedsa' | 'ed25519' | 'x25519' | 'ed448' | 'x448';
enum publicKey {
rsaEncryptSign = 1,
rsaEncrypt = 2,
@@ -830,6 +830,10 @@ export namespace enums {
eddsaLegacy = 22,
aedh = 23,
aedsa = 24,
+ x25519 = 25,
+ x448 = 26,
+ ed25519 = 27,
+ ed448 = 28
}
enum curve {
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index bcab724f7..8b08a671f 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -36,14 +36,14 @@ ed25519.hash = bytes => sha512(bytes);
* @returns {Promise<{ A: Uint8Array, seed: Uint8Array }>}
*/
export async function generate(algo) {
- const seed = getRandomBytes(getPayloadSize(algo));
-
switch (algo) {
case enums.publicKey.ed25519: {
+ const seed = getRandomBytes(getPayloadSize(algo));
const { publicKey: A } = ed25519.sign.keyPair.fromSeed(seed);
return { A, seed };
}
case enums.publicKey.ed448: {
+ const seed = ed448.utils.randomPrivateKey();
const A = ed448.getPublicKey(seed);
return { A, seed };
}
diff --git a/src/key/factory.js b/src/key/factory.js
index 6c1d7ee17..c485b35ca 100644
--- a/src/key/factory.js
+++ b/src/key/factory.js
@@ -64,9 +64,9 @@ function createKey(packetlist) {
/**
- * Generates a new OpenPGP key. Supports RSA and ECC keys.
+ * Generates a new OpenPGP key. Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519 keys.
* By default, primary and subkeys will be of same type.
- * @param {ecc|rsa} options.type The primary key algorithm type: ECC or RSA
+ * @param {ecc|rsa|curve448|curve25519} options.type The primary key algorithm type: ECC, RSA, Curve448 or Curve25519 (new format).
* @param {String} options.curve Elliptic curve for ECC keys
* @param {Integer} options.rsaBits Number of bits for RSA keys
* @param {Array} options.userIDs User IDs as strings or objects: 'Jo Doe ' or { name:'Jo Doe', email:'info@jo.com' }
diff --git a/src/key/helper.js b/src/key/helper.js
index e887ed193..a23bbaaea 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -326,7 +326,7 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
options.sign = options.sign || false;
switch (options.type) {
- case 'ecc':
+ case 'ecc': // NB: this case also handles legacy eddsa and x25519 keys, based on `options.curve`
try {
options.curve = enums.write(enums.curve, options.curve);
} catch (e) {
@@ -341,6 +341,12 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
options.algorithm = enums.publicKey.ecdh;
}
break;
+ case 'curve25519':
+ options.algorithm = options.sign ? enums.publicKey.ed25519 : enums.publicKey.x25519;
+ break;
+ case 'curve448':
+ options.algorithm = options.sign ? enums.publicKey.ed448 : enums.publicKey.x448;
+ break;
case 'rsa':
options.algorithm = enums.publicKey.rsaEncryptSign;
break;
diff --git a/src/key/private_key.js b/src/key/private_key.js
index 055de0085..7b86945b1 100644
--- a/src/key/private_key.js
+++ b/src/key/private_key.js
@@ -198,8 +198,10 @@ class PrivateKey extends PublicKey {
/**
* Generates a new OpenPGP subkey, and returns a clone of the Key object with the new subkey added.
- * Supports RSA and ECC keys. Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
- * @param {ecc|rsa} options.type The subkey algorithm: ECC or RSA
+ * Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519.
+ * Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
+ * @param {ecc|rsa|curve25519|curve448} options.type The subkey algorithm: ECC, RSA, Curve448 or Curve25519 (new format).
+ * Note: Curve448 and Curve25519 are not widely supported yet.
* @param {String} options.curve (optional) Elliptic curve for ECC keys
* @param {Integer} options.rsaBits (optional) Number of bits for RSA subkeys
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
@@ -225,7 +227,7 @@ class PrivateKey extends PublicKey {
throw new Error('Key is not decrypted');
}
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
- defaultOptions.type = defaultOptions.curve ? 'ecc' : 'rsa'; // DSA keys default to RSA
+ defaultOptions.type = getDefaultSubkeyType(defaultOptions.algorithm);
defaultOptions.rsaBits = defaultOptions.bits || 4096;
defaultOptions.curve = defaultOptions.curve || 'curve25519';
options = helper.sanitizeKeyOptions(options, defaultOptions);
@@ -238,4 +240,25 @@ class PrivateKey extends PublicKey {
}
}
+function getDefaultSubkeyType(algoName) {
+ const algo = enums.write(enums.publicKey, algoName);
+ // NB: no encryption-only algos, since they cannot be in primary keys
+ switch (algo) {
+ case enums.publicKey.rsaEncrypt:
+ case enums.publicKey.rsaEncryptSign:
+ case enums.publicKey.rsaSign:
+ case enums.publicKey.dsa:
+ return 'rsa';
+ case enums.publicKey.ecdsa:
+ case enums.publicKey.eddsaLegacy:
+ return 'ecc';
+ case enums.publicKey.ed25519:
+ return 'curve25519';
+ case enums.publicKey.ed448:
+ return 'curve448';
+ default:
+ throw new Error('Unsupported algorithm');
+ }
+}
+
export default PrivateKey;
diff --git a/src/openpgp.js b/src/openpgp.js
index 70dfd2406..7fad9aaa5 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -32,11 +32,13 @@ import { checkKeyRequirements } from './key/helper';
/**
- * Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type.
+ * Generates a new OpenPGP key pair. Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519 keys.
+ * By default, primary and subkeys will be of same type.
* The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated.
* @param {Object} options
* @param {Object|Array} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
- * @param {'ecc'|'rsa'} [options.type='ecc'] - The primary key algorithm type: ECC (default) or RSA
+ * @param {'ecc'|'rsa'|'curve448'|'curve25519'} [options.type='ecc'] - The primary key algorithm type: ECC (default), RSA, Curve448 or Curve25519 (new format).
+ * Note: Curve448 and Curve25519 (new format) are not widely supported yet.
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted or empty, the key won't be encrypted.
* @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys
* @param {String} [options.curve='curve25519'] - Elliptic curve for ECC keys:
diff --git a/test/crypto/validate.js b/test/crypto/validate.js
index 3388f26b6..9b9b883e5 100644
--- a/test/crypto/validate.js
+++ b/test/crypto/validate.js
@@ -193,13 +193,13 @@ export default () => {
});
});
- const curves = ['curve25519', 'p256', 'p384', 'p521', 'secp256k1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
+ const curves = ['curve25519Legacy', 'p256', 'p384', 'p521', 'secp256k1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
curves.forEach(curve => {
describe(`ECC ${curve} parameter validation`, () => {
let ecdsaKey;
let ecdhKey;
before(async () => {
- if (curve !== 'curve25519') {
+ if (curve !== 'curve25519Legacy') {
ecdsaKey = await generatePrivateKeyObject({ curve });
ecdhKey = ecdsaKey.subkeys[0];
} else {
@@ -247,58 +247,45 @@ export default () => {
});
});
- describe('Ed448/X448 parameter validation', function() {
- let eddsaKey;
- let ecdhXKey;
- before(async () => {
- eddsaKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
-5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
-x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
-HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
-BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
-Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
-8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
-tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
-y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
-ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
-BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
-6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
-JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
-x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
------END PGP PRIVATE KEY BLOCK-----` });
- ecdhXKey = eddsaKey.subkeys[0];
- });
+ // new EdDSA/XECDH algos
+ ['25519', '448'].forEach(curveID => {
+ describe(`Ed${curveID}/X${curveID} parameter validation`, function() {
+ let eddsaKey;
+ let ecdhXKey;
+ before(async () => {
+ eddsaKey = await generatePrivateKeyObject({ type: `curve${curveID}` });
+ ecdhXKey = eddsaKey.subkeys[0];
+ });
- it('Ed448 params should be valid', async function() {
- await expect(eddsaKey.keyPacket.validate()).to.not.be.rejected;
- });
+ it(`Ed${curveID} params should be valid`, async function() {
+ await expect(eddsaKey.keyPacket.validate()).to.not.be.rejected;
+ });
- it('detect invalid Ed448 public point', async function() {
- const eddsaKeyPacket = await cloneKeyPacket(eddsaKey);
- const A = eddsaKeyPacket.publicParams.A;
- A[0]++;
- await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ it(`detect invalid Ed${curveID} public point`, async function() {
+ const eddsaKeyPacket = await cloneKeyPacket(eddsaKey);
+ const A = eddsaKeyPacket.publicParams.A;
+ A[0]++;
+ await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
- const infA = new Uint8Array(A.length);
- eddsaKeyPacket.publicParams.A = infA;
- await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
- });
+ const infA = new Uint8Array(A.length);
+ eddsaKeyPacket.publicParams.A = infA;
+ await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ });
- it('X448 params should be valid', async function() {
- await expect(ecdhXKey.keyPacket.validate()).to.not.be.rejected;
- });
+ it(`X${curveID} params should be valid`, async function() {
+ await expect(ecdhXKey.keyPacket.validate()).to.not.be.rejected;
+ });
- it('detect invalid x448 public point', async function() {
- const ecdhXKeyPacket = await cloneKeyPacket(ecdhXKey);
- const A = ecdhXKeyPacket.publicParams.A;
- A[0]++;
- await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ it(`detect invalid X${curveID} public point`, async function() {
+ const ecdhXKeyPacket = await cloneKeyPacket(ecdhXKey);
+ const A = ecdhXKeyPacket.publicParams.A;
+ A[0]++;
+ await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
- const infA = new Uint8Array(A.length);
- ecdhXKeyPacket.publicParams.A = infA;
- await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ const infA = new Uint8Array(A.length);
+ ecdhXKeyPacket.publicParams.A = infA;
+ await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
+ });
});
});
diff --git a/test/general/key.js b/test/general/key.js
index adc11528b..3fedd73f9 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -2509,6 +2509,54 @@ function versionSpecificTests() {
}
});
+ it('Generate Ed25519 key (new format) - default subkey', async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const opt = { type: 'curve25519', userIDs: [userID], passphrase: '123', format: 'object' };
+ const { privateKey: key } = await openpgp.generateKey(opt);
+ expect(key.users.length).to.equal(1);
+ expect(key.users[0].userID.userID).to.equal('test ');
+ expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
+ expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
+ expect(key.subkeys).to.have.length(1);
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
+ });
+
+ it('Generate Ed25519 key (new format) - one signing subkey', async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const opt = { type: 'curve25519', userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ sign: true }] };
+ const { privateKey: key } = await openpgp.generateKey(opt);
+ expect(key.users.length).to.equal(1);
+ expect(key.users[0].userID.userID).to.equal('test ');
+ expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
+ expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
+ expect(key.subkeys).to.have.length(1);
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ed25519');
+ });
+
+ it('Generate Ed448 key - default subkey', async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const opt = { type: 'curve448', userIDs: [userID], passphrase: '123', format: 'object' };
+ const { privateKey: key } = await openpgp.generateKey(opt);
+ expect(key.users.length).to.equal(1);
+ expect(key.users[0].userID.userID).to.equal('test ');
+ expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
+ expect(key.getAlgorithmInfo().algorithm).to.equal('ed448');
+ expect(key.subkeys).to.have.length(1);
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
+ });
+
+ it('Generate Ed448 key - one signing subkey', async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const opt = { type: 'curve448', userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ sign: true }] };
+ const { privateKey: key } = await openpgp.generateKey(opt);
+ expect(key.users.length).to.equal(1);
+ expect(key.users[0].userID.userID).to.equal('test ');
+ expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
+ expect(key.getAlgorithmInfo().algorithm).to.equal('ed448');
+ expect(key.subkeys).to.have.length(1);
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ed448');
+ });
+
it('Generate key - one signing subkey', function() {
const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] };
@@ -4196,6 +4244,16 @@ VYGdb3eNlV8CfoEC
expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
});
+ it('Add a new default subkey to an Ed488 key', async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const opt = { type: 'curve448', userIDs: [userID], format: 'object', subkeys: [] };
+ const { privateKey: key } = await openpgp.generateKey(opt);
+ expect(key.subkeys).to.have.length(0);
+ const newKey = await key.addSubkey();
+ expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
+ expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.be.undefined;
+ });
+
it('Add a new default subkey to a dsa key', async function() {
const key = await openpgp.readKey({ armoredKey: dsaPrivateKey });
const total = key.subkeys.length;
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index e2ff31289..e97a21f53 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -4758,17 +4758,8 @@ sEj+v9LKoMTYZGMfp3qDVFLtkBE88eVmVjgJOoLhrsv7yh0PAA==
});
it('sign/verify with new Ed25519 format', async function () {
- // v4 key, which we do not support generating
- const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xUkEZBw5PBscroGar9fsilA0q9AX979pBhTNkGQ69vQGGW7kxRxNuABB+eAw
-JrQ9A3o1gUJg28ORTQd72+kFo87184qR97a6rRGFzQR0ZXN0wogEEBsIAD4F
-gmQcOTwECwkHCAmQT/m+Rl22Ps8DFQgKBBYAAgECGQECmwMCHgEWIQSUlOfm
-G7MWJd2909ZP+b5GXbY+zwAAVs/4pWH4l7pWcTATBavVqSATMKi4A+usp89G
-J/qaHc+qmcEpIMmPNvLQ7n4F4kEXk8Zwz+OXovVWLQ+Njl5gzooF
-=wYg1
------END PGP PRIVATE KEY BLOCK-----
- ` });
+ const userIDs = { name: 'Alice', email: 'info@alice.com' };
+ const { privateKey } = await openpgp.generateKey({ type: 'curve25519', userIDs, format: 'object' });
const plaintext = 'plaintext';
const signed = await openpgp.sign({
@@ -4786,22 +4777,8 @@ J/qaHc+qmcEpIMmPNvLQ7n4F4kEXk8Zwz+OXovVWLQ+Njl5gzooF
});
it('sign/verify with Ed448', async function () {
- const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-
-xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT
-+hLeV6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVs
-IU7QqLv1hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoA
-AAA9BQJlGotiIqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUC
-GwMCHgkCCwcDFQoIAhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vH
-z43Wb++AkmpWL1HQmrJE3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiW
-QSeMeexCTy+Gdr6j0wb4FhFNnoIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmK
-gQTSOzJEvyO0ACR5L4vV3ADceOAdG8/sqhE89rTSevFXng4JAM0XVXNlckEg
-PFVzZXJBQHRlc3QudGVzdD7CwA0GExwKAAAALAUCZRqLYiKhBgMYnbB0Rw7M
-hU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkBAAAAAFw/IH72M1iyzMWhbgtw
-v0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOjm7VAeOSfSdxt1xSKnoAL
-RsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qAmc+K5jdA2xcl9iW5
-bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGvgqe00ohRKiQA
------END PGP PRIVATE KEY BLOCK-----` });
+ const userIDs = { name: 'Alice', email: 'info@alice.com' };
+ const { privateKey } = await openpgp.generateKey({ type: 'curve448', userIDs, format: 'object' });
const plaintext = 'plaintext';
const signed = await openpgp.sign({
From 0b7a5f69fafaca5f4aa3d95c2c4ea337f20ca1d5 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 7 Sep 2023 19:36:42 +0200
Subject: [PATCH 067/224] Drop `enums.publicKey.eddsa` in favour of
`enums.publicKey.eddsaLegacy`
The crypto-refresh has standardised a new key format for EdDSA, whose algorithm
identifier are `enums.publicKey.ed25519` and `.ed448`
---
openpgp.d.ts | 4 +---
src/enums.js | 6 +-----
test/general/config.js | 8 ++++----
test/general/key.js | 12 ++++++------
test/general/x25519.js | 4 ++--
5 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index 6a2e54181..529fdb610 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -816,7 +816,7 @@ export namespace enums {
aeadEncryptedData = 20,
}
- export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsa' | 'ed25519Legacy' | 'aedh' | 'aedsa' | 'ed25519' | 'x25519' | 'ed448' | 'x448';
+ export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsaLegacy' | 'aedh' | 'aedsa' | 'ed25519' | 'x25519' | 'ed448' | 'x448';
enum publicKey {
rsaEncryptSign = 1,
rsaEncrypt = 2,
@@ -825,8 +825,6 @@ export namespace enums {
dsa = 17,
ecdh = 18,
ecdsa = 19,
- /** @deprecated use `eddsaLegacy` instead */
- eddsa = 22,
eddsaLegacy = 22,
aedh = 23,
aedsa = 24,
diff --git a/src/enums.js b/src/enums.js
index 5dbbffcc0..61fe1b370 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -116,11 +116,7 @@ export default {
ecdsa: 19,
/** EdDSA (Sign only) - deprecated by crypto-refresh (replaced by `ed25519` identifier below)
* [{@link https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04|Draft RFC}] */
- eddsaLegacy: 22, // NB: this is declared before `eddsa` to translate 22 to 'eddsa' for backwards compatibility
- /** @deprecated use `eddsaLegacy` instead */
- ed25519Legacy: 22,
- /** @deprecated use `eddsaLegacy` instead */
- eddsa: 22,
+ eddsaLegacy: 22,
/** Reserved for AEDH */
aedh: 23,
/** Reserved for AEDSA */
diff --git a/test/general/config.js b/test/general/config.js
index 66032a91e..3da4c40ab 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -369,10 +369,10 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
await expect(openpgp.sign({
message, signingKeys: [key], config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsaLegacy]) }
- })).to.be.eventually.rejectedWith(/eddsa keys are considered too weak/);
+ })).to.be.eventually.rejectedWith(/eddsaLegacy keys are considered too weak/);
await expect(openpgp.sign({
message, signingKeys: [key], config: { rejectCurves: new Set([openpgp.enums.curve.ed25519Legacy]) }
- })).to.be.eventually.rejectedWith(/Support for eddsa keys using curve ed25519 is disabled/);
+ })).to.be.eventually.rejectedWith(/Support for eddsaLegacy keys using curve ed25519 is disabled/);
});
it('openpgp.verify', async function() {
@@ -416,7 +416,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsaLegacy]) }
};
const { signatures: [sig4] } = await openpgp.verify(opt4);
- await expect(sig4.verified).to.be.rejectedWith(/eddsa keys are considered too weak/);
+ await expect(sig4.verified).to.be.rejectedWith(/eddsaLegacy keys are considered too weak/);
const opt5 = {
message: await openpgp.readMessage({ armoredMessage: signed }),
@@ -424,7 +424,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
config: { rejectCurves: new Set([openpgp.enums.curve.ed25519Legacy]) }
};
const { signatures: [sig5] } = await openpgp.verify(opt5);
- await expect(sig5.verified).to.be.eventually.rejectedWith(/Support for eddsa keys using curve ed25519 is disabled/);
+ await expect(sig5.verified).to.be.eventually.rejectedWith(/Support for eddsaLegacy keys using curve ed25519 is disabled/);
});
describe('detects unknown config property', async function() {
diff --git a/test/general/key.js b/test/general/key.js
index 3fedd73f9..4eb8eda1d 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -2467,7 +2467,7 @@ function versionSpecificTests() {
const opt = { userIDs: [userID], format: 'object' };
return openpgp.generateKey(opt).then(function({ privateKey: key }) {
expect(key.isDecrypted()).to.be.true;
- expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa');
+ expect(key.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test ');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
@@ -2567,7 +2567,7 @@ function versionSpecificTests() {
expect(key.subkeys).to.have.length(2);
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]);
- expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsa');
+ expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
expect(await key.getSigningKey()).to.equal(key.subkeys[1]);
});
});
@@ -2585,7 +2585,7 @@ function versionSpecificTests() {
expect(key.subkeys).to.have.length(2);
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]);
- expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsa');
+ expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
expect(await key.getSigningKey()).to.equal(key.subkeys[1]);
});
});
@@ -4344,7 +4344,7 @@ XvmoLueOOShu01X/kaylMqaT8w==
const subkeyOid = subkey2.keyPacket.publicParams.oid;
const pkOid = privateKey.keyPacket.publicParams.oid;
expect(subkeyOid.getName()).to.be.equal(pkOid.getName());
- expect(subkey2.getAlgorithmInfo().algorithm).to.be.equal('eddsa');
+ expect(subkey2.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
await subkey2.verify();
});
@@ -4359,7 +4359,7 @@ XvmoLueOOShu01X/kaylMqaT8w==
expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
expect(newPrivateKey.getAlgorithmInfo().curve).to.be.equal('ed25519');
expect(subkey.getAlgorithmInfo().curve).to.be.equal('p256');
- expect(newPrivateKey.getAlgorithmInfo().algorithm).to.be.equal('eddsa');
+ expect(newPrivateKey.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdsa');
await subkey.verify();
@@ -4427,7 +4427,7 @@ XvmoLueOOShu01X/kaylMqaT8w==
const subkeyOid = subkey.keyPacket.publicParams.oid;
const pkOid = newPrivateKey.keyPacket.publicParams.oid;
expect(subkeyOid.getName()).to.be.equal(pkOid.getName());
- expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('eddsa');
+ expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
await subkey.verify();
expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey);
const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, format: 'binary' });
diff --git a/test/general/x25519.js b/test/general/x25519.js
index 52bd19c26..f197c595f 100644
--- a/test/general/x25519.js
+++ b/test/general/x25519.js
@@ -396,7 +396,7 @@ function omnibus() {
const primaryKey = hi.keyPacket;
const subkey = hi.subkeys[0];
expect(hi.getAlgorithmInfo().curve).to.equal('ed25519');
- expect(hi.getAlgorithmInfo().algorithm).to.equal('eddsa');
+ expect(hi.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
expect(subkey.getAlgorithmInfo().curve).to.equal('curve25519');
expect(subkey.getAlgorithmInfo().algorithm).to.equal('ecdh');
@@ -416,7 +416,7 @@ function omnibus() {
return openpgp.generateKey(options).then(async function({ privateKey: bye }) {
expect(bye.getAlgorithmInfo().curve).to.equal('ed25519');
- expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsa');
+ expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
expect(bye.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
expect(bye.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
From 360a44f57babdd08762abd22d89e6f6488d38f63 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 26 Sep 2023 19:23:30 +0200
Subject: [PATCH 068/224] `addSubkey`: match primary key version
As required by the spec.
---
src/key/private_key.js | 6 +++++-
test/general/key.js | 41 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/src/key/private_key.js b/src/key/private_key.js
index 7b86945b1..b65336761 100644
--- a/src/key/private_key.js
+++ b/src/key/private_key.js
@@ -231,7 +231,11 @@ class PrivateKey extends PublicKey {
defaultOptions.rsaBits = defaultOptions.bits || 4096;
defaultOptions.curve = defaultOptions.curve || 'curve25519';
options = helper.sanitizeKeyOptions(options, defaultOptions);
- const keyPacket = await helper.generateSecretSubkey(options);
+ // Every subkey for a v4 primary key MUST be a v4 subkey.
+ // Every subkey for a v6 primary key MUST be a v6 subkey.
+ // For v5 keys, since we dropped generation support, a v4 subkey is added.
+ // The config is always overwritten since we cannot tell if the defaultConfig was changed by the user.
+ const keyPacket = await helper.generateSecretSubkey(options, { ...config, v6Keys: this.keyPacket.version === 6 });
helper.checkKeyRequirements(keyPacket, config);
const bindingSignature = await helper.createBindingSignature(keyPacket, secretKeyPacket, options, config);
const packetList = this.toPacketList();
diff --git a/test/general/key.js b/test/general/key.js
index 4eb8eda1d..2238b510c 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -4249,8 +4249,20 @@ VYGdb3eNlV8CfoEC
const opt = { type: 'curve448', userIDs: [userID], format: 'object', subkeys: [] };
const { privateKey: key } = await openpgp.generateKey(opt);
expect(key.subkeys).to.have.length(0);
+ const keyWithNewSubkey = await key.addSubkey();
+ const parsedNewKey = await openpgp.readKey({ armoredKey: keyWithNewSubkey.armor() });
+ expect(parsedNewKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
+ expect(parsedNewKey.subkeys[0].getAlgorithmInfo().curve).to.be.undefined;
+ });
+
+ it('Add a new default subkey to a v6 key', async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const opt = { type: 'curve25519', userIDs: [userID], format: 'object', subkeys: [], config: { v6Keys: true } };
+ const { privateKey: key } = await openpgp.generateKey(opt);
+ expect(key.subkeys).to.have.length(0);
const newKey = await key.addSubkey();
- expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
+ expect(newKey.subkeys[0].keyPacket.version).to.equal(6);
+ expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.be.undefined;
});
@@ -4464,6 +4476,33 @@ XvmoLueOOShu01X/kaylMqaT8w==
expect(decrypted.data).to.be.equal(vData);
});
+ ['curve25519', 'curve448'].forEach(keyType => (
+ it(`encrypt/decrypt data with the new subkey correctly using ${keyType}`, async function() {
+ const userID = { name: 'test', email: 'a@b.com' };
+ const vData = 'the data to encrypted!';
+ const opt = { type: keyType, userIDs: [userID], format: 'object', subkeys:[] };
+ const { privateKey } = await openpgp.generateKey(opt);
+ const total = privateKey.subkeys.length;
+ let newPrivateKey = await privateKey.addSubkey();
+ const armoredKey = newPrivateKey.armor();
+ newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
+ const subkey = newPrivateKey.subkeys[total];
+ const publicKey = newPrivateKey.toPublic();
+ await subkey.verify();
+ expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
+ const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, format: 'binary' });
+ expect(encrypted).to.be.exist;
+ const message = await openpgp.readMessage({ binaryMessage: encrypted });
+ const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
+ expect(pkSessionKeys).to.exist;
+ expect(pkSessionKeys.length).to.be.equal(1);
+ expect(pkSessionKeys[0].publicKeyID.toHex()).to.be.equals(subkey.keyPacket.getKeyID().toHex());
+ const decrypted = await openpgp.decrypt({ message, decryptionKeys: newPrivateKey });
+ expect(decrypted).to.exist;
+ expect(decrypted.data).to.be.equal(vData);
+ })
+ ));
+
it('sign/verify data with the new subkey correctly using rsa', async function() {
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
From 7c2248151da0d31b1bbd8f06b50708cd8b947327 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 26 Sep 2023 15:36:14 +0200
Subject: [PATCH 069/224] Default to generating new curve25519 format for v6
keys
As per the spec, v6 keys must not use the legacy curve25519 format.
The new format is not used by default with v4 keys as it's not compatible with OpenPGP.js older than v5.10.0 .
However, v6 keys already break compatibility, so if the user requests them via config flag, we can safely use the new curve format as well.
---
src/openpgp.js | 11 +++++++++--
test/general/key.js | 29 ++++++++++++++++++++---------
test/general/openpgp.js | 34 +++++++++++++++++++++++++++++++++-
3 files changed, 62 insertions(+), 12 deletions(-)
diff --git a/src/openpgp.js b/src/openpgp.js
index 7fad9aaa5..13c93d58d 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -37,7 +37,7 @@ import { checkKeyRequirements } from './key/helper';
* The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated.
* @param {Object} options
* @param {Object|Array} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
- * @param {'ecc'|'rsa'|'curve448'|'curve25519'} [options.type='ecc'] - The primary key algorithm type: ECC (default), RSA, Curve448 or Curve25519 (new format).
+ * @param {'ecc'|'rsa'|'curve448'|'curve25519'} [options.type='ecc'] - The primary key algorithm type: ECC (default for v4 keys), RSA, Curve448 or Curve25519 (new format, default for v6 keys).
* Note: Curve448 and Curve25519 (new format) are not widely supported yet.
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted or empty, the key won't be encrypted.
* @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys
@@ -55,8 +55,15 @@ import { checkKeyRequirements } from './key/helper';
* @async
* @static
*/
-export async function generateKey({ userIDs = [], passphrase, type = 'ecc', rsaBits = 4096, curve = 'curve25519', keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armored', config, ...rest }) {
+export async function generateKey({ userIDs = [], passphrase, type, curve, rsaBits = 4096, keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armored', config, ...rest }) {
config = { ...defaultConfig, ...config }; checkConfig(config);
+ if (!type && !curve) {
+ type = config.v6Keys ? 'curve25519' : 'ecc'; // default to new curve25519 for v6 keys (legacy curve25519 cannot be used with them)
+ curve = 'curve25519'; // unused with type != 'ecc'
+ } else {
+ type = type || 'ecc';
+ curve = curve || 'curve25519';
+ }
userIDs = toArray(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
diff --git a/test/general/key.js b/test/general/key.js
index 2238b510c..b30f01666 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -2463,29 +2463,35 @@ function versionSpecificTests() {
});
it('Generate key - default values', function() {
+ const v6Key = openpgp.config.v6Keys;
+
const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], format: 'object' };
return openpgp.generateKey(opt).then(function({ privateKey: key }) {
+ expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
expect(key.isDecrypted()).to.be.true;
- expect(key.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
+ expect(key.getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy');
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test ');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subkeys).to.have.length(1);
- expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
});
});
it('Generate key - two subkeys with default values', function() {
+ const v6Key = openpgp.config.v6Keys;
+
const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] };
return openpgp.generateKey(opt).then(function({ privateKey: key }) {
+ expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test ');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subkeys).to.have.length(2);
- expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
- expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
+ expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
});
});
@@ -2558,34 +2564,39 @@ function versionSpecificTests() {
});
it('Generate key - one signing subkey', function() {
+ const v6Key = openpgp.config.v6Keys;
const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] };
+
return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
+ expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test ');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subkeys).to.have.length(2);
- expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]);
- expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
+ expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy');
expect(await key.getSigningKey()).to.equal(key.subkeys[1]);
});
});
it('Reformat key - one signing subkey', async function() {
+ const v6Key = openpgp.config.v6Keys;
const userID = { name: 'test', email: 'a@b.com' };
const opt = { userIDs: [userID], format: 'object', subkeys:[{}, { sign: true }] };
const { privateKey } = await openpgp.generateKey(opt);
return openpgp.reformatKey({ privateKey, userIDs: [userID] }).then(async function({ privateKey: armoredKey }) {
const key = await openpgp.readKey({ armoredKey });
+ expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.userID).to.equal('test ');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subkeys).to.have.length(2);
- expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]);
- expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
+ expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy');
expect(await key.getSigningKey()).to.equal(key.subkeys[1]);
});
});
@@ -2596,7 +2607,7 @@ function versionSpecificTests() {
openpgp.config.minRSABits = rsaBits;
const userID = { name: 'test', email: 'a@b.com' };
- const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'curve25519' }] };
+ const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'p256' }] };
try {
const { privateKey: key } = await openpgp.generateKey(opt);
expect(key.users.length).to.equal(1);
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index e97a21f53..d59c4cd1f 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1012,7 +1012,7 @@ export default () => describe('OpenPGP.js public api tests', function() {
});
describe('generateKey - unit tests', function() {
- it('should have default params set', function() {
+ it('should have default params set (v4 key)', function() {
const now = util.normalizeDate(new Date());
const opt = {
userIDs: { name: 'Test User', email: 'text@example.com' },
@@ -1023,6 +1023,7 @@ export default () => describe('OpenPGP.js public api tests', function() {
return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
for (const key of [publicKey, privateKey]) {
expect(key).to.exist;
+ expect(key.keyPacket.version).to.equal(4);
expect(key.users.length).to.equal(1);
expect(key.users[0].userID.name).to.equal('Test User');
expect(key.users[0].userID.email).to.equal('text@example.com');
@@ -1039,6 +1040,37 @@ export default () => describe('OpenPGP.js public api tests', function() {
});
});
+ it('should have default params set (v6 key)', function() {
+ const now = util.normalizeDate(new Date());
+ const opt = {
+ userIDs: { name: 'Test User', email: 'text@example.com' },
+ passphrase: 'secret',
+ date: now,
+ format: 'object',
+ config: { v6Keys: true }
+ };
+ return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
+ for (const key of [publicKey, privateKey]) {
+ expect(key).to.exist;
+ expect(key.keyPacket.version).to.equal(6);
+ expect(key.users.length).to.equal(1);
+ expect(key.users[0].userID.name).to.equal('Test User');
+ expect(key.users[0].userID.email).to.equal('text@example.com');
+ expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
+ expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
+ expect(key.getAlgorithmInfo().curve).to.equal(undefined);
+ expect(+key.getCreationTime()).to.equal(+now);
+ expect(await key.getExpirationTime()).to.equal(Infinity);
+ expect(key.subkeys.length).to.equal(1);
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
+ expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
+ expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal(undefined);
+ expect(+key.subkeys[0].getCreationTime()).to.equal(+now);
+ expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity);
+ }
+ });
+ });
+
it('should output keypair with expected format', async function() {
const opt = {
userIDs: { name: 'Test User', email: 'text@example.com' }
From c7efef60ac8b15895a6a45d990fdb659214bfde9 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 26 Sep 2023 15:30:44 +0200
Subject: [PATCH 070/224] Throw when parsing v6 keys using legacy curve25519
---
src/packet/public_key.js | 11 +++++++++++
test/general/signature.js | 30 ++++++++++++++----------------
2 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/src/packet/public_key.js b/src/packet/public_key.js
index af81f3a95..17732e07e 100644
--- a/src/packet/public_key.js
+++ b/src/packet/public_key.js
@@ -124,6 +124,17 @@ class PublicKeyPacket {
// - A series of values comprising the key material.
const { read, publicParams } = crypto.parsePublicKeyParams(this.algorithm, bytes.subarray(pos));
+ // The deprecated OIDs for Ed25519Legacy and Curve25519Legacy are used in legacy version 4 keys and signatures.
+ // Implementations MUST NOT accept or generate v6 key material using the deprecated OIDs.
+ if (
+ this.version === 6 &&
+ publicParams.oid && (
+ publicParams.oid.getName() === enums.curve.curve25519Legacy ||
+ publicParams.oid.getName() === enums.curve.ed25519Legacy
+ )
+ ) {
+ throw new Error('Legacy curve25519 cannot be used with v6 keys');
+ }
this.publicParams = publicParams;
pos += read;
diff --git a/test/general/signature.js b/test/general/signature.js
index 5580fedd5..63ce14baf 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -1089,25 +1089,23 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
// signature with salt shorter than expected
const armoredMessage = `-----BEGIN PGP MESSAGE-----
-xEQGAQoWHgTCf3OkPcYPPB6GmoMeaOz1wYXbuSvHxW/PVbRIynPv5yU3YApt
-KDJPb4mCbmxvCoKjGx6CMjDpDsVB+wDFAcsLdQBlEWcKaGVsbG/CmgYBFgoA
-AAApBYJlEWcKIqEGc+/nJTdgCm0oMk9viYJubG8KgqMbHoIyMOkOxUH7AMUA
-AAAA5GYeBMJ/c6Q9xg88Hoaagx5o7PXBhdu5K8fFb89VtEjKAQCW/XwAPo2V
-ugvc1634oGA/74j7KonU2qdl0LvxVJuB2wEAtutHh3wry/SNkc+japCGO4u4
-XjIVmkzQNtymmOECUwI=
+xDQGAQgbDpdDiCIrq6YZAf5vD3wFIucHRyMNlExatdj6sQcW2FA/vV5eZGCv
+mBUS4Mqqki4ByxR1AGUddyNUaGlzIGlzIHNpZ25lZMKGBgEbCAAAACkFgmUd
+dyMioQYi5wdHIw2UTFq12PqxBxbYUD+9Xl5kYK+YFRLgyqqSLgAAAADZ9w6X
+Q4giK6umGQH+bw98BS96KSXxW39Ue6hNxbSoc5xOqYnTsD+75FYdR1U9fco/
+HDpH7axPa2euIDpwT60NedSjcTx7C9Sots4mTvjMwQQ=
-----END PGP MESSAGE-----`;
const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
-xVoGZRFjtxYAAAAtCSsGAQQB2kcPAQEHQJRcfAi8wlCCWAeBcvpRO6iL5YK8
-1e8BVcOkAGVXKDguAAEAxIUb1xswIKPfVEyOZkqSFukVOegoArxIeEuDaoK0
-feXCrQYfFgoAAAA6BYJlEWO3AwsJBwMVCAoCFgACmwMCHgEioQZz7+clN2AK
-bSgyT2+Jgm5sbwqCoxsegjIw6Q7FQfsAxQAAAACBKyDA5Ih9cWlc9o5NUzmo
-jSCtKhy54bBzfRX0t9Jha4BfZwD9FvmhOEpJAnYRDmBrEiaO4okM3D6eNZz9
-rmGZkLT9oJMBAI6UbwsjgWw42W85Kb57tfYdF/779TrLHcNRZLNV0p8NzQDC
-nwYQFgoAAAAsBYJlEWO3AhkBIqEGc+/nJTdgCm0oMk9viYJubG8KgqMbHoIy
-MOkOxUH7AMUAAAAAV2kgOkNvj/g+Q6hFcHcpRFekCUxOons+JgXE+lxuKnbt
-l10BAO7pYlHAee5dxkzQI3WPiiYFt/OYrnr7fT5QadRZhAutAP9n5bvQaoLX
-vfHp79dKJnU1qDnSTEshB7ytt9I3Ze+DAQ==
+xUsGZR13GRsAAAAgcCI5M7vPn+9uD1ii8nnT/schP5BjXXTyr+q7EmSlcaoA
+/OkLygFTbUdwt6hMlfcNyUmS058WSIHxaVtG4uSfyjbCmQYfGwgAAAA6BYJl
+HXcZAwsJBwMVCAoCFgACmwMCHgEioQYi5wdHIw2UTFq12PqxBxbYUD+9Xl5k
+YK+YFRLgyqqSLgAAAABCZxAAxl8ycoAAY74DEPZDnfSYLP+dqdM8QZ3b/Mp4
+fnzOcVI4RvaxAjp3GZVXxisSS36A2fUx2lpj38y1tIvnnlShfpuylTp73foT
+DVf/bROnAM0AwosGEBsIAAAALAWCZR13GQIZASKhBiLnB0cjDZRMWrXY+rEH
+FthQP71eXmRgr5gVEuDKqpIuAAAAAFEEEFrhrlN40SgxwpL3UaSWs6F5pD83
+AOtaXLA/e9gFPNgiLnuid3AqUaFa6JlhWf4N/Md6SMQJ5cC7ATxTJ2a3xAMY
+5UsE6+HN099QVLx95CMP
-----END PGP PRIVATE KEY BLOCK-----` });
const { signatures } = await openpgp.verify({
From d6d8576700d1e29180ab1e934d60a6a6b8b9f18c Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 26 Sep 2023 15:31:24 +0200
Subject: [PATCH 071/224] Prevent generating v6 keys using legacy curve25519
---
src/packet/secret_key.js | 8 ++++++++
test/general/key.js | 20 ++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js
index 6dbb3b72a..acebd0a61 100644
--- a/src/packet/secret_key.js
+++ b/src/packet/secret_key.js
@@ -487,6 +487,14 @@ class SecretKeyPacket extends PublicKeyPacket {
}
async generate(bits, curve) {
+ // The deprecated OIDs for Ed25519Legacy and Curve25519Legacy are used in legacy version 4 keys and signatures.
+ // Implementations MUST NOT accept or generate v6 key material using the deprecated OIDs.
+ if (this.version === 6 && (
+ (this.algorithm === enums.publicKey.ecdh && curve === enums.curve.curve25519Legacy) ||
+ this.algorithm === enums.publicKey.eddsaLegacy
+ )) {
+ throw new Error(`Cannot generate v6 keys of type 'ecc' with curve ${curve}. Generate a key of type 'curve25519' instead`);
+ }
const { privateParams, publicParams } = await crypto.generateParams(this.algorithm, bits, curve);
this.privateParams = privateParams;
this.publicParams = publicParams;
diff --git a/test/general/key.js b/test/general/key.js
index b30f01666..4ee961335 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -4314,6 +4314,26 @@ XvmoLueOOShu01X/kaylMqaT8w==
expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('secp256k1');
});
+ it('should throw when trying to add a curve25519Legacy key to a v6 key', async function() {
+ const v6Key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMA
+GXKBexK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJj
+h3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifB
+ilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2
+kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
+QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaT
+JINn+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u
+/tVY6a//1q0NWC1X+yui3O24wpsGGBsKAAAALAWCY4d/4wKbDCIhBssYbE8G
+CaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8j+Vj
+FM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
+I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
+-----END PGP PRIVATE KEY BLOCK-----` });
+ expect(v6Key.subkeys).to.have.length(1);
+ await expect(v6Key.addSubkey({ type: 'ecc' })).to.be.rejectedWith(/Cannot generate v6 keys of type 'ecc' with curve curve25519/);
+ expect(v6Key.subkeys).to.have.length(1);
+ });
+
it('should throw when trying to encrypt a subkey separately from key', async function() {
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
From 01df8ca889368894056f8ef20a75c0c4624eb418 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Fri, 20 Oct 2023 17:16:04 +0200
Subject: [PATCH 072/224] Rename values of `enums.curve.{curve, ed}25519Legacy`
from `'{curve. ed}25519'` to `'{curve. ed}25519Legacy'`
To reflect the crypto-refresh naming, after the standardisation of the new EdDSA
key types.
---
openpgp.d.ts | 10 +++----
src/crypto/public_key/elliptic/ecdh.js | 4 +--
.../public_key/elliptic/eddsa_legacy.js | 2 +-
src/crypto/public_key/elliptic/oid_curves.js | 20 ++++++-------
src/enums.js | 30 +++++++++----------
src/key/helper.js | 3 +-
src/key/private_key.js | 2 +-
src/openpgp.js | 8 ++---
test/crypto/ecdh.js | 6 ++--
test/crypto/elliptic.js | 4 +--
test/crypto/validate.js | 6 ++--
test/general/config.js | 6 ++--
test/general/key.js | 18 +++++------
test/general/openpgp.js | 24 +++++++++++++--
test/general/x25519.js | 14 ++++-----
15 files changed, 88 insertions(+), 69 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index 529fdb610..3082030f0 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -687,7 +687,7 @@ interface KeyPair {
publicKey: PublicKey;
}
-export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1';
+export type EllipticCurveName = 'ed25519Legacy' | 'curve25519Legacy' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1';
interface GenerateKeyOptions {
userIDs: MaybeArray;
@@ -839,11 +839,11 @@ export namespace enums {
p384 = 'p384',
p521 = 'p521',
/** @deprecated use `ed25519Legacy` instead */
- ed25519 = 'ed25519',
- ed25519Legacy = 'ed25519',
+ ed25519 = 'ed25519Legacy',
+ ed25519Legacy = 'ed25519Legacy',
/** @deprecated use `curve25519Legacy` instead */
- curve25519 = 'curve25519',
- curve25519Legacy = 'curve25519',
+ curve25519 = 'curve25519Legacy',
+ curve25519Legacy = 'curve25519Legacy',
secp256k1 = 'secp256k1',
brainpoolP256r1 = 'brainpoolP256r1',
brainpoolP384r1 = 'brainpoolP384r1',
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index e37fb6334..370019165 100644
--- a/src/crypto/public_key/elliptic/ecdh.js
+++ b/src/crypto/public_key/elliptic/ecdh.js
@@ -92,7 +92,7 @@ async function kdf(hashAlgo, X, length, param, stripLeading = false, stripTraili
*/
async function genPublicEphemeralKey(curve, Q) {
switch (curve.type) {
- case 'curve25519': {
+ case 'curve25519Legacy': {
const d = getRandomBytes(32);
const { secretKey, sharedKey } = await genPrivateEphemeralKey(curve, Q, null, d);
let { publicKey } = nacl.box.keyPair.fromSecretKey(secretKey);
@@ -154,7 +154,7 @@ async function genPrivateEphemeralKey(curve, V, Q, d) {
d = privateKey;
}
switch (curve.type) {
- case 'curve25519': {
+ case 'curve25519Legacy': {
const secretKey = d.slice().reverse();
const sharedKey = nacl.scalarMult(secretKey, V.subarray(1));
return { secretKey, sharedKey }; // Note: sharedKey is little-endian here, unlike below
diff --git a/src/crypto/public_key/elliptic/eddsa_legacy.js b/src/crypto/public_key/elliptic/eddsa_legacy.js
index 3de09ba40..d90e0f9c6 100644
--- a/src/crypto/public_key/elliptic/eddsa_legacy.js
+++ b/src/crypto/public_key/elliptic/eddsa_legacy.js
@@ -86,7 +86,7 @@ export async function verify(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
*/
export async function validateParams(oid, Q, k) {
// Check whether the given curve is supported
- if (oid.getName() !== 'ed25519') {
+ if (oid.getName() !== enums.curve.ed25519Legacy) {
return false;
}
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index 129ab22c7..4d40e25b3 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -89,14 +89,14 @@ const curves = {
node: nodeCurves.secp256k1,
payloadSize: 32
},
- ed25519: {
+ ed25519Legacy: {
oid: [0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01],
keyType: enums.publicKey.eddsaLegacy,
hash: enums.hash.sha512,
node: false, // nodeCurves.ed25519 TODO
payloadSize: 32
},
- curve25519: {
+ curve25519Legacy: {
oid: [0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01],
keyType: enums.publicKey.ecdh,
hash: enums.hash.sha256,
@@ -161,10 +161,10 @@ class CurveWithOID {
this.type = 'web';
} else if (this.node && util.getNodeCrypto()) {
this.type = 'node';
- } else if (this.name === 'curve25519') {
- this.type = 'curve25519';
- } else if (this.name === 'ed25519') {
- this.type = 'ed25519';
+ } else if (this.name === enums.curve.curve25519Legacy) {
+ this.type = 'curve25519Legacy';
+ } else if (this.name === enums.curve.ed25519Legacy) {
+ this.type = 'ed25519Legacy';
}
}
@@ -180,7 +180,7 @@ class CurveWithOID {
}
case 'node':
return nodeGenKeyPair(this.name);
- case 'curve25519': {
+ case 'curve25519Legacy': {
const privateKey = getRandomBytes(32);
privateKey[0] = (privateKey[0] & 127) | 64;
privateKey[31] &= 248;
@@ -189,7 +189,7 @@ class CurveWithOID {
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
return { publicKey, privateKey };
}
- case 'ed25519': {
+ case 'ed25519Legacy': {
const privateKey = getRandomBytes(32);
const keyPair = nacl.sign.keyPair.fromSeed(privateKey);
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
@@ -243,7 +243,7 @@ async function validateStandardParams(algo, oid, Q, d) {
p384: true,
p521: true,
secp256k1: true,
- curve25519: algo === enums.publicKey.ecdh,
+ curve25519Legacy: algo === enums.publicKey.ecdh,
brainpoolP256r1: true,
brainpoolP384r1: true,
brainpoolP512r1: true
@@ -255,7 +255,7 @@ async function validateStandardParams(algo, oid, Q, d) {
return false;
}
- if (curveName === 'curve25519') {
+ if (curveName === enums.curve.curve25519Legacy) {
d = d.slice().reverse();
// Re-derive public point Q'
const { publicKey } = nacl.box.keyPair.fromSecretKey(d);
diff --git a/src/enums.js b/src/enums.js
index 61fe1b370..8a417ec0e 100644
--- a/src/enums.js
+++ b/src/enums.js
@@ -44,25 +44,25 @@ export default {
'2B8104000A': 'secp256k1',
/** Ed25519 - deprecated by crypto-refresh (replaced by standaone Ed25519 algo) */
- 'ed25519Legacy': 'ed25519',
- 'ED25519': 'ed25519',
+ 'ed25519Legacy': 'ed25519Legacy',
+ 'ED25519': 'ed25519Legacy',
/** @deprecated use `ed25519Legacy` instead */
- 'ed25519': 'ed25519',
- 'Ed25519': 'ed25519',
- '1.3.6.1.4.1.11591.15.1': 'ed25519',
- '2b06010401da470f01': 'ed25519',
- '2B06010401DA470F01': 'ed25519',
+ 'ed25519': 'ed25519Legacy',
+ 'Ed25519': 'ed25519Legacy',
+ '1.3.6.1.4.1.11591.15.1': 'ed25519Legacy',
+ '2b06010401da470f01': 'ed25519Legacy',
+ '2B06010401DA470F01': 'ed25519Legacy',
/** Curve25519 - deprecated by crypto-refresh (replaced by standaone X25519 algo) */
- 'curve25519Legacy': 'curve25519',
- 'X25519': 'curve25519',
- 'cv25519': 'curve25519',
+ 'curve25519Legacy': 'curve25519Legacy',
+ 'X25519': 'curve25519Legacy',
+ 'cv25519': 'curve25519Legacy',
/** @deprecated use `curve25519Legacy` instead */
- 'curve25519': 'curve25519',
- 'Curve25519': 'curve25519',
- '1.3.6.1.4.1.3029.1.5.1': 'curve25519',
- '2b060104019755010501': 'curve25519',
- '2B060104019755010501': 'curve25519',
+ 'curve25519': 'curve25519Legacy',
+ 'Curve25519': 'curve25519Legacy',
+ '1.3.6.1.4.1.3029.1.5.1': 'curve25519Legacy',
+ '2b060104019755010501': 'curve25519Legacy',
+ '2B060104019755010501': 'curve25519Legacy',
/** BrainpoolP256r1 Curve */
'brainpoolP256r1': 'brainpoolP256r1',
diff --git a/src/key/helper.js b/src/key/helper.js
index a23bbaaea..babaf3e6c 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -332,7 +332,8 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
} catch (e) {
throw new Error('Unknown curve');
}
- if (options.curve === enums.curve.ed25519Legacy || options.curve === enums.curve.curve25519Legacy) {
+ if (options.curve === enums.curve.ed25519Legacy || options.curve === enums.curve.curve25519Legacy ||
+ options.curve === 'ed25519' || options.curve === 'curve25519') { // keep support for curve names without 'Legacy' addition, for now
options.curve = options.sign ? enums.curve.ed25519Legacy : enums.curve.curve25519Legacy;
}
if (options.sign) {
diff --git a/src/key/private_key.js b/src/key/private_key.js
index b65336761..9fe89ca99 100644
--- a/src/key/private_key.js
+++ b/src/key/private_key.js
@@ -229,7 +229,7 @@ class PrivateKey extends PublicKey {
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
defaultOptions.type = getDefaultSubkeyType(defaultOptions.algorithm);
defaultOptions.rsaBits = defaultOptions.bits || 4096;
- defaultOptions.curve = defaultOptions.curve || 'curve25519';
+ defaultOptions.curve = defaultOptions.curve || 'curve25519Legacy';
options = helper.sanitizeKeyOptions(options, defaultOptions);
// Every subkey for a v4 primary key MUST be a v4 subkey.
// Every subkey for a v6 primary key MUST be a v6 subkey.
diff --git a/src/openpgp.js b/src/openpgp.js
index 13c93d58d..408eb3e22 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -41,8 +41,8 @@ import { checkKeyRequirements } from './key/helper';
* Note: Curve448 and Curve25519 (new format) are not widely supported yet.
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted or empty, the key won't be encrypted.
* @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys
- * @param {String} [options.curve='curve25519'] - Elliptic curve for ECC keys:
- * curve25519 (default), p256, p384, p521, secp256k1,
+ * @param {String} [options.curve='curve25519Legacy'] - Elliptic curve for ECC keys:
+ * curve25519Legacy (default), p256, p384, p521, secp256k1,
* brainpoolP256r1, brainpoolP384r1, or brainpoolP512r1
* @param {Date} [options.date=current date] - Override the creation date of the key and the key signatures
* @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires
@@ -59,10 +59,10 @@ export async function generateKey({ userIDs = [], passphrase, type, curve, rsaBi
config = { ...defaultConfig, ...config }; checkConfig(config);
if (!type && !curve) {
type = config.v6Keys ? 'curve25519' : 'ecc'; // default to new curve25519 for v6 keys (legacy curve25519 cannot be used with them)
- curve = 'curve25519'; // unused with type != 'ecc'
+ curve = 'curve25519Legacy'; // unused with type != 'ecc'
} else {
type = type || 'ecc';
- curve = curve || 'curve25519';
+ curve = curve || 'curve25519Legacy';
}
userIDs = toArray(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index 4f211386e..85eba9faf 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -149,7 +149,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
});
it('Different keys', async function () {
- const curve = new elliptic_curves.CurveWithOID('curve25519');
+ const curve = new elliptic_curves.CurveWithOID(openpgp.enums.curve.curve25519Legacy);
const oid = new OID(curve.oid);
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
const data = util.stringToUint8Array('test');
@@ -160,7 +160,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
});
it('Invalid fingerprint', async function () {
- const curve = new elliptic_curves.CurveWithOID('curve25519');
+ const curve = new elliptic_curves.CurveWithOID(openpgp.enums.curve.curve25519Legacy);
const oid = new OID(curve.oid);
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
const data = util.stringToUint8Array('test');
@@ -171,7 +171,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
});
it('Successful exchange x25519 (legacy)', async function () {
- const curve = new elliptic_curves.CurveWithOID('curve25519');
+ const curve = new elliptic_curves.CurveWithOID(openpgp.enums.curve.curve25519Legacy);
const oid = new OID(curve.oid);
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
const data = util.stringToUint8Array('test');
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index f34660e05..048413fdf 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -71,8 +71,8 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
this.skip();
}
- const names = config.useIndutnyElliptic ? ['p256', 'p384', 'p521', 'secp256k1', 'curve25519', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'] :
- ['p256', 'p384', 'p521', 'curve25519'];
+ const names = config.useIndutnyElliptic ? ['p256', 'p384', 'p521', 'secp256k1', 'curve25519Legacy', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'] :
+ ['p256', 'p384', 'p521', 'curve25519Legacy'];
return Promise.all(names.map(function (name) {
const curve = new elliptic_curves.CurveWithOID(name);
return curve.genKeyPair().then(keyPair => {
diff --git a/test/crypto/validate.js b/test/crypto/validate.js
index 9b9b883e5..ee4fa29e8 100644
--- a/test/crypto/validate.js
+++ b/test/crypto/validate.js
@@ -91,7 +91,7 @@ export default () => {
describe('EdDSA parameter validation (legacy format)', function() {
let eddsaKey;
before(async () => {
- eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' });
+ eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519Legacy' });
});
it('EdDSA params should be valid', async function() {
@@ -115,7 +115,7 @@ export default () => {
let ecdhKey;
let ecdsaKey;
before(async () => {
- eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' });
+ eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519Legacy' });
ecdhKey = eddsaKey.subkeys[0];
ecdsaKey = await generatePrivateKeyObject({ curve: 'p256' });
});
@@ -203,7 +203,7 @@ export default () => {
ecdsaKey = await generatePrivateKeyObject({ curve });
ecdhKey = ecdsaKey.subkeys[0];
} else {
- const eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' });
+ const eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519Legacy' });
ecdhKey = eddsaKey.subkeys[0];
}
});
diff --git a/test/general/config.js b/test/general/config.js
index 3da4c40ab..55120a306 100644
--- a/test/general/config.js
+++ b/test/general/config.js
@@ -299,7 +299,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
await expect(openpgp.encrypt({
message, encryptionKeys: [key], config: { rejectCurves: new Set([openpgp.enums.curve.curve25519Legacy]) }
- })).to.be.eventually.rejectedWith(/Support for ecdh keys using curve curve25519 is disabled/);
+ })).to.be.eventually.rejectedWith(/Support for ecdh keys using curve curve25519Legacy is disabled/);
const echdEncrypted = await openpgp.encrypt({
message, encryptionKeys: [key], config: { rejectCurves: new Set([openpgp.enums.curve.ed25519Legacy]) }
@@ -372,7 +372,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
})).to.be.eventually.rejectedWith(/eddsaLegacy keys are considered too weak/);
await expect(openpgp.sign({
message, signingKeys: [key], config: { rejectCurves: new Set([openpgp.enums.curve.ed25519Legacy]) }
- })).to.be.eventually.rejectedWith(/Support for eddsaLegacy keys using curve ed25519 is disabled/);
+ })).to.be.eventually.rejectedWith(/Support for eddsaLegacy keys using curve ed25519Legacy is disabled/);
});
it('openpgp.verify', async function() {
@@ -424,7 +424,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
config: { rejectCurves: new Set([openpgp.enums.curve.ed25519Legacy]) }
};
const { signatures: [sig5] } = await openpgp.verify(opt5);
- await expect(sig5.verified).to.be.eventually.rejectedWith(/Support for eddsaLegacy keys using curve ed25519 is disabled/);
+ await expect(sig5.verified).to.be.eventually.rejectedWith(/Support for eddsaLegacy keys using curve ed25519Legacy is disabled/);
});
describe('detects unknown config property', async function() {
diff --git a/test/general/key.js b/test/general/key.js
index 4ee961335..f1ee51a19 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -3510,7 +3510,7 @@ PzIEeL7UH3trraFmi+Gq8u4kAA==
});
it("validate() - don't throw if key parameters correspond", async function() {
- const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', format: 'object' });
+ const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519Legacy', format: 'object' });
await expect(key.validate()).to.not.be.rejected;
});
@@ -3536,7 +3536,7 @@ PzIEeL7UH3trraFmi+Gq8u4kAA==
it('isDecrypted() - should reflect whether all (sub)keys are encrypted', async function() {
const passphrase = '12345678';
- const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', passphrase, format: 'object' });
+ const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519Legacy', passphrase, format: 'object' });
expect(key.isDecrypted()).to.be.false;
await key.subkeys[0].keyPacket.decrypt(passphrase);
expect(key.isDecrypted()).to.be.true;
@@ -4252,7 +4252,7 @@ VYGdb3eNlV8CfoEC
expect(key.subkeys).to.have.length(0);
const newKey = await key.addSubkey();
expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
- expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
+ expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
});
it('Add a new default subkey to an Ed488 key', async function() {
@@ -4330,7 +4330,7 @@ FM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
-----END PGP PRIVATE KEY BLOCK-----` });
expect(v6Key.subkeys).to.have.length(1);
- await expect(v6Key.addSubkey({ type: 'ecc' })).to.be.rejectedWith(/Cannot generate v6 keys of type 'ecc' with curve curve25519/);
+ await expect(v6Key.addSubkey({ type: 'ecc' })).to.be.rejectedWith(/Cannot generate v6 keys of type 'ecc' with curve curve25519Legacy/);
expect(v6Key.subkeys).to.have.length(1);
});
@@ -4369,10 +4369,10 @@ I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
it('create and add a new eddsa subkey to a eddsa key', async function() {
const passphrase = '12345678';
const userID = { name: 'test', email: 'a@b.com' };
- const { privateKey } = await openpgp.generateKey({ curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] });
+ const { privateKey } = await openpgp.generateKey({ curve: 'curve25519Legacy', userIDs: [userID], format: 'object', subkeys:[] });
const total = privateKey.subkeys.length;
- let newPrivateKey = await privateKey.addSubkey({ curve: 'curve25519', userIDs: [userID], sign: true });
+ let newPrivateKey = await privateKey.addSubkey({ curve: 'curve25519Legacy', userIDs: [userID], sign: true });
const subkey1 = newPrivateKey.subkeys[total];
const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase });
newPrivateKey = await openpgp.decryptKey({
@@ -4393,14 +4393,14 @@ I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
it('create and add a new ecdsa subkey to a eddsa key', async function() {
const userID = { name: 'test', email: 'a@b.com' };
- const { privateKey } = await openpgp.generateKey({ curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] });
+ const { privateKey } = await openpgp.generateKey({ curve: 'ed25519Legacy', userIDs: [userID], format: 'object', subkeys:[] });
const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey({ curve: 'p256', sign: true });
newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() });
const subkey = newPrivateKey.subkeys[total];
expect(subkey).to.exist;
expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
- expect(newPrivateKey.getAlgorithmInfo().curve).to.be.equal('ed25519');
+ expect(newPrivateKey.getAlgorithmInfo().curve).to.be.equal('ed25519Legacy');
expect(subkey.getAlgorithmInfo().curve).to.be.equal('p256');
expect(newPrivateKey.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdsa');
@@ -4428,7 +4428,7 @@ I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
it('create and add a new rsa subkey to a ecc key', async function() {
const userID = { name: 'test', email: 'a@b.com' };
- const opt = { curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] };
+ const opt = { curve: 'ed25519Legacy', userIDs: [userID], format: 'object', subkeys:[] };
const { privateKey } = await openpgp.generateKey(opt);
const total = privateKey.subkeys.length;
let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index d59c4cd1f..008cc7133 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -1012,6 +1012,24 @@ export default () => describe('OpenPGP.js public api tests', function() {
});
describe('generateKey - unit tests', function() {
+ it('should still support curve="curve25519" for ECC key type (v4 key)', function() {
+ const opt = {
+ userIDs: { name: 'Test User', email: 'text@example.com' },
+ type: 'ecc',
+ curve: 'curve25519',
+ format: 'object'
+ };
+ return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
+ expect(key).to.exist;
+ expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
+ expect(key.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
+ expect(key.getAlgorithmInfo().curve).to.equal('ed25519Legacy');
+ expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
+ expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
+ });
+ });
+
it('should have default params set (v4 key)', function() {
const now = util.normalizeDate(new Date());
const opt = {
@@ -1028,12 +1046,12 @@ export default () => describe('OpenPGP.js public api tests', function() {
expect(key.users[0].userID.name).to.equal('Test User');
expect(key.users[0].userID.email).to.equal('text@example.com');
expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
- expect(key.getAlgorithmInfo().curve).to.equal('ed25519');
+ expect(key.getAlgorithmInfo().curve).to.equal('ed25519Legacy');
expect(+key.getCreationTime()).to.equal(+now);
expect(await key.getExpirationTime()).to.equal(Infinity);
expect(key.subkeys.length).to.equal(1);
expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
- expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
+ expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
expect(+key.subkeys[0].getCreationTime()).to.equal(+now);
expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity);
}
@@ -4777,7 +4795,7 @@ sEj+v9LKoMTYZGMfp3qDVFLtkBE88eVmVjgJOoLhrsv7yh0PAA==
});
describe('Sign and verify with each curve', function() {
- const curves = ['secp256k1' , 'p256', 'p384', 'p521', 'curve25519', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
+ const curves = ['secp256k1' , 'p256', 'p384', 'p521', 'curve25519Legacy', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
curves.forEach(curve => {
it(`sign/verify with ${curve}`, async function() {
const config = { rejectCurves: new Set() };
diff --git a/test/general/x25519.js b/test/general/x25519.js
index f197c595f..93bc8c26b 100644
--- a/test/general/x25519.js
+++ b/test/general/x25519.js
@@ -219,7 +219,7 @@ export default () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cryp
describe('Ed25519 Test Vectors from RFC8032', function () {
// https://tools.ietf.org/html/rfc8032#section-7.1
function testVector(vector) {
- const curve = new elliptic.CurveWithOID('ed25519');
+ const curve = new elliptic.CurveWithOID(openpgp.enums.curve.ed25519Legacy);
const { publicKey } = nacl.sign.keyPair.fromSeed(util.hexToUint8Array(vector.SECRET_KEY));
expect(publicKey).to.deep.equal(util.hexToUint8Array(vector.PUBLIC_KEY));
const data = vector.MESSAGE;
@@ -382,7 +382,7 @@ function omnibus() {
it('Omnibus Ed25519/Curve25519 Test', function() {
const options = {
userIDs: { name: 'Hi', email: 'hi@hel.lo' },
- curve: 'ed25519',
+ curve: 'ed25519Legacy',
format: 'object'
};
return openpgp.generateKey(options).then(async function({ privateKey, publicKey }) {
@@ -395,10 +395,10 @@ function omnibus() {
const hi = privateKey;
const primaryKey = hi.keyPacket;
const subkey = hi.subkeys[0];
- expect(hi.getAlgorithmInfo().curve).to.equal('ed25519');
expect(hi.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
- expect(subkey.getAlgorithmInfo().curve).to.equal('curve25519');
+ expect(hi.getAlgorithmInfo().curve).to.equal('ed25519Legacy');
expect(subkey.getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(subkey.getAlgorithmInfo().curve).to.equal('curve25519Legacy');
// Verify that self Certificate is valid
const user = hi.users[0];
@@ -410,15 +410,15 @@ function omnibus() {
const options = {
userIDs: { name: 'Bye', email: 'bye@good.bye' },
- curve: 'curve25519',
+ curve: 'curve25519Legacy',
format: 'object'
};
return openpgp.generateKey(options).then(async function({ privateKey: bye }) {
- expect(bye.getAlgorithmInfo().curve).to.equal('ed25519');
expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
- expect(bye.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
+ expect(bye.getAlgorithmInfo().curve).to.equal('ed25519Legacy');
expect(bye.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
+ expect(bye.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
// Verify that self Certificate is valid
const user = bye.users[0];
From a9fae5ff12bf96f5f232eea05e702abe65121034 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Fri, 6 Oct 2023 16:14:59 +0200
Subject: [PATCH 073/224] Replace indutny-elliptic lib with noble-curves
Unlike elliptic, noble-curves targets algorithmic constant time, and
it relies on the native BigInts when available, resulting in a smaller bundle
and improved performance.
Also, expand testing of fallback elliptic implementation.
---
package-lock.json | 97 ------------
package.json | 1 -
src/crypto/public_key/elliptic/ecdh.js | 71 ++++-----
src/crypto/public_key/elliptic/ecdsa.js | 35 ++---
src/crypto/public_key/elliptic/indutnyKey.js | 44 ------
src/crypto/public_key/elliptic/oid_curves.js | 103 +++++++------
test/crypto/ecdh.js | 27 ++--
test/crypto/elliptic.js | 153 +++++++++----------
test/crypto/elliptic_data.js | 14 ++
test/general/brainpool.js | 4 -
10 files changed, 204 insertions(+), 345 deletions(-)
delete mode 100644 src/crypto/public_key/elliptic/indutnyKey.js
diff --git a/package-lock.json b/package-lock.json
index a12641177..0c0cc0511 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,6 @@
},
"devDependencies": {
"@openpgp/asmcrypto.js": "^3.0.0",
- "@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
"@openpgp/noble-curves": "^1.2.1-0",
"@openpgp/noble-hashes": "^1.3.3-0",
@@ -572,21 +571,6 @@
"integrity": "sha512-X/DPYy7uHe+dlY2Botb99uXwb2kXR6HTv0hQOnnI0TVEqOIMQyzCDWAzlX00AacsYryDAphuOndg6mk6wtJCNg==",
"dev": true
},
- "node_modules/@openpgp/elliptic": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@openpgp/elliptic/-/elliptic-6.5.1.tgz",
- "integrity": "sha512-VR20QWndMXoZTAzCUqauDT4dLrHO4RTnyVV3szuRHllQSU/JZToLvWtFxpEQth4XWyqlxHPwq7tljE5V97+n1g==",
- "dev": true,
- "dependencies": {
- "bn.js": "^4.4.0",
- "brorand": "^1.0.1",
- "hash.js": "^1.0.0",
- "hmac-drbg": "^1.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.0"
- }
- },
"node_modules/@openpgp/jsdoc": {
"version": "3.6.11",
"resolved": "https://registry.npmjs.org/@openpgp/jsdoc/-/jsdoc-3.6.11.tgz",
@@ -1489,12 +1473,6 @@
"node": ">=8"
}
},
- "node_modules/brorand": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
- "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
- "dev": true
- },
"node_modules/browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
@@ -3465,16 +3443,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/hash.js": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
- "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "minimalistic-assert": "^1.0.0"
- }
- },
"node_modules/hasha": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz",
@@ -3496,17 +3464,6 @@
"he": "bin/he"
}
},
- "node_modules/hmac-drbg": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
- "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
- "dev": true,
- "dependencies": {
- "hash.js": "^1.0.3",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.1"
- }
- },
"node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
@@ -4975,12 +4932,6 @@
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
"integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M="
},
- "node_modules/minimalistic-crypto-utils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
- "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
- "dev": true
- },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -7993,21 +7944,6 @@
"integrity": "sha512-X/DPYy7uHe+dlY2Botb99uXwb2kXR6HTv0hQOnnI0TVEqOIMQyzCDWAzlX00AacsYryDAphuOndg6mk6wtJCNg==",
"dev": true
},
- "@openpgp/elliptic": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@openpgp/elliptic/-/elliptic-6.5.1.tgz",
- "integrity": "sha512-VR20QWndMXoZTAzCUqauDT4dLrHO4RTnyVV3szuRHllQSU/JZToLvWtFxpEQth4XWyqlxHPwq7tljE5V97+n1g==",
- "dev": true,
- "requires": {
- "bn.js": "^4.4.0",
- "brorand": "^1.0.1",
- "hash.js": "^1.0.0",
- "hmac-drbg": "^1.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.0"
- }
- },
"@openpgp/jsdoc": {
"version": "3.6.11",
"resolved": "https://registry.npmjs.org/@openpgp/jsdoc/-/jsdoc-3.6.11.tgz",
@@ -8699,12 +8635,6 @@
"fill-range": "^7.0.1"
}
},
- "brorand": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
- "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
- "dev": true
- },
"browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
@@ -10238,16 +10168,6 @@
"has-symbols": "^1.0.2"
}
},
- "hash.js": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
- "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "minimalistic-assert": "^1.0.0"
- }
- },
"hasha": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz",
@@ -10263,17 +10183,6 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
- "hmac-drbg": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
- "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
- "dev": true,
- "requires": {
- "hash.js": "^1.0.3",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.1"
- }
- },
"hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
@@ -11425,12 +11334,6 @@
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
"integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M="
},
- "minimalistic-crypto-utils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
- "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
- "dev": true
- },
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
diff --git a/package.json b/package.json
index c8b4f351b..90cd63461 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,6 @@
"devDependencies": {
"@openpgp/asmcrypto.js": "^3.0.0",
"@openpgp/noble-curves": "^1.2.1-0",
- "@openpgp/elliptic": "^6.5.1",
"@openpgp/jsdoc": "^3.6.11",
"@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git",
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index 370019165..ed370578d 100644
--- a/src/crypto/public_key/elliptic/ecdh.js
+++ b/src/crypto/public_key/elliptic/ecdh.js
@@ -21,7 +21,7 @@
*/
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
-import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams } from './oid_curves';
+import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
import hash from '../../hash';
@@ -29,7 +29,6 @@ import enums from '../../../enums';
import util from '../../../util';
import { b64ToUint8Array } from '../../../encoding/base64';
import * as pkcs5 from '../../pkcs5';
-import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey';
import getCipher from '../../cipher/getCipher';
const webCrypto = util.getWebCrypto();
@@ -105,13 +104,16 @@ async function genPublicEphemeralKey(curve, Q) {
return await webPublicEphemeralKey(curve, Q);
} catch (err) {
util.printDebugError(err);
+ return jsPublicEphemeralKey(curve, Q);
}
}
break;
case 'node':
return nodePublicEphemeralKey(curve, Q);
+ default: {
+ return jsPublicEphemeralKey(curve, Q);
+ }
}
- return ellipticPublicEphemeralKey(curve, Q);
}
/**
@@ -165,13 +167,16 @@ async function genPrivateEphemeralKey(curve, V, Q, d) {
return await webPrivateEphemeralKey(curve, V, Q, d);
} catch (err) {
util.printDebugError(err);
+ return jsPrivateEphemeralKey(curve, V, d);
}
}
break;
case 'node':
return nodePrivateEphemeralKey(curve, V, d);
+ default: {
+ return jsPrivateEphemeralKey(curve, V, d);
+ }
}
- return ellipticPrivateEphemeralKey(curve, V, d);
}
/**
@@ -205,6 +210,24 @@ export async function decrypt(oid, kdfParams, V, C, Q, d, fingerprint) {
throw err;
}
+function jsPrivateEphemeralKey(curve, V, d) {
+ const nobleCurve = getNobleCurve(curve.name);
+ // The output includes parity byte
+ const sharedSecretWithParity = nobleCurve.getSharedSecret(d, V);
+ const sharedKey = sharedSecretWithParity.subarray(1);
+ return { secretKey: d, sharedKey };
+}
+
+async function jsPublicEphemeralKey(curve, Q) {
+ const nobleCurve = getNobleCurve(curve.name);
+ const { publicKey: V, privateKey: v } = await curve.genKeyPair();
+
+ // The output includes parity byte
+ const sharedSecretWithParity = nobleCurve.getSharedSecret(v, Q);
+ const sharedKey = sharedSecretWithParity.subarray(1);
+ return { publicKey: V, sharedKey };
+}
+
/**
* Generate ECDHE secret from private key and public part of ephemeral key using webCrypto
*
@@ -306,46 +329,6 @@ async function webPublicEphemeralKey(curve, Q) {
return { publicKey, sharedKey };
}
-/**
- * Generate ECDHE secret from private key and public part of ephemeral key using indutny/elliptic
- *
- * @param {CurveWithOID} curve - Elliptic curve object
- * @param {Uint8Array} V - Public part of ephemeral key
- * @param {Uint8Array} d - Recipient private key
- * @returns {Promise<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
- * @async
- */
-async function ellipticPrivateEphemeralKey(curve, V, d) {
- const indutnyCurve = await getIndutnyCurve(curve.name);
- V = keyFromPublic(indutnyCurve, V);
- d = keyFromPrivate(indutnyCurve, d);
- const secretKey = new Uint8Array(d.getPrivate());
- const S = d.derive(V.getPublic());
- const len = indutnyCurve.curve.p.byteLength();
- const sharedKey = S.toArrayLike(Uint8Array, 'be', len);
- return { secretKey, sharedKey };
-}
-
-/**
- * Generate ECDHE ephemeral key and secret from public key using indutny/elliptic
- *
- * @param {CurveWithOID} curve - Elliptic curve object
- * @param {Uint8Array} Q - Recipient public key
- * @returns {Promise<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
- * @async
- */
-async function ellipticPublicEphemeralKey(curve, Q) {
- const indutnyCurve = await getIndutnyCurve(curve.name);
- const v = await curve.genKeyPair();
- Q = keyFromPublic(indutnyCurve, Q);
- const V = keyFromPrivate(indutnyCurve, v.privateKey);
- const publicKey = v.publicKey;
- const S = V.derive(Q.getPublic());
- const len = indutnyCurve.curve.p.byteLength();
- const sharedKey = S.toArrayLike(Uint8Array, 'be', len);
- return { publicKey, sharedKey };
-}
-
/**
* Generate ECDHE secret from private key and public part of ephemeral key using nodeCrypto
*
diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js
index 19412aa10..d000bf017 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -24,8 +24,7 @@ import enums from '../../../enums';
import util from '../../../util';
import { getRandomBytes } from '../../random';
import hash from '../../hash';
-import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams } from './oid_curves';
-import { getIndutnyCurve, keyFromPrivate, keyFromPublic } from './indutnyKey';
+import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
@@ -74,7 +73,14 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
}
}
}
- return ellipticSign(curve, hashed, privateKey);
+
+ const nobleCurve = getNobleCurve(curve.name);
+ // lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
+ const signature = nobleCurve.sign(hashed, privateKey, { lowS: false });
+ return {
+ r: signature.r.toUint8Array('be', curve.payloadSize),
+ s: signature.s.toUint8Array('be', curve.payloadSize)
+ };
}
/**
@@ -111,8 +117,10 @@ export async function verify(oid, hashAlgo, signature, message, publicKey, hashe
return nodeVerify(curve, hashAlgo, signature, message, publicKey);
}
}
- const digest = (typeof hashAlgo === 'undefined') ? message : hashed;
- return ellipticVerify(curve, signature, digest, publicKey);
+
+ const nobleCurve = getNobleCurve(curve.name);
+ // lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
+ return nobleCurve.verify(util.concatUint8Array([signature.r, signature.s]), hashed, publicKey, { lowS: false });
}
/**
@@ -156,23 +164,6 @@ export async function validateParams(oid, Q, d) {
// Helper functions //
// //
//////////////////////////
-
-async function ellipticSign(curve, hashed, privateKey) {
- const indutnyCurve = await getIndutnyCurve(curve.name);
- const key = keyFromPrivate(indutnyCurve, privateKey);
- const signature = key.sign(hashed);
- return {
- r: signature.r.toArrayLike(Uint8Array),
- s: signature.s.toArrayLike(Uint8Array)
- };
-}
-
-async function ellipticVerify(curve, signature, digest, publicKey) {
- const indutnyCurve = await getIndutnyCurve(curve.name);
- const key = keyFromPublic(indutnyCurve, publicKey);
- return key.verify(digest, signature);
-}
-
async function webSign(curve, hashAlgo, message, keyPair) {
const len = curve.payloadSize;
const jwk = privateToJWK(curve.payloadSize, webCurves[curve.name], keyPair.publicKey, keyPair.privateKey);
diff --git a/src/crypto/public_key/elliptic/indutnyKey.js b/src/crypto/public_key/elliptic/indutnyKey.js
deleted file mode 100644
index ddfc6aa79..000000000
--- a/src/crypto/public_key/elliptic/indutnyKey.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// OpenPGP.js - An OpenPGP implementation in javascript
-// Copyright (C) 2015-2016 Decentral
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 3.0 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-/**
- * @fileoverview Wrapper for a KeyPair of an curve from indutny/elliptic library
- * @module crypto/public_key/elliptic/indutnyKey
- */
-
-import config from '../../../config';
-
-export function keyFromPrivate(indutnyCurve, priv) {
- const keyPair = indutnyCurve.keyPair({ priv: priv });
- return keyPair;
-}
-
-export function keyFromPublic(indutnyCurve, pub) {
- const keyPair = indutnyCurve.keyPair({ pub: pub });
- if (keyPair.validate().result !== true) {
- throw new Error('Invalid elliptic public key');
- }
- return keyPair;
-}
-
-export async function getIndutnyCurve(name) {
- if (!config.useIndutnyElliptic) {
- throw new Error('This curve is only supported in the full build of OpenPGP.js');
- }
- const { default: elliptic } = await import('@openpgp/elliptic');
- return new elliptic.ec(name);
-}
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index 4d40e25b3..d6561d5ad 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -19,37 +19,58 @@
* @fileoverview Wrapper of an instance of an Elliptic Curve
* @module crypto/public_key/elliptic/curve
*/
-import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import nacl from '@openpgp/tweetnacl/nacl-fast-light';
+import { p256 } from '@openpgp/noble-curves/p256';
+import { p384 } from '@openpgp/noble-curves/p384';
+import { p521 } from '@openpgp/noble-curves/p521';
+import { brainpoolP256r1 } from '@openpgp/noble-curves/brainpoolP256r1';
+import { brainpoolP384r1 } from '@openpgp/noble-curves/brainpoolP384r1';
+import { brainpoolP512r1 } from '@openpgp/noble-curves/brainpoolP512r1';
+import { secp256k1 } from '@openpgp/noble-curves/secp256k1';
import { getRandomBytes } from '../../random';
import enums from '../../../enums';
import util from '../../../util';
import { uint8ArrayToB64, b64ToUint8Array } from '../../../encoding/base64';
import OID from '../../../type/oid';
-import { keyFromPublic, keyFromPrivate, getIndutnyCurve } from './indutnyKey';
import { UnsupportedError } from '../../../packet/packet';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
const webCurves = {
- 'p256': 'P-256',
- 'p384': 'P-384',
- 'p521': 'P-521'
+ [enums.curve.p256]: 'P-256',
+ [enums.curve.p384]: 'P-384',
+ [enums.curve.p521]: 'P-521'
};
const knownCurves = nodeCrypto ? nodeCrypto.getCurves() : [];
const nodeCurves = nodeCrypto ? {
- secp256k1: knownCurves.includes('secp256k1') ? 'secp256k1' : undefined,
- p256: knownCurves.includes('prime256v1') ? 'prime256v1' : undefined,
- p384: knownCurves.includes('secp384r1') ? 'secp384r1' : undefined,
- p521: knownCurves.includes('secp521r1') ? 'secp521r1' : undefined,
- ed25519: knownCurves.includes('ED25519') ? 'ED25519' : undefined,
- curve25519: knownCurves.includes('X25519') ? 'X25519' : undefined,
- brainpoolP256r1: knownCurves.includes('brainpoolP256r1') ? 'brainpoolP256r1' : undefined,
- brainpoolP384r1: knownCurves.includes('brainpoolP384r1') ? 'brainpoolP384r1' : undefined,
- brainpoolP512r1: knownCurves.includes('brainpoolP512r1') ? 'brainpoolP512r1' : undefined
+ [enums.curve.secp256k1]: knownCurves.includes('secp256k1') ? 'secp256k1' : undefined,
+ [enums.curve.p256]: knownCurves.includes('prime256v1') ? 'prime256v1' : undefined,
+ [enums.curve.p384]: knownCurves.includes('secp384r1') ? 'secp384r1' : undefined,
+ [enums.curve.p521]: knownCurves.includes('secp521r1') ? 'secp521r1' : undefined,
+ [enums.curve.ed25519Legacy]: knownCurves.includes('ED25519') ? 'ED25519' : undefined,
+ [enums.curve.curve25519Legacy]: knownCurves.includes('X25519') ? 'X25519' : undefined,
+ [enums.curve.brainpoolP256r1]: knownCurves.includes('brainpoolP256r1') ? 'brainpoolP256r1' : undefined,
+ [enums.curve.brainpoolP384r1]: knownCurves.includes('brainpoolP384r1') ? 'brainpoolP384r1' : undefined,
+ [enums.curve.brainpoolP512r1]: knownCurves.includes('brainpoolP512r1') ? 'brainpoolP512r1' : undefined
} : {};
+const nobleCurvess = {
+ [enums.curve.p256]: p256,
+ [enums.curve.p384]: p384,
+ [enums.curve.p521]: p521,
+ [enums.curve.secp256k1]: secp256k1,
+ [enums.curve.brainpoolP256r1]: brainpoolP256r1,
+ [enums.curve.brainpoolP384r1]: brainpoolP384r1,
+ [enums.curve.brainpoolP512r1]: brainpoolP512r1
+};
+export const getNobleCurve = curveName => {
+ const curve = nobleCurvess[curveName];
+ if (!curve) throw new Error('Unsupported curve');
+ return curve;
+};
+
+
const curves = {
p256: {
oid: [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
@@ -169,14 +190,13 @@ class CurveWithOID {
}
async genKeyPair() {
- let keyPair;
switch (this.type) {
case 'web':
try {
return await webGenKeyPair(this.name);
} catch (err) {
util.printDebugError('Browser did not support generating ec key ' + err.message);
- break;
+ return jsGenKeyPair(this.name);
}
case 'node':
return nodeGenKeyPair(this.name);
@@ -185,8 +205,8 @@ class CurveWithOID {
privateKey[0] = (privateKey[0] & 127) | 64;
privateKey[31] &= 248;
const secretKey = privateKey.slice().reverse();
- keyPair = nacl.box.keyPair.fromSecretKey(secretKey);
- const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
+ const { publicKey: rawPublicKey } = nacl.box.keyPair.fromSecretKey(secretKey);
+ const publicKey = util.concatUint8Array([new Uint8Array([0x40]), rawPublicKey]);
return { publicKey, privateKey };
}
case 'ed25519Legacy': {
@@ -195,26 +215,23 @@ class CurveWithOID {
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
return { publicKey, privateKey };
}
+ default: {
+ return jsGenKeyPair(this.name);
+ }
}
- const indutnyCurve = await getIndutnyCurve(this.name);
- keyPair = await indutnyCurve.genKeyPair({
- entropy: util.uint8ArrayToString(getRandomBytes(32))
- });
- return { publicKey: new Uint8Array(keyPair.getPublic('array', false)), privateKey: keyPair.getPrivate().toArrayLike(Uint8Array) };
}
}
-async function generate(curve) {
- curve = new CurveWithOID(curve);
+async function generate(curveName) {
+ const curve = new CurveWithOID(curveName);
+ const { oid, hash, cipher } = curve;
const keyPair = await curve.genKeyPair();
- const Q = BigInteger.new(keyPair.publicKey).toUint8Array();
- const secret = BigInteger.new(keyPair.privateKey).toUint8Array('be', curve.payloadSize);
return {
- oid: curve.oid,
- Q,
- secret,
- hash: curve.hash,
- cipher: curve.cipher
+ oid,
+ Q: keyPair.publicKey,
+ secret: util.leftPad(keyPair.privateKey, curve.payloadSize),
+ hash,
+ cipher
};
}
@@ -269,20 +286,13 @@ async function validateStandardParams(algo, oid, Q, d) {
return true;
}
- const curve = await getIndutnyCurve(curveName);
- try {
- // Parse Q and check that it is on the curve but not at infinity
- Q = keyFromPublic(curve, Q).getPublic();
- } catch (validationErrors) {
- return false;
- }
-
- /**
+ const nobleCurve = getNobleCurve(enums.write(enums.curve, oid.toHex()));
+ /*
* Re-derive public point Q' = dG from private key
* Expect Q == Q'
*/
- const dG = keyFromPrivate(curve, d).getPublic();
- if (!dG.eq(Q)) {
+ const dG = nobleCurve.getPublicKey(d, false);
+ if (!util.equalsUint8Array(dG, Q)) {
return false;
}
@@ -298,7 +308,12 @@ export {
// Helper functions //
// //
//////////////////////////
-
+function jsGenKeyPair(name) {
+ const nobleCurve = getNobleCurve(name);
+ const privateKey = nobleCurve.utils.randomPrivateKey();
+ const publicKey = nobleCurve.getPublicKey(privateKey, false);
+ return { publicKey, privateKey };
+}
async function webGenKeyPair(name) {
// Note: keys generated with ECDSA and ECDH are structurally equivalent
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index 85eba9faf..c3b4536f9 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -77,7 +77,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
}
expect(decrypt_message(
'secp256k1', 2, 7, [], [], [], [], []
- )).to.be.rejectedWith(Error, /Private key is not valid for specified curve|Unknown point format/).notify(done);
+ )).to.be.rejectedWith(Error, /Private key is not valid for specified curve|second arg must be public key/).notify(done);
});
it('Invalid elliptic public key', function (done) {
if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
@@ -85,7 +85,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
}
expect(decrypt_message(
'secp256k1', 2, 7, secp256k1_value, secp256k1_point, secp256k1_invalid_point, secp256k1_data, []
- )).to.be.rejectedWith(Error, /Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|Invalid elliptic public key/).notify(done);
+ )).to.be.rejectedWith(/Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|bad point/).notify(done);
});
it('Invalid key data integrity', function (done) {
if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
@@ -93,7 +93,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
}
expect(decrypt_message(
'secp256k1', 2, 7, secp256k1_value, secp256k1_point, secp256k1_point, secp256k1_data, []
- )).to.be.rejectedWith(Error, /Key Data Integrity failed/).notify(done);
+ )).to.be.rejectedWith(/Key Data Integrity failed/).notify(done);
});
const Q1 = new Uint8Array([
@@ -143,9 +143,9 @@ export default () => describe('ECDH key exchange @lightweight', function () {
const oid = new OID(curve.oid);
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
const data = util.stringToUint8Array('test');
- expect(
- ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1)
- ).to.be.rejectedWith(Error, /Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|Unknown point format/);
+ await expect(
+ ecdh.encrypt(oid, kdfParams, data, Q1.subarray(1), fingerprint1)
+ ).to.be.rejectedWith(/Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|second arg must be public key/);
});
it('Different keys', async function () {
@@ -199,8 +199,9 @@ export default () => describe('ECDH key exchange @lightweight', function () {
expect(await ecdhX.decrypt(openpgp.enums.publicKey.x448, ephemeralPublicKey, wrappedKey, K_B, b)).to.deep.equal(data);
});
- ['p256', 'p384', 'p521'].forEach(curveName => {
- it(`NIST ${curveName} - Successful exchange`, async function () {
+ const allCurves = ['secp256k1', 'p256', 'p384', 'p521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
+ allCurves.forEach(curveName => {
+ it(`${curveName} - Successful exchange`, async function () {
const curve = new elliptic_curves.CurveWithOID(curveName);
const oid = new OID(curve.oid);
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
@@ -236,14 +237,16 @@ export default () => describe('ECDH key exchange @lightweight', function () {
getNodeCryptoStub && getNodeCryptoStub.restore();
};
- ['p256', 'p384', 'p521'].forEach(curveName => {
- it(`NIST ${curveName}`, async function () {
+ allCurves.forEach(curveName => {
+ it(`${curveName}`, async function () {
const nodeCrypto = util.getNodeCrypto();
const webCrypto = util.getWebCrypto();
if (!nodeCrypto && !webCrypto) {
this.skip();
}
+ const expectNativeWeb = new Set(['p256', 'p384']); // older versions of safari do not implement p521
+
const curve = new elliptic_curves.CurveWithOID(curveName);
const oid = new OID(curve.oid);
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
@@ -254,9 +257,11 @@ export default () => describe('ECDH key exchange @lightweight', function () {
const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'deriveBits') : sinonSandbox.spy(nodeCrypto, 'createECDH');
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
+ const expectedNativeCallCount = nativeDecryptSpy.callCount;
disableNative();
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
- if (curveName !== 'p521') { // safari does not implement p521 in webcrypto
+ expect(nativeDecryptSpy.callCount).to.equal(expectedNativeCallCount); // assert that fallback implementation was called
+ if (expectNativeWeb.has(curveName)) {
expect(nativeDecryptSpy.calledOnce).to.be.true;
}
});
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index 048413fdf..a434c5430 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -122,6 +122,21 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
getNodeCryptoStub && getNodeCryptoStub.restore();
};
+ const testNativeAndFallback = async fn => {
+ const webCrypto = util.getWebCrypto();
+ const nodeCrypto = util.getNodeCrypto();
+ const nativeSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'importKey') : sinonSandbox.spy(nodeCrypto, 'createVerify'); // spy on function used on verification, since that's used by all tests calling `testNativeAndFallback`
+
+ // if native not available, fallback will be tested twice (not possible to automatically check native algo availability)
+ enableNative();
+ await fn();
+ const expectedNativeCallCount = nativeSpy.callCount;
+ disableNative();
+ await fn();
+ expect(nativeSpy.callCount).to.equal(expectedNativeCallCount);
+ enableNative();
+ };
+
const verify_signature = async function (oid, hash, r, s, message, pub) {
if (util.isString(message)) {
message = util.stringToUint8Array(message);
@@ -162,99 +177,81 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]);
- it('Invalid curve oid', function () {
- return Promise.all([
- expect(verify_signature(
- 'invalid oid', 8, [], [], [], []
- )).to.be.rejectedWith(Error, /Unknown curve/),
- expect(verify_signature(
- '\x00', 8, [], [], [], []
- )).to.be.rejectedWith(Error, /Unknown curve/)
- ]);
+ it('Invalid curve oid', async function () {
+ await expect(verify_signature(
+ 'invalid oid', 8, [], [], [], []
+ )).to.be.rejectedWith(Error, /Unknown curve/);
+ await expect(verify_signature(
+ '\x00', 8, [], [], [], []
+ )).to.be.rejectedWith(Error, /Unknown curve/);
});
- it('Invalid public key', async function () {
+ it('secp256k1 - Invalid public key', async function () {
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
- this.skip(); // webcrypto does not implement secp256k1
- }
- if (util.getNodeCrypto()) {
- await expect(verify_signature(
- 'secp256k1', 8, [], [], [], []
- )).to.eventually.be.false;
- await expect(verify_signature(
- 'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
- )).to.eventually.be.false;
- }
- if (config.useIndutnyElliptic) {
- disableNative();
- await expect(verify_signature(
- 'secp256k1', 8, [], [], [], []
- )).to.be.rejectedWith(Error, /Unknown point format/);
- await expect(verify_signature(
- 'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
- )).to.be.rejectedWith(Error, /Unknown point format/);
+ this.skip(); // webcrypto does not implement secp256k1: JS fallback tested instead
}
+ await expect(verify_signature(
+ 'secp256k1', 8, [], [], [], []
+ )).to.eventually.be.false;
+ await expect(verify_signature(
+ 'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
+ )).to.eventually.be.false;
});
- it('Invalid point', async function () {
+ it('secp256k1 - Invalid point', async function () {
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
- this.skip();
- }
- if (util.getNodeCrypto()) {
- await expect(verify_signature(
- 'secp256k1', 8, [], [], [], secp256k1_invalid_point
- )).to.eventually.be.false;
- }
- if (config.useIndutnyElliptic) {
- disableNative();
- await expect(verify_signature(
- 'secp256k1', 8, [], [], [], secp256k1_invalid_point
- )).to.be.rejectedWith(Error, /Invalid elliptic public key/);
+ this.skip(); // webcrypto does not implement secp256k1: JS fallback tested instead
}
+ await expect(verify_signature(
+ 'secp256k1', 8, [], [], [], secp256k1_invalid_point
+ )).to.eventually.be.false;
});
- it('Invalid signature', function (done) {
+ it('secp256k1 - Invalid signature', function (done) {
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
- this.skip();
+ this.skip(); // webcrypto does not implement secp256k1: JS fallback tested instead
}
expect(verify_signature(
'secp256k1', 8, [], [], [], secp256k1_point
)).to.eventually.be.false.notify(done);
});
- const p384_message = new Uint8Array([
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
- ]);
- const p384_r = new Uint8Array([
- 0x9D, 0x07, 0xCA, 0xA5, 0x9F, 0xBE, 0xB8, 0x76,
- 0xA9, 0xB9, 0x66, 0x0F, 0xA0, 0x64, 0x70, 0x5D,
- 0xE6, 0x37, 0x40, 0x43, 0xD0, 0x8E, 0x40, 0xA8,
- 0x8B, 0x37, 0x83, 0xE7, 0xBC, 0x1C, 0x4C, 0x86,
- 0xCB, 0x3C, 0xD5, 0x9B, 0x68, 0xF0, 0x65, 0xEB,
- 0x3A, 0xB6, 0xD6, 0xA6, 0xCF, 0x85, 0x3D, 0xA9
- ]);
- const p384_s = new Uint8Array([
- 0x32, 0x85, 0x78, 0xCC, 0xEA, 0xC5, 0x22, 0x83,
- 0x10, 0x73, 0x1C, 0xCF, 0x10, 0x8A, 0x52, 0x11,
- 0x8E, 0x49, 0x9E, 0xCF, 0x7E, 0x17, 0x18, 0xC3,
- 0x11, 0x11, 0xBC, 0x0F, 0x6D, 0x98, 0xE2, 0x16,
- 0x68, 0x58, 0x23, 0x1D, 0x11, 0xEF, 0x3D, 0x21,
- 0x30, 0x75, 0x24, 0x39, 0x48, 0x89, 0x03, 0xDC
- ]);
- it('Valid signature', function (done) {
- expect(verify_signature('p384', 8, p384_r, p384_s, p384_message, key_data.p384.pub))
- .to.eventually.be.true.notify(done);
+ it('P-384 - Valid signature', async function () {
+ const p384_r = new Uint8Array([
+ 0x9D, 0x07, 0xCA, 0xA5, 0x9F, 0xBE, 0xB8, 0x76,
+ 0xA9, 0xB9, 0x66, 0x0F, 0xA0, 0x64, 0x70, 0x5D,
+ 0xE6, 0x37, 0x40, 0x43, 0xD0, 0x8E, 0x40, 0xA8,
+ 0x8B, 0x37, 0x83, 0xE7, 0xBC, 0x1C, 0x4C, 0x86,
+ 0xCB, 0x3C, 0xD5, 0x9B, 0x68, 0xF0, 0x65, 0xEB,
+ 0x3A, 0xB6, 0xD6, 0xA6, 0xCF, 0x85, 0x3D, 0xA9
+ ]);
+ const p384_s = new Uint8Array([
+ 0x32, 0x85, 0x78, 0xCC, 0xEA, 0xC5, 0x22, 0x83,
+ 0x10, 0x73, 0x1C, 0xCF, 0x10, 0x8A, 0x52, 0x11,
+ 0x8E, 0x49, 0x9E, 0xCF, 0x7E, 0x17, 0x18, 0xC3,
+ 0x11, 0x11, 0xBC, 0x0F, 0x6D, 0x98, 0xE2, 0x16,
+ 0x68, 0x58, 0x23, 0x1D, 0x11, 0xEF, 0x3D, 0x21,
+ 0x30, 0x75, 0x24, 0x39, 0x48, 0x89, 0x03, 0xDC
+ ]);
+ const p384_message = new Uint8Array([
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
+ ]);
+
+ await testNativeAndFallback(
+ () => expect(verify_signature('p384', 8, p384_r, p384_s, p384_message, key_data.p384.pub)).to.eventually.be.true
+ );
});
- it('Sign and verify message', function () {
- const curve = new elliptic_curves.CurveWithOID('p521');
- return curve.genKeyPair().then(async keyPair => {
- const keyPublic = new Uint8Array(keyPair.publicKey);
- const keyPrivate = new Uint8Array(keyPair.privateKey);
- const oid = curve.oid;
- const message = p384_message;
- return elliptic_curves.ecdsa.sign(oid, 10, message, keyPublic, keyPrivate, await hashMod.digest(10, message)).then(async signature => {
- await expect(elliptic_curves.ecdsa.verify(oid, 10, signature, message, keyPublic, await hashMod.digest(10, message)))
- .to.eventually.be.true;
- });
+ const curves = ['secp256k1' , 'p256', 'p384', 'p521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
+ curves.forEach(curveName => it(`${curveName} - Sign and verify message`, async function () {
+ const curve = new elliptic_curves.CurveWithOID(curveName);
+ const { publicKey: keyPublic, privateKey: keyPrivate } = await curve.genKeyPair();
+ const message = new Uint8Array([
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
+ ]);
+ const messageDigest = await hashMod.digest(openpgp.enums.hash.sha512, message);
+ await testNativeAndFallback(async () => {
+ const signature = await elliptic_curves.ecdsa.sign(curve.oid, openpgp.enums.hash.sha512, message, keyPublic, keyPrivate, messageDigest);
+ await expect(elliptic_curves.ecdsa.verify(curve.oid, openpgp.enums.hash.sha512, signature, message, keyPublic, messageDigest)).to.eventually.be.true;
});
- });
+ }));
});
});
diff --git a/test/crypto/elliptic_data.js b/test/crypto/elliptic_data.js
index 61eba7d97..1fbc64d04 100644
--- a/test/crypto/elliptic_data.js
+++ b/test/crypto/elliptic_data.js
@@ -1,3 +1,5 @@
+import util from '../../src/util.js';
+
const elliptic_data = {
key_data: {
p256: {
@@ -95,6 +97,18 @@ const elliptic_data = {
0xB8, 0xFD, 0x0B, 0xDF, 0x76, 0xCE, 0xBC, 0x95,
0x4B, 0x92, 0x26, 0xFC, 0xAA, 0x7A, 0x7C, 0x3F
])
+ },
+ brainpoolP256r1: {
+ priv: util.hexToUint8Array('8b426897130e1e5e70a4d6320c4002bb1642a5e57ade066e060464137dfd5e05'),
+ pub: util.hexToUint8Array('042a43d8cc20e5a3fbd75d3a5a9b17d867bba80f11334d0665f0c641d13460a52aa3373a4ccfaa7d76765a689bd9fe15a4fd107ef1ec9ac980234c31647170c81a')
+ },
+ brainpoolP384r1: {
+ priv: util.hexToUint8Array('7ccc97acdf4b775606c5c994a37a8b28086167046ac0d55664ede4097d8de79dec56e69dfff5776d53fcbd2147bbae9f'),
+ pub: util.hexToUint8Array('043809fa0c74ec9817cb73eba67db71e01663528fb9fbe6a123f8339346c37efc9ff7cd116074a80684448e44ee9204c795c88ad634ad272585c0b4e3093b11e6c99a6c0ca9c278f83ef57e2ed802502aee76f4529bcb873eef754bec894a5032f')
+ },
+ brainpoolP512r1: {
+ priv: util.hexToUint8Array('0a32459d1ecf8815397a66f6cdb18692c6f79a3c6059b4c344d0162416c7603a82a9a938568edafb132c7433ffeeab4cf201d9542209eb28070bea56ab6b8938'),
+ pub: util.hexToUint8Array('040f64473d9b3597752e3a87095c0b219dd85f56a79c3b2dc8fb2b0c95b60f4be45c41a8a7ea31d60e15fea6275eb7db93856bc2eb30cc8876513335d43812bd2c4e195e05679ac667a2f7fb05c5842779d18fa411500e43e2f291ea8348f061db15382d4db1cfcf106a29f46e1c00e7d63e635c51293f69c0dd4f6a61da589b2a')
}
}
};
diff --git a/test/general/brainpool.js b/test/general/brainpool.js
index e22dae587..903e4a66e 100644
--- a/test/general/brainpool.js
+++ b/test/general/brainpool.js
@@ -256,10 +256,6 @@ EJ4QcD/oQ6x1M/8X/iKQCtxZP8RnlrbH7ExkNON5s5g=
expect(await result.signatures[0].verified).to.be.true;
});
it('Decrypt and verify message with leading zero in hash signed with old elliptic algorithm', async function () {
- //this test would not work with nodeCrypto, since message is signed with leading zero stripped from the hash
- if (util.getNodeCrypto()) {
- this.skip(); // eslint-disable-line no-invalid-this
- }
const juliet = await load_priv_key('juliet');
const romeo = await load_pub_key('romeo');
const msg = await openpgp.readMessage({ armoredMessage: data.romeo.message_encrypted_with_leading_zero_in_hash_signed_by_elliptic_with_old_implementation });
From 909d44f43687d10bcc89506c6e24b0a4eecee81b Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Fri, 6 Oct 2023 17:21:50 +0200
Subject: [PATCH 074/224] Add back support for verification of some invalid
ECDSA sigs affected by old lib bug
At some point we used to generate invalid ECDSA sigs with the js (non-native) elliptic lib,
if the signature digest had leading zeros: https://github.com/openpgpjs/openpgpjs/pull/948 .
Brainpool curves are the most likely to have been affected by the bug, since they do not
have WebCrypto support (unlike NIST curves).
This commit reintroduces support on web to verify such invalid signatures
(support for this was previously built-in in the indutny-elliptic library).
It also expands the fix to work in Node.
---
src/crypto/public_key/elliptic/ecdsa.js | 37 +++++++++++++++++++++----
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js
index d000bf017..33f222325 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -97,12 +97,25 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
*/
export async function verify(oid, hashAlgo, signature, message, publicKey, hashed) {
const curve = new CurveWithOID(oid);
+ // See https://github.com/openpgpjs/openpgpjs/pull/948.
+ // NB: the impact was more likely limited to Brainpool curves, since thanks
+ // to WebCrypto availability, NIST curve should not have been affected.
+ // Similarly, secp256k1 should have been used rarely enough.
+ // However, we implement the fix for all curves, since it's only needed in case of
+ // verification failure, which is unexpected, hence a minor slowdown is acceptable.
+ const tryFallbackVerificationForOldBug = () => (
+ hashed[0] === 0 ?
+ jsVerify(curve, signature, hashed.subarray(1), publicKey) :
+ false
+ );
+
if (message && !util.isStream(message)) {
switch (curve.type) {
case 'web':
try {
// Need to await to make sure browser succeeds
- return await webVerify(curve, hashAlgo, signature, message, publicKey);
+ const verified = await webVerify(curve, hashAlgo, signature, message, publicKey);
+ return verified || tryFallbackVerificationForOldBug();
} catch (err) {
// We do not fallback if the error is related to key integrity
// Unfortunately Safari does not support p521 and throws a DataError when using it
@@ -113,14 +126,15 @@ export async function verify(oid, hashAlgo, signature, message, publicKey, hashe
util.printDebugError('Browser did not support verifying: ' + err.message);
}
break;
- case 'node':
- return nodeVerify(curve, hashAlgo, signature, message, publicKey);
+ case 'node': {
+ const verified = await nodeVerify(curve, hashAlgo, signature, message, publicKey);
+ return verified || tryFallbackVerificationForOldBug();
+ }
}
}
- const nobleCurve = getNobleCurve(curve.name);
- // lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
- return nobleCurve.verify(util.concatUint8Array([signature.r, signature.s]), hashed, publicKey, { lowS: false });
+ const verified = jsVerify(curve, signature, hashed, publicKey);
+ return verified || tryFallbackVerificationForOldBug();
}
/**
@@ -164,6 +178,17 @@ export async function validateParams(oid, Q, d) {
// Helper functions //
// //
//////////////////////////
+
+/**
+ * Fallback javascript implementation of ECDSA verification.
+ * To be used if no native implementation is available for the given curve/operation.
+ */
+function jsVerify(curve, signature, hashed, publicKey) {
+ const nobleCurve = getNobleCurve(curve.name);
+ // lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
+ return nobleCurve.verify(util.concatUint8Array([signature.r, signature.s]), hashed, publicKey, { lowS: false });
+}
+
async function webSign(curve, hashAlgo, message, keyPair) {
const len = curve.payloadSize;
const jwk = privateToJWK(curve.payloadSize, webCurves[curve.name], keyPair.publicKey, keyPair.privateKey);
From 7295a2e7b34d4990a2b6b839d5ae9ab5a825e078 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Fri, 6 Oct 2023 17:23:55 +0200
Subject: [PATCH 075/224] Rename `config.useIndutnyElliptic` to
`.useEllipticFallback`
To reflect change of underlying library
---
openpgp.d.ts | 2 +-
src/config/config.js | 7 +++----
src/crypto/public_key/elliptic/oid_curves.js | 5 +++++
test/crypto/ecdh.js | 8 ++++----
test/crypto/elliptic.js | 10 +++++-----
test/general/brainpool.js | 4 ++--
test/general/ecc_secp256k1.js | 2 +-
7 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index 3082030f0..d50d8a493 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -336,7 +336,7 @@ interface Config {
s2kArgon2Params: { passes: number, parallelism: number; memoryExponent: number; };
maxUserIDLength: number;
knownNotations: string[];
- useIndutnyElliptic: boolean;
+ useEllipticFallback: boolean;
rejectHashAlgorithms: Set;
rejectMessageHashAlgorithms: Set;
rejectPublicKeyAlgorithms: Set;
diff --git a/src/config/config.js b/src/config/config.js
index e448cbda6..c03c0cadb 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -246,13 +246,12 @@ export default {
*/
knownNotations: [],
/**
- * Whether to use the indutny/elliptic library for curves (other than Curve25519) that are not supported by the available native crypto API.
+ * Whether to use the the noble-curves library for curves (other than Curve25519) that are not supported by the available native crypto API.
* When false, certain standard curves will not be supported (depending on the platform).
- * Note: the indutny/elliptic curve library is not designed to be constant time.
* @memberof module:config
- * @property {Boolean} useIndutnyElliptic
+ * @property {Boolean} useEllipticFallback
*/
- useIndutnyElliptic: true,
+ useEllipticFallback: true,
/**
* Reject insecure hash algorithms
* @memberof module:config
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index d6561d5ad..0ad88cbaa 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -33,6 +33,7 @@ import util from '../../../util';
import { uint8ArrayToB64, b64ToUint8Array } from '../../../encoding/base64';
import OID from '../../../type/oid';
import { UnsupportedError } from '../../../packet/packet';
+import defaultConfig from '../../../config';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
@@ -65,6 +66,10 @@ const nobleCurvess = {
[enums.curve.brainpoolP512r1]: brainpoolP512r1
};
export const getNobleCurve = curveName => {
+ if (!defaultConfig.useEllipticFallback) {
+ // TODO make import dynamic
+ throw new Error('This curve is only supported in the full build of OpenPGP.js');
+ }
const curve = nobleCurvess[curveName];
if (!curve) throw new Error('Unsupported curve');
return curve;
diff --git a/test/crypto/ecdh.js b/test/crypto/ecdh.js
index c3b4536f9..8b4c7a82e 100644
--- a/test/crypto/ecdh.js
+++ b/test/crypto/ecdh.js
@@ -72,7 +72,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
)).to.be.rejectedWith(Error, /Unknown curve/).notify(done);
});
it('Invalid ephemeral key', function (done) {
- if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!openpgp.config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip();
}
expect(decrypt_message(
@@ -80,7 +80,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
)).to.be.rejectedWith(Error, /Private key is not valid for specified curve|second arg must be public key/).notify(done);
});
it('Invalid elliptic public key', function (done) {
- if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!openpgp.config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip();
}
expect(decrypt_message(
@@ -88,7 +88,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
)).to.be.rejectedWith(/Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|bad point/).notify(done);
});
it('Invalid key data integrity', function (done) {
- if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!openpgp.config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip();
}
expect(decrypt_message(
@@ -136,7 +136,7 @@ export default () => describe('ECDH key exchange @lightweight', function () {
const ecdh = elliptic_curves.ecdh;
it('Invalid curve', async function () {
- if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!openpgp.config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip();
}
const curve = new elliptic_curves.CurveWithOID('secp256k1');
diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js
index a434c5430..c755524e2 100644
--- a/test/crypto/elliptic.js
+++ b/test/crypto/elliptic.js
@@ -68,10 +68,10 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
done();
});
it('Creating KeyPair', function () {
- if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip();
}
- const names = config.useIndutnyElliptic ? ['p256', 'p384', 'p521', 'secp256k1', 'curve25519Legacy', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'] :
+ const names = config.useEllipticFallback ? ['p256', 'p384', 'p521', 'secp256k1', 'curve25519Legacy', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'] :
['p256', 'p384', 'p521', 'curve25519Legacy'];
return Promise.all(names.map(function (name) {
const curve = new elliptic_curves.CurveWithOID(name);
@@ -186,7 +186,7 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
)).to.be.rejectedWith(Error, /Unknown curve/);
});
it('secp256k1 - Invalid public key', async function () {
- if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip(); // webcrypto does not implement secp256k1: JS fallback tested instead
}
await expect(verify_signature(
@@ -197,7 +197,7 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
)).to.eventually.be.false;
});
it('secp256k1 - Invalid point', async function () {
- if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip(); // webcrypto does not implement secp256k1: JS fallback tested instead
}
await expect(verify_signature(
@@ -205,7 +205,7 @@ export default () => describe('Elliptic Curve Cryptography @lightweight', functi
)).to.eventually.be.false;
});
it('secp256k1 - Invalid signature', function (done) {
- if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip(); // webcrypto does not implement secp256k1: JS fallback tested instead
}
expect(verify_signature(
diff --git a/test/general/brainpool.js b/test/general/brainpool.js
index 903e4a66e..1cd3f78fe 100644
--- a/test/general/brainpool.js
+++ b/test/general/brainpool.js
@@ -13,7 +13,7 @@ export default () => (openpgp.config.ci ? describe.skip : describe)('Brainpool C
let rejectCurvesVal;
before(function() {
//only x25519 crypto is fully functional in lightbuild
- if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!openpgp.config.useEllipticFallback && !util.getNodeCrypto()) {
this.skip(); // eslint-disable-line no-invalid-this
}
});
@@ -283,7 +283,7 @@ EJ4QcD/oQ6x1M/8X/iKQCtxZP8RnlrbH7ExkNON5s5g=
});
tryTests('Brainpool Omnibus Tests @lightweight', omnibus, {
- if: openpgp.config.useIndutnyElliptic || util.getNodeCrypto()
+ if: openpgp.config.useEllipticFallback || util.getNodeCrypto()
});
});
diff --git a/test/general/ecc_secp256k1.js b/test/general/ecc_secp256k1.js
index da4576401..8b4674d86 100644
--- a/test/general/ecc_secp256k1.js
+++ b/test/general/ecc_secp256k1.js
@@ -6,7 +6,7 @@ import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
export default () => describe('Elliptic Curve Cryptography for secp256k1 curve @lightweight', function () {
- if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
+ if (!openpgp.config.useEllipticFallback && !util.getNodeCrypto()) {
before(function() {
this.skip(); // eslint-disable-line no-invalid-this
});
From a56a4a16e8c07a0a67209b4ae610c5c102b37210 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 12 Oct 2023 13:56:02 +0200
Subject: [PATCH 076/224] Use internal tweetnacl SHA-512 implementation
Instead of relying on externally provided one (no async loading supported)
---
package-lock.json | 14 +++++++-------
package.json | 2 +-
src/crypto/public_key/elliptic/ecdh.js | 2 +-
src/crypto/public_key/elliptic/ecdh_x.js | 2 +-
src/crypto/public_key/elliptic/eddsa.js | 2 +-
src/crypto/public_key/elliptic/eddsa_legacy.js | 5 +----
src/crypto/public_key/elliptic/oid_curves.js | 2 +-
src/crypto/public_key/index.js | 5 +----
8 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 0c0cc0511..8c3b047cd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,7 +17,7 @@
"@openpgp/noble-curves": "^1.2.1-0",
"@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git",
- "@openpgp/tweetnacl": "^1.0.3",
+ "@openpgp/tweetnacl": "^1.0.4-1",
"@openpgp/web-stream-tools": "^0.0.14",
"@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^24.0.1",
@@ -663,9 +663,9 @@
}
},
"node_modules/@openpgp/tweetnacl": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@openpgp/tweetnacl/-/tweetnacl-1.0.3.tgz",
- "integrity": "sha512-KGXNhU/mRg+uTsLGva55V340jwbX2pC8LndjOVI2oQ8vewPVTS2KnDOIXQ8O6KyT/c9Qy16KUQ5mwewe72m1Yw==",
+ "version": "1.0.4-1",
+ "resolved": "https://registry.npmjs.org/@openpgp/tweetnacl/-/tweetnacl-1.0.4-1.tgz",
+ "integrity": "sha512-coYo04Op1+g4h6yE6q0GglGdvWkdfvpQWKmR9nDIrW+LqdTtwHFXIyIQGs5cosR4tCajxRn9aF/+WK207zxFrg==",
"dev": true
},
"node_modules/@openpgp/web-stream-tools": {
@@ -8010,9 +8010,9 @@
}
},
"@openpgp/tweetnacl": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@openpgp/tweetnacl/-/tweetnacl-1.0.3.tgz",
- "integrity": "sha512-KGXNhU/mRg+uTsLGva55V340jwbX2pC8LndjOVI2oQ8vewPVTS2KnDOIXQ8O6KyT/c9Qy16KUQ5mwewe72m1Yw==",
+ "version": "1.0.4-1",
+ "resolved": "https://registry.npmjs.org/@openpgp/tweetnacl/-/tweetnacl-1.0.4-1.tgz",
+ "integrity": "sha512-coYo04Op1+g4h6yE6q0GglGdvWkdfvpQWKmR9nDIrW+LqdTtwHFXIyIQGs5cosR4tCajxRn9aF/+WK207zxFrg==",
"dev": true
},
"@openpgp/web-stream-tools": {
diff --git a/package.json b/package.json
index 90cd63461..f1bf3b303 100644
--- a/package.json
+++ b/package.json
@@ -67,7 +67,7 @@
"@openpgp/jsdoc": "^3.6.11",
"@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git",
- "@openpgp/tweetnacl": "^1.0.3",
+ "@openpgp/tweetnacl": "^1.0.4-1",
"@openpgp/web-stream-tools": "^0.0.14",
"@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^24.0.1",
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index ed370578d..9039833a5 100644
--- a/src/crypto/public_key/elliptic/ecdh.js
+++ b/src/crypto/public_key/elliptic/ecdh.js
@@ -20,7 +20,7 @@
* @module crypto/public_key/elliptic/ecdh
*/
-import nacl from '@openpgp/tweetnacl/nacl-fast-light';
+import nacl from '@openpgp/tweetnacl';
import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
diff --git a/src/crypto/public_key/elliptic/ecdh_x.js b/src/crypto/public_key/elliptic/ecdh_x.js
index decdeaab3..2d9ffe3e5 100644
--- a/src/crypto/public_key/elliptic/ecdh_x.js
+++ b/src/crypto/public_key/elliptic/ecdh_x.js
@@ -3,7 +3,7 @@
* @module crypto/public_key/elliptic/ecdh
*/
-import x25519 from '@openpgp/tweetnacl/nacl-fast-light';
+import x25519 from '@openpgp/tweetnacl';
import { x448 } from '@openpgp/noble-curves/ed448';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index 8b08a671f..28c33f0c1 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -21,7 +21,7 @@
*/
import { sha512 } from '@openpgp/noble-hashes/sha512';
-import ed25519 from '@openpgp/tweetnacl/nacl-fast-light';
+import ed25519 from '@openpgp/tweetnacl';
import { ed448 } from '@openpgp/noble-curves/ed448';
import util from '../../../util';
import enums from '../../../enums';
diff --git a/src/crypto/public_key/elliptic/eddsa_legacy.js b/src/crypto/public_key/elliptic/eddsa_legacy.js
index d90e0f9c6..966f8dbee 100644
--- a/src/crypto/public_key/elliptic/eddsa_legacy.js
+++ b/src/crypto/public_key/elliptic/eddsa_legacy.js
@@ -21,14 +21,11 @@
* @module crypto/public_key/elliptic/eddsa_legacy
*/
-import { sha512 } from '@openpgp/noble-hashes/sha512';
-import nacl from '@openpgp/tweetnacl/nacl-fast-light';
+import nacl from '@openpgp/tweetnacl';
import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
-nacl.hash = bytes => sha512(bytes);
-
/**
* Sign a message using the provided legacy EdDSA key
* @param {module:type/oid} oid - Elliptic curve object identifier
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index 0ad88cbaa..f5716d025 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -19,7 +19,7 @@
* @fileoverview Wrapper of an instance of an Elliptic Curve
* @module crypto/public_key/elliptic/curve
*/
-import nacl from '@openpgp/tweetnacl/nacl-fast-light';
+import nacl from '@openpgp/tweetnacl';
import { p256 } from '@openpgp/noble-curves/p256';
import { p384 } from '@openpgp/noble-curves/p384';
import { p521 } from '@openpgp/noble-curves/p521';
diff --git a/src/crypto/public_key/index.js b/src/crypto/public_key/index.js
index ac34ab76f..ffcf73cc7 100644
--- a/src/crypto/public_key/index.js
+++ b/src/crypto/public_key/index.js
@@ -3,7 +3,6 @@
* @module crypto/public_key
*/
-import nacl from '@openpgp/tweetnacl/nacl-fast-light';
import * as rsa from './rsa';
import * as elgamal from './elgamal';
import * as elliptic from './elliptic';
@@ -17,7 +16,5 @@ export default {
/** @see module:crypto/public_key/elliptic */
elliptic: elliptic,
/** @see module:crypto/public_key/dsa */
- dsa: dsa,
- /** @see tweetnacl */
- nacl: nacl
+ dsa: dsa
};
From 545621126647e4dc67a13393686e8792136a9ba3 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 18 Oct 2023 16:51:18 +0200
Subject: [PATCH 077/224] Simplify userID parsing based on conventions, drop
third-party parsing lib
Follow conventions as per https://datatracker.ietf.org/doc/draft-dkg-openpgp-userid-conventions
---
package-lock.json | 13 ----------
package.json | 1 -
src/packet/userid.js | 29 ++++++++++++++++------
test/general/packet.js | 56 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 8c3b047cd..bff38d5e8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -31,7 +31,6 @@
"bn.js": "^4.11.8",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
- "email-addresses": "3.1.0",
"eslint": "^8.34.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-base": "^15.0.0",
@@ -2103,12 +2102,6 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
"dev": true
},
- "node_modules/email-addresses": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
- "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
- "dev": true
- },
"node_modules/emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@@ -9131,12 +9124,6 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
"dev": true
},
- "email-addresses": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
- "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
- "dev": true
- },
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
diff --git a/package.json b/package.json
index f1bf3b303..5befcbc04 100644
--- a/package.json
+++ b/package.json
@@ -81,7 +81,6 @@
"bn.js": "^4.11.8",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
- "email-addresses": "3.1.0",
"eslint": "^8.34.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-base": "^15.0.0",
diff --git a/src/packet/userid.js b/src/packet/userid.js
index 4c89fecc6..4a092d8cf 100644
--- a/src/packet/userid.js
+++ b/src/packet/userid.js
@@ -15,8 +15,6 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-import emailAddresses from 'email-addresses';
-
import enums from '../enums';
import util from '../util';
import defaultConfig from '../config';
@@ -79,12 +77,27 @@ class UserIDPacket {
if (userID.length > config.maxUserIDLength) {
throw new Error('User ID string is too long');
}
- try {
- const { name, address: email, comments } = emailAddresses.parseOneAddress({ input: userID, atInDisplayName: true });
- this.comment = comments.replace(/^\(|\)$/g, '');
- this.name = name;
- this.email = email;
- } catch (e) {}
+
+ /**
+ * We support the conventional cases described in https://www.ietf.org/id/draft-dkg-openpgp-userid-conventions-00.html#section-4.1,
+ * as well comments placed between the name (if present) and the bracketed email address:
+ * - name (comment)
+ * - email
+ * In the first case, the `email` is the only required part, and it must contain the `@` symbol.
+ * The `name` and `comment` parts can include any letters, whitespace, and symbols, except for `(` and `)`,
+ * since they interfere with `comment` parsing.
+ */
+ const re = /^(?[^()]+\s+)?(?\([^()]+\)\s+)?(?<\S+@\S+>)$/;
+ const matches = re.exec(userID);
+ if (matches !== null) {
+ const { name, comment, email } = matches.groups;
+ this.comment = comment?.replace(/^\(|\)|\s$/g, '').trim() || ''; // remove parenthesis and separating whiltespace
+ this.name = name?.trim() || '';
+ this.email = email.substring(1, email.length - 1); // remove brackets
+ } else if (/^[^\s@]+@[^\s@]+$/.test(userID)) { // unbracketed email: enforce single @ and no whitespace
+ this.email = userID;
+ }
+
this.userID = userID;
}
diff --git a/test/general/packet.js b/test/general/packet.js
index f3a4e9b73..0cf26d7b6 100644
--- a/test/general/packet.js
+++ b/test/general/packet.js
@@ -1565,4 +1565,60 @@ kePFjAnu9cpynKXu3usf8+FuBw2zLsg1Id1n7ttxoAte416KjBN9lFBt8mcu
expect(otherPackets[0].constructor.tag).to.equal(openpgp.enums.packet.userID);
});
});
+
+ describe('UserID', () => {
+ it('parse conventional userID', () => {
+ const userID = 'Mr. Ed, the Talking Horse ';
+
+ const packet = new openpgp.UserIDPacket();
+ packet.read(new TextEncoder().encode(userID));
+ expect(packet.comment).to.equal('');
+ expect(packet.email).to.equal('ed@example.org');
+ expect(packet.userID).to.equal(userID);
+ });
+
+ it('parse userID with comment', () => {
+ const userID = 'Alice Jones (the Great) ';
+
+ const packet = new openpgp.UserIDPacket();
+ packet.read(new TextEncoder().encode(userID));
+ expect(packet.name).to.equal('Alice Jones');
+ expect(packet.comment).to.equal('the Great');
+ expect(packet.email).to.equal('alice@example.org');
+ expect(packet.userID).to.equal(userID);
+ });
+
+ it('parse userID with unbracketed email address', () => {
+ const userID = 'alice@example.org';
+
+ const packet = new openpgp.UserIDPacket();
+ packet.read(new TextEncoder().encode(userID));
+ expect(packet.name).to.equal('');
+ expect(packet.comment).to.equal('');
+ expect(packet.email).to.equal('alice@example.org');
+ expect(packet.userID).to.equal(userID);
+ });
+
+ it('parse userID with whitespace between parts', () => {
+ const userID = ' A name surrounded by whitespace ( a comment surrounded too ) ';
+
+ const packet = new openpgp.UserIDPacket();
+ packet.read(new TextEncoder().encode(userID));
+ expect(packet.name).to.equal('A name surrounded by whitespace');
+ expect(packet.comment).to.equal('a comment surrounded too');
+ expect(packet.email).to.equal('ed@example.org');
+ expect(packet.userID).to.equal(userID);
+ });
+
+ it('store userID without parts if parsing fails', () => {
+ const userID = 'Name only';
+
+ const packet = new openpgp.UserIDPacket();
+ packet.read(new TextEncoder().encode(userID));
+ expect(packet.name).to.equal('');
+ expect(packet.comment).to.equal('');
+ expect(packet.email).to.equal('');
+ expect(packet.userID).to.equal(userID);
+ });
+ });
});
From 9e1962f00608070d2b8fdffd9ec39cee4b543c3f Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 10 Oct 2023 11:23:03 +0200
Subject: [PATCH 078/224] Import noble-hashes, noble-curves and BN.js only on
demand
This primarily affects the lightweight build, which will not include these
(fairly large) libs in the main bundle file. This allows fetching their code only if required:
- Noble-curves is only needed for curves other than curve25519.
- Noble-hashes is needed for streamed hashing and e.g. SHA3 on web.
- BN.js is used by the above libs, and it's also separately needed for platforms
without native BigInt support.
---
src/biginteger.js | 39 ++++++++++++++
src/crypto/hash/index.js | 52 ++++++++-----------
src/crypto/hash/noble_hashes.js | 22 ++++++++
src/crypto/public_key/dsa.js | 7 ++-
src/crypto/public_key/elgamal.js | 8 ++-
src/crypto/public_key/elliptic/ecdh.js | 8 +--
src/crypto/public_key/elliptic/ecdh_x.js | 5 +-
src/crypto/public_key/elliptic/ecdsa.js | 12 ++---
src/crypto/public_key/elliptic/eddsa.js | 11 ++--
.../public_key/elliptic/noble_curves.js | 27 ++++++++++
src/crypto/public_key/elliptic/oid_curves.js | 34 ++----------
src/crypto/public_key/prime.js | 10 +++-
src/crypto/public_key/rsa.js | 15 +++++-
src/crypto/random.js | 3 +-
src/util.js | 33 ++++++++++++
15 files changed, 206 insertions(+), 80 deletions(-)
create mode 100644 src/biginteger.js
create mode 100644 src/crypto/hash/noble_hashes.js
create mode 100644 src/crypto/public_key/elliptic/noble_curves.js
diff --git a/src/biginteger.js b/src/biginteger.js
new file mode 100644
index 000000000..b869e50e0
--- /dev/null
+++ b/src/biginteger.js
@@ -0,0 +1,39 @@
+/**
+ * This is a vanilla JS copy of @openpgp/noble-hashes/esm/biginteger/interface.ts .
+ * We need to duplicate the file, instead of importing it, since in that case the BigIntegerInterface instance
+ * would be shared with noble-hashes, which separately calls `setImplementation()` on load, causing it to throw due to
+ * duplicate initialization.
+ */
+class BigInteger {
+ static setImplementation(Implementation, replace = false) {
+ if (BigInteger.Implementation && !replace) {
+ throw new Error('Implementation already set');
+ }
+ BigInteger.Implementation = Implementation;
+ }
+
+ static new(n) {
+ return new BigInteger.Implementation(n);
+ }
+}
+
+const detectBigInt = () => typeof BigInt !== 'undefined';
+export async function getBigInteger() {
+ if (BigInteger.Implementation) {
+ return BigInteger;
+ }
+
+ // TODOOOOO replace = true needed in case of concurrent class loading, how to fix without removing wrapper class?
+
+ if (detectBigInt()) {
+ // NativeBigInteger is small, so it's imported in isolation (it could also be imported at the top level)
+ const { default: NativeBigInteger } = await import('@openpgp/noble-hashes/esm/biginteger/native.interface');
+ BigInteger.setImplementation(NativeBigInteger, true);
+ } else {
+ // FallbackBigInteger relies on large BN.js lib, which is also used by noble-hashes and noble-curves
+ const { default: FallbackBigInteger } = await import('@openpgp/noble-hashes/esm/biginteger/bn.interface');
+ BigInteger.setImplementation(FallbackBigInteger, true);
+ }
+
+ return BigInteger;
+}
diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js
index 0943b82f7..3332a1cec 100644
--- a/src/crypto/hash/index.js
+++ b/src/crypto/hash/index.js
@@ -5,11 +5,6 @@
* @module crypto/hash
*/
-import { sha1 } from '@openpgp/noble-hashes/sha1';
-import { sha224, sha256 } from '@openpgp/noble-hashes/sha256';
-import { sha384, sha512 } from '@openpgp/noble-hashes/sha512';
-import { sha3_256, sha3_512 } from '@openpgp/noble-hashes/sha3';
-import { ripemd160 } from '@openpgp/noble-hashes/ripemd160';
import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5';
import util from '../../util';
@@ -31,48 +26,47 @@ function nodeHash(type) {
};
}
-function nobleHash(hash, webCryptoHash) {
+function nobleHash(nobleHashName, webCryptoHashName) {
+ const getNobleHash = async () => {
+ const { nobleHashes } = await import('./noble_hashes');
+ const hash = nobleHashes.get(nobleHashName);
+ if (!hash) throw new Error('Unsupported hash');
+ return hash;
+ };
+
return async function(data) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
if (util.isStream(data)) {
+ const hash = await getNobleHash();
+
const hashInstance = hash.create();
return stream.transform(data, value => {
hashInstance.update(value);
}, () => hashInstance.digest());
- } else if (webCrypto && webCryptoHash) {
- return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
+ } else if (webCrypto && webCryptoHashName) {
+ return new Uint8Array(await webCrypto.digest(webCryptoHashName, data));
} else {
+ const hash = await getNobleHash();
+
return hash(data);
}
};
}
-const hashFunctions = {
- md5: nodeHash('md5') || md5,
- sha1: nodeHash('sha1') || nobleHash(sha1, 'SHA-1'),
- sha224: nodeHash('sha224') || nobleHash(sha224),
- sha256: nodeHash('sha256') || nobleHash(sha256, 'SHA-256'),
- sha384: nodeHash('sha384') || nobleHash(sha384, 'SHA-384'),
- sha512: nodeHash('sha512') || nobleHash(sha512, 'SHA-512'),
- ripemd: nodeHash('ripemd160') || nobleHash(ripemd160),
- sha3_256: nodeHash('sha3-256') || nobleHash(sha3_256),
- sha3_512: nodeHash('sha3-512') || nobleHash(sha3_512)
-};
-
export default {
/** @see module:md5 */
- md5: hashFunctions.md5,
- sha1: hashFunctions.sha1,
- sha224: hashFunctions.sha224,
- sha256: hashFunctions.sha256,
- sha384: hashFunctions.sha384,
- sha512: hashFunctions.sha512,
- ripemd: hashFunctions.ripemd,
- sha3_256: hashFunctions.sha3_256,
- sha3_512: hashFunctions.sha3_512,
+ md5: nodeHash('md5') || md5,
+ sha1: nodeHash('sha1') || nobleHash('sha1', 'SHA-1'),
+ sha224: nodeHash('sha224') || nobleHash('sha224'),
+ sha256: nodeHash('sha256') || nobleHash('sha256', 'SHA-256'),
+ sha384: nodeHash('sha384') || nobleHash('sha384', 'SHA-384'),
+ sha512: nodeHash('sha512') || nobleHash('sha512', 'SHA-512'),
+ ripemd: nodeHash('ripemd160') || nobleHash('ripemd160'),
+ sha3_256: nodeHash('sha3-256') || nobleHash('sha3_256'),
+ sha3_512: nodeHash('sha3-512') || nobleHash('sha3_512'),
/**
* Create a hash on the specified data using the specified algorithm
diff --git a/src/crypto/hash/noble_hashes.js b/src/crypto/hash/noble_hashes.js
new file mode 100644
index 000000000..0d589a789
--- /dev/null
+++ b/src/crypto/hash/noble_hashes.js
@@ -0,0 +1,22 @@
+/**
+ * This file is needed to dynamic import the noble-hashes.
+ * Separate dynamic imports are not convenient as they result in too many chunks,
+ * which share a lot of code anyway.
+ */
+
+import { sha1 } from '@openpgp/noble-hashes/sha1';
+import { sha224, sha256 } from '@openpgp/noble-hashes/sha256';
+import { sha384, sha512 } from '@openpgp/noble-hashes/sha512';
+import { sha3_256, sha3_512 } from '@openpgp/noble-hashes/sha3';
+import { ripemd160 } from '@openpgp/noble-hashes/ripemd160';
+
+export const nobleHashes = new Map(Object.entries({
+ sha1,
+ sha224,
+ sha256,
+ sha384,
+ sha512,
+ sha3_256,
+ sha3_512,
+ ripemd160
+}));
diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js
index b48a4d972..b315da5f8 100644
--- a/src/crypto/public_key/dsa.js
+++ b/src/crypto/public_key/dsa.js
@@ -19,7 +19,6 @@
* @fileoverview A Digital signature algorithm implementation
* @module crypto/public_key/dsa
*/
-import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
import util from '../../util';
import { isProbablePrime } from './prime';
@@ -42,6 +41,8 @@ import { isProbablePrime } from './prime';
* @async
*/
export async function sign(hashAlgo, hashed, g, p, q, x) {
+ const BigInteger = await util.getBigInteger();
+
const one = BigInteger.new(1);
p = BigInteger.new(p);
q = BigInteger.new(q);
@@ -100,6 +101,8 @@ export async function sign(hashAlgo, hashed, g, p, q, x) {
* @async
*/
export async function verify(hashAlgo, r, s, hashed, g, p, q, y) {
+ const BigInteger = await util.getBigInteger();
+
const zero = BigInteger.new(0);
r = BigInteger.new(r);
s = BigInteger.new(s);
@@ -142,6 +145,8 @@ export async function verify(hashAlgo, r, s, hashed, g, p, q, y) {
* @async
*/
export async function validateParams(p, q, g, y, x) {
+ const BigInteger = await util.getBigInteger();
+
p = BigInteger.new(p);
q = BigInteger.new(q);
g = BigInteger.new(g);
diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js
index e9d668657..7e6790d64 100644
--- a/src/crypto/public_key/elgamal.js
+++ b/src/crypto/public_key/elgamal.js
@@ -19,9 +19,9 @@
* @fileoverview ElGamal implementation
* @module crypto/public_key/elgamal
*/
-import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { getRandomBigInteger } from '../random';
import { emeEncode, emeDecode } from '../pkcs1';
+import util from '../../util';
/**
* ElGamal Encryption function
@@ -34,6 +34,8 @@ import { emeEncode, emeDecode } from '../pkcs1';
* @async
*/
export async function encrypt(data, p, g, y) {
+ const BigInteger = await util.getBigInteger();
+
p = BigInteger.new(p);
g = BigInteger.new(g);
y = BigInteger.new(y);
@@ -63,6 +65,8 @@ export async function encrypt(data, p, g, y) {
* @async
*/
export async function decrypt(c1, c2, p, x, randomPayload) {
+ const BigInteger = await util.getBigInteger();
+
c1 = BigInteger.new(c1);
c2 = BigInteger.new(c2);
p = BigInteger.new(p);
@@ -82,6 +86,8 @@ export async function decrypt(c1, c2, p, x, randomPayload) {
* @async
*/
export async function validateParams(p, g, y, x) {
+ const BigInteger = await util.getBigInteger();
+
p = BigInteger.new(p);
g = BigInteger.new(g);
y = BigInteger.new(y);
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index 9039833a5..3ea593d72 100644
--- a/src/crypto/public_key/elliptic/ecdh.js
+++ b/src/crypto/public_key/elliptic/ecdh.js
@@ -21,7 +21,7 @@
*/
import nacl from '@openpgp/tweetnacl';
-import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
+import { CurveWithOID, jwkToRawPublic, rawPublicToJWK, privateToJWK, validateStandardParams } from './oid_curves';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
import hash from '../../hash';
@@ -210,8 +210,8 @@ export async function decrypt(oid, kdfParams, V, C, Q, d, fingerprint) {
throw err;
}
-function jsPrivateEphemeralKey(curve, V, d) {
- const nobleCurve = getNobleCurve(curve.name);
+async function jsPrivateEphemeralKey(curve, V, d) {
+ const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdh, curve.name);
// The output includes parity byte
const sharedSecretWithParity = nobleCurve.getSharedSecret(d, V);
const sharedKey = sharedSecretWithParity.subarray(1);
@@ -219,7 +219,7 @@ function jsPrivateEphemeralKey(curve, V, d) {
}
async function jsPublicEphemeralKey(curve, Q) {
- const nobleCurve = getNobleCurve(curve.name);
+ const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdh, curve.name);
const { publicKey: V, privateKey: v } = await curve.genKeyPair();
// The output includes parity byte
diff --git a/src/crypto/public_key/elliptic/ecdh_x.js b/src/crypto/public_key/elliptic/ecdh_x.js
index 2d9ffe3e5..a517e88a9 100644
--- a/src/crypto/public_key/elliptic/ecdh_x.js
+++ b/src/crypto/public_key/elliptic/ecdh_x.js
@@ -4,7 +4,6 @@
*/
import x25519 from '@openpgp/tweetnacl';
-import { x448 } from '@openpgp/noble-curves/ed448';
import * as aesKW from '../../aes_kw';
import { getRandomBytes } from '../../random';
@@ -32,6 +31,7 @@ export async function generate(algo) {
return { A, k };
}
case enums.publicKey.x448: {
+ const x448 = await util.getNobleCurve(enums.publicKey.x448);
const k = x448.utils.randomPrivateKey();
const A = x448.getPublicKey(k);
return { A, k };
@@ -60,6 +60,7 @@ export async function validateParams(algo, A, k) {
return util.equalsUint8Array(A, publicKey);
}
case enums.publicKey.x448: {
+ const x448 = await util.getNobleCurve(enums.publicKey.x448);
/**
* Derive public point A' from private key
* and expect A == A'
@@ -102,6 +103,7 @@ export async function encrypt(algo, data, recipientA) {
return { ephemeralPublicKey, wrappedKey };
}
case enums.publicKey.x448: {
+ const x448 = await util.getNobleCurve(enums.publicKey.x448);
const ephemeralSecretKey = x448.utils.randomPrivateKey();
const sharedSecret = x448.getSharedSecret(ephemeralSecretKey, recipientA);
const ephemeralPublicKey = x448.getPublicKey(ephemeralSecretKey);
@@ -146,6 +148,7 @@ export async function decrypt(algo, ephemeralPublicKey, wrappedKey, A, k) {
return aesKW.unwrap(encryptionKey, wrappedKey);
}
case enums.publicKey.x448: {
+ const x448 = await util.getNobleCurve(enums.publicKey.x448);
const sharedSecret = x448.getSharedSecret(k, ephemeralPublicKey);
const hkdfInput = util.concatUint8Array([
ephemeralPublicKey,
diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js
index 33f222325..b90bed2b3 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -24,7 +24,7 @@ import enums from '../../../enums';
import util from '../../../util';
import { getRandomBytes } from '../../random';
import hash from '../../hash';
-import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, getNobleCurve } from './oid_curves';
+import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams } from './oid_curves';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
@@ -74,7 +74,7 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
}
}
- const nobleCurve = getNobleCurve(curve.name);
+ const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, curve.name);
// lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
const signature = nobleCurve.sign(hashed, privateKey, { lowS: false });
return {
@@ -103,7 +103,7 @@ export async function verify(oid, hashAlgo, signature, message, publicKey, hashe
// Similarly, secp256k1 should have been used rarely enough.
// However, we implement the fix for all curves, since it's only needed in case of
// verification failure, which is unexpected, hence a minor slowdown is acceptable.
- const tryFallbackVerificationForOldBug = () => (
+ const tryFallbackVerificationForOldBug = async () => (
hashed[0] === 0 ?
jsVerify(curve, signature, hashed.subarray(1), publicKey) :
false
@@ -133,7 +133,7 @@ export async function verify(oid, hashAlgo, signature, message, publicKey, hashe
}
}
- const verified = jsVerify(curve, signature, hashed, publicKey);
+ const verified = await jsVerify(curve, signature, hashed, publicKey);
return verified || tryFallbackVerificationForOldBug();
}
@@ -183,8 +183,8 @@ export async function validateParams(oid, Q, d) {
* Fallback javascript implementation of ECDSA verification.
* To be used if no native implementation is available for the given curve/operation.
*/
-function jsVerify(curve, signature, hashed, publicKey) {
- const nobleCurve = getNobleCurve(curve.name);
+async function jsVerify(curve, signature, hashed, publicKey) {
+ const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, curve.name);
// lowS: non-canonical sig: https://stackoverflow.com/questions/74338846/ecdsa-signature-verification-mismatch
return nobleCurve.verify(util.concatUint8Array([signature.r, signature.s]), hashed, publicKey, { lowS: false });
}
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index 28c33f0c1..c13665ea8 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -20,15 +20,12 @@
* @module crypto/public_key/elliptic/eddsa
*/
-import { sha512 } from '@openpgp/noble-hashes/sha512';
import ed25519 from '@openpgp/tweetnacl';
-import { ed448 } from '@openpgp/noble-curves/ed448';
import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
import { getRandomBytes } from '../../random';
-ed25519.hash = bytes => sha512(bytes);
/**
* Generate (non-legacy) EdDSA key
@@ -43,6 +40,7 @@ export async function generate(algo) {
return { A, seed };
}
case enums.publicKey.ed448: {
+ const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
const seed = ed448.utils.randomPrivateKey();
const A = ed448.getPublicKey(seed);
return { A, seed };
@@ -76,6 +74,7 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
return { RS: signature };
}
case enums.publicKey.ed448: {
+ const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
const signature = ed448.sign(hashed, privateKey);
return { RS: signature };
}
@@ -104,8 +103,10 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
case enums.publicKey.ed25519: {
return ed25519.sign.detached.verify(hashed, RS, publicKey);
}
- case enums.publicKey.ed448:
+ case enums.publicKey.ed448: {
+ const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
return ed448.verify(RS, hashed, publicKey);
+ }
default:
throw new Error('Unsupported EdDSA algorithm');
}
@@ -131,6 +132,8 @@ export async function validateParams(algo, A, seed) {
}
case enums.publicKey.ed448: {
+ const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
+
const publicKey = ed448.getPublicKey(seed);
return util.equalsUint8Array(A, publicKey);
}
diff --git a/src/crypto/public_key/elliptic/noble_curves.js b/src/crypto/public_key/elliptic/noble_curves.js
new file mode 100644
index 000000000..22a80fbab
--- /dev/null
+++ b/src/crypto/public_key/elliptic/noble_curves.js
@@ -0,0 +1,27 @@
+/**
+ * This file is needed to dynamic import the noble-curves.
+ * Separate dynamic imports are not convenient as they result in too many chunks,
+ * which share a lot of code anyway.
+ */
+
+import { p256 } from '@openpgp/noble-curves/p256';
+import { p384 } from '@openpgp/noble-curves/p384';
+import { p521 } from '@openpgp/noble-curves/p521';
+import { brainpoolP256r1 } from '@openpgp/noble-curves/brainpoolP256r1';
+import { brainpoolP384r1 } from '@openpgp/noble-curves/brainpoolP384r1';
+import { brainpoolP512r1 } from '@openpgp/noble-curves/brainpoolP512r1';
+import { x448, ed448 } from '@openpgp/noble-curves/ed448';
+import { secp256k1 } from '@openpgp/noble-curves/secp256k1';
+
+export const nobleCurves = new Map(Object.entries({
+ p256,
+ p384,
+ p521,
+ brainpoolP256r1,
+ brainpoolP384r1,
+ brainpoolP512r1,
+ secp256k1,
+ x448,
+ ed448
+}));
+
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index f5716d025..75c238274 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -20,20 +20,12 @@
* @module crypto/public_key/elliptic/curve
*/
import nacl from '@openpgp/tweetnacl';
-import { p256 } from '@openpgp/noble-curves/p256';
-import { p384 } from '@openpgp/noble-curves/p384';
-import { p521 } from '@openpgp/noble-curves/p521';
-import { brainpoolP256r1 } from '@openpgp/noble-curves/brainpoolP256r1';
-import { brainpoolP384r1 } from '@openpgp/noble-curves/brainpoolP384r1';
-import { brainpoolP512r1 } from '@openpgp/noble-curves/brainpoolP512r1';
-import { secp256k1 } from '@openpgp/noble-curves/secp256k1';
import { getRandomBytes } from '../../random';
import enums from '../../../enums';
import util from '../../../util';
import { uint8ArrayToB64, b64ToUint8Array } from '../../../encoding/base64';
import OID from '../../../type/oid';
import { UnsupportedError } from '../../../packet/packet';
-import defaultConfig from '../../../config';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
@@ -56,26 +48,6 @@ const nodeCurves = nodeCrypto ? {
[enums.curve.brainpoolP512r1]: knownCurves.includes('brainpoolP512r1') ? 'brainpoolP512r1' : undefined
} : {};
-const nobleCurvess = {
- [enums.curve.p256]: p256,
- [enums.curve.p384]: p384,
- [enums.curve.p521]: p521,
- [enums.curve.secp256k1]: secp256k1,
- [enums.curve.brainpoolP256r1]: brainpoolP256r1,
- [enums.curve.brainpoolP384r1]: brainpoolP384r1,
- [enums.curve.brainpoolP512r1]: brainpoolP512r1
-};
-export const getNobleCurve = curveName => {
- if (!defaultConfig.useEllipticFallback) {
- // TODO make import dynamic
- throw new Error('This curve is only supported in the full build of OpenPGP.js');
- }
- const curve = nobleCurvess[curveName];
- if (!curve) throw new Error('Unsupported curve');
- return curve;
-};
-
-
const curves = {
p256: {
oid: [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
@@ -291,7 +263,7 @@ async function validateStandardParams(algo, oid, Q, d) {
return true;
}
- const nobleCurve = getNobleCurve(enums.write(enums.curve, oid.toHex()));
+ const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, enums.write(enums.curve, oid.toHex())); // excluding curve25519Legacy, ecdh and ecdsa use the same curves
/*
* Re-derive public point Q' = dG from private key
* Expect Q == Q'
@@ -313,8 +285,8 @@ export {
// Helper functions //
// //
//////////////////////////
-function jsGenKeyPair(name) {
- const nobleCurve = getNobleCurve(name);
+async function jsGenKeyPair(name) {
+ const nobleCurve = await util.getNobleCurve(enums.publicKey.ecdsa, name); // excluding curve25519Legacy, ecdh and ecdsa use the same curves
const privateKey = nobleCurve.utils.randomPrivateKey();
const publicKey = nobleCurve.getPublicKey(privateKey, false);
return { publicKey, privateKey };
diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js
index 8e0bd13d1..18d3250e3 100644
--- a/src/crypto/public_key/prime.js
+++ b/src/crypto/public_key/prime.js
@@ -19,7 +19,7 @@
* @fileoverview Algorithms for probabilistic random prime generation
* @module crypto/public_key/prime
*/
-import { BigInteger } from '@openpgp/noble-hashes/biginteger';
+import util from '../../util';
import { getRandomBigInteger } from '../random';
/**
@@ -31,6 +31,8 @@ import { getRandomBigInteger } from '../random';
* @async
*/
export async function randomProbablePrime(bits, e, k) {
+ const BigInteger = await util.getBigInteger();
+
const one = BigInteger.new(1);
const min = one.leftShift(BigInteger.new(bits - 1));
const thirty = BigInteger.new(30);
@@ -91,11 +93,15 @@ export async function isProbablePrime(n, e, k) {
* @returns {boolean}
*/
export async function fermat(n, b) {
+ const BigInteger = await util.getBigInteger();
+
b = b || BigInteger.new(2);
return b.modExp(n.dec(), n).isOne();
}
export async function divisionTest(n) {
+ const BigInteger = await util.getBigInteger();
+
return smallPrimes.every(m => {
return n.mod(BigInteger.new(m)) !== 0;
});
@@ -224,6 +230,8 @@ const smallPrimes = [
* @async
*/
export async function millerRabin(n, k, rand) {
+ const BigInteger = await util.getBigInteger();
+
const len = n.bitLength();
if (!k) {
diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js
index 180a33263..9050edcc4 100644
--- a/src/crypto/public_key/rsa.js
+++ b/src/crypto/public_key/rsa.js
@@ -19,7 +19,6 @@
* @fileoverview RSA implementation
* @module crypto/public_key/rsa
*/
-import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import { randomProbablePrime } from './prime';
import { getRandomBigInteger } from '../random';
import util from '../../util';
@@ -159,6 +158,8 @@ export async function decrypt(data, n, e, d, p, q, u, randomPayload) {
* @async
*/
export async function generate(bits, e) {
+ const BigInteger = await util.getBigInteger();
+
e = BigInteger.new(e);
// Native RSA keygen using Web Crypto
@@ -262,6 +263,8 @@ export async function generate(bits, e) {
* @async
*/
export async function validateParams(n, e, d, p, q, u) {
+ const BigInteger = await util.getBigInteger();
+
n = BigInteger.new(n);
p = BigInteger.new(p);
q = BigInteger.new(q);
@@ -300,6 +303,8 @@ export async function validateParams(n, e, d, p, q, u) {
}
async function bnSign(hashAlgo, n, d, hashed) {
+ const BigInteger = await util.getBigInteger();
+
n = BigInteger.new(n);
const m = BigInteger.new(await emsaEncode(hashAlgo, hashed, n.byteLength()));
d = BigInteger.new(d);
@@ -360,6 +365,8 @@ async function nodeSign(hashAlgo, data, n, e, d, p, q, u) {
}
async function bnVerify(hashAlgo, s, n, e, hashed) {
+ const BigInteger = await util.getBigInteger();
+
n = BigInteger.new(n);
s = BigInteger.new(s);
e = BigInteger.new(e);
@@ -427,6 +434,8 @@ async function nodeEncrypt(data, n, e) {
}
async function bnEncrypt(data, n, e) {
+ const BigInteger = await util.getBigInteger();
+
n = BigInteger.new(n);
data = BigInteger.new(emeEncode(data, n.byteLength()));
e = BigInteger.new(e);
@@ -478,6 +487,8 @@ async function nodeDecrypt(data, n, e, d, p, q, u, randomPayload) {
}
async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
+ const BigInteger = await util.getBigInteger();
+
data = BigInteger.new(data);
n = BigInteger.new(n);
e = BigInteger.new(e);
@@ -519,6 +530,8 @@ async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
* @param {Uint8Array} u
*/
async function privateToJWK(n, e, d, p, q, u) {
+ const BigInteger = await util.getBigInteger();
+
const pNum = BigInteger.new(p);
const qNum = BigInteger.new(q);
const dNum = BigInteger.new(d);
diff --git a/src/crypto/random.js b/src/crypto/random.js
index 8c7ad4183..1f5f81426 100644
--- a/src/crypto/random.js
+++ b/src/crypto/random.js
@@ -21,7 +21,6 @@
* @fileoverview Provides tools for retrieving secure randomness from browsers or Node.js
* @module crypto/random
*/
-import { BigInteger } from '@openpgp/noble-hashes/biginteger';
import util from '../util';
const nodeCrypto = util.getNodeCrypto();
@@ -52,6 +51,8 @@ export function getRandomBytes(length) {
* @async
*/
export async function getRandomBigInteger(min, max) {
+ const BigInteger = await util.getBigInteger();
+
if (max.lt(min)) {
throw new Error('Illegal parameter value: max <= min');
}
diff --git a/src/util.js b/src/util.js
index f0ee7f637..0a1c721db 100644
--- a/src/util.js
+++ b/src/util.js
@@ -25,6 +25,8 @@
import * as stream from '@openpgp/web-stream-tools';
import { createRequire } from 'module'; // Must be stripped in browser built
import enums from './enums';
+import defaultConfig from './config';
+import { getBigInteger } from './biginteger';
const debugMode = (() => {
try {
@@ -48,6 +50,37 @@ const util = {
isStream: stream.isStream,
+ getBigInteger,
+
+ /**
+ * Load noble-curves lib on demand and return the requested curve function
+ * @param {enums.publicKey} publicKeyAlgo
+ * @param {enums.curve} [curveName] - for algos supporting different curves (e.g. ECDSA)
+ * @returns curve implementation
+ * @throws on unrecognized curve, or curve not implemented by noble-curve
+ */
+ getNobleCurve: async (publicKeyAlgo, curveName) => {
+ if (!defaultConfig.useEllipticFallback) {
+ throw new Error('This curve is only supported in the full build of OpenPGP.js');
+ }
+
+ const { nobleCurves } = await import('./crypto/public_key/elliptic/noble_curves');
+ switch (publicKeyAlgo) {
+ case enums.publicKey.ecdh:
+ case enums.publicKey.ecdsa: {
+ const curve = nobleCurves.get(curveName);
+ if (!curve) throw new Error('Unsupported curve');
+ return curve;
+ }
+ case enums.publicKey.x448:
+ return nobleCurves.get('x448');
+ case enums.publicKey.ed448:
+ return nobleCurves.get('ed448');
+ default:
+ throw new Error('Unsupported curve');
+ }
+ },
+
readNumber: function (bytes) {
let n = 0;
for (let i = 0; i < bytes.length; i++) {
From 4ee9deae626f2bdd5b005a7848d7408b69114ec4 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 12 Oct 2023 11:16:55 +0200
Subject: [PATCH 079/224] Switch back to using standard BigInteger class
instead of wrapper
Using a wrapper requires adding some handling code to fix race conditions,
but it does not provide advantages until we switch to TS.
---
src/biginteger.js | 35 +++++--------------
src/crypto/public_key/dsa.js | 46 ++++++++++++-------------
src/crypto/public_key/elgamal.js | 38 ++++++++++-----------
src/crypto/public_key/prime.js | 16 ++++-----
src/crypto/public_key/rsa.js | 58 ++++++++++++++++----------------
src/crypto/random.js | 2 +-
6 files changed, 88 insertions(+), 107 deletions(-)
diff --git a/src/biginteger.js b/src/biginteger.js
index b869e50e0..bd114984f 100644
--- a/src/biginteger.js
+++ b/src/biginteger.js
@@ -1,39 +1,20 @@
/**
- * This is a vanilla JS copy of @openpgp/noble-hashes/esm/biginteger/interface.ts .
- * We need to duplicate the file, instead of importing it, since in that case the BigIntegerInterface instance
- * would be shared with noble-hashes, which separately calls `setImplementation()` on load, causing it to throw due to
- * duplicate initialization.
+ * We don't use the BigIntegerInterface wrapper from noble-hashes because:
+ * - importing the instance results in it being shared with noble-hashes, which separately calls `setImplementation()`
+ * on load, causing it to throw due to duplicate initialization.
+ * - even duplicating the interface code here to keep a separate instance requires handing a race-conditions the first time
+ * `getBigInteger` is called, when the code needs to check if the implementation is set, and initialize it if not.
+ * Ultimately, the interface provides no advantages and it's only needed because of TS.
*/
-class BigInteger {
- static setImplementation(Implementation, replace = false) {
- if (BigInteger.Implementation && !replace) {
- throw new Error('Implementation already set');
- }
- BigInteger.Implementation = Implementation;
- }
-
- static new(n) {
- return new BigInteger.Implementation(n);
- }
-}
-
const detectBigInt = () => typeof BigInt !== 'undefined';
export async function getBigInteger() {
- if (BigInteger.Implementation) {
- return BigInteger;
- }
-
- // TODOOOOO replace = true needed in case of concurrent class loading, how to fix without removing wrapper class?
-
if (detectBigInt()) {
// NativeBigInteger is small, so it's imported in isolation (it could also be imported at the top level)
const { default: NativeBigInteger } = await import('@openpgp/noble-hashes/esm/biginteger/native.interface');
- BigInteger.setImplementation(NativeBigInteger, true);
+ return NativeBigInteger;
} else {
// FallbackBigInteger relies on large BN.js lib, which is also used by noble-hashes and noble-curves
const { default: FallbackBigInteger } = await import('@openpgp/noble-hashes/esm/biginteger/bn.interface');
- BigInteger.setImplementation(FallbackBigInteger, true);
+ return FallbackBigInteger;
}
-
- return BigInteger;
}
diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js
index b315da5f8..d3fb6e8c5 100644
--- a/src/crypto/public_key/dsa.js
+++ b/src/crypto/public_key/dsa.js
@@ -43,11 +43,11 @@ import { isProbablePrime } from './prime';
export async function sign(hashAlgo, hashed, g, p, q, x) {
const BigInteger = await util.getBigInteger();
- const one = BigInteger.new(1);
- p = BigInteger.new(p);
- q = BigInteger.new(q);
- g = BigInteger.new(g);
- x = BigInteger.new(x);
+ const one = new BigInteger(1);
+ p = new BigInteger(p);
+ q = new BigInteger(q);
+ g = new BigInteger(g);
+ x = new BigInteger(x);
let k;
let r;
@@ -60,7 +60,7 @@ export async function sign(hashAlgo, hashed, g, p, q, x) {
// of leftmost bits equal to the number of bits of q. This (possibly
// truncated) hash function result is treated as a number and used
// directly in the DSA signature algorithm.
- const h = BigInteger.new(hashed.subarray(0, q.byteLength())).mod(q);
+ const h = new BigInteger(hashed.subarray(0, q.byteLength())).mod(q);
// FIPS-186-4, section 4.6:
// The values of r and s shall be checked to determine if r = 0 or s = 0.
// If either r = 0 or s = 0, a new value of k shall be generated, and the
@@ -103,21 +103,21 @@ export async function sign(hashAlgo, hashed, g, p, q, x) {
export async function verify(hashAlgo, r, s, hashed, g, p, q, y) {
const BigInteger = await util.getBigInteger();
- const zero = BigInteger.new(0);
- r = BigInteger.new(r);
- s = BigInteger.new(s);
+ const zero = new BigInteger(0);
+ r = new BigInteger(r);
+ s = new BigInteger(s);
- p = BigInteger.new(p);
- q = BigInteger.new(q);
- g = BigInteger.new(g);
- y = BigInteger.new(y);
+ p = new BigInteger(p);
+ q = new BigInteger(q);
+ g = new BigInteger(g);
+ y = new BigInteger(y);
if (r.lte(zero) || r.gte(q) ||
s.lte(zero) || s.gte(q)) {
util.printDebug('invalid DSA Signature');
return false;
}
- const h = BigInteger.new(hashed.subarray(0, q.byteLength())).imod(q);
+ const h = new BigInteger(hashed.subarray(0, q.byteLength())).imod(q);
const w = s.modInv(q); // s**-1 mod q
if (w.isZero()) {
util.printDebug('invalid DSA Signature');
@@ -147,11 +147,11 @@ export async function verify(hashAlgo, r, s, hashed, g, p, q, y) {
export async function validateParams(p, q, g, y, x) {
const BigInteger = await util.getBigInteger();
- p = BigInteger.new(p);
- q = BigInteger.new(q);
- g = BigInteger.new(g);
- y = BigInteger.new(y);
- const one = BigInteger.new(1);
+ p = new BigInteger(p);
+ q = new BigInteger(q);
+ g = new BigInteger(g);
+ y = new BigInteger(y);
+ const one = new BigInteger(1);
// Check that 1 < g < p
if (g.lte(one) || g.gte(p)) {
return false;
@@ -175,8 +175,8 @@ export async function validateParams(p, q, g, y, x) {
/**
* Check q is large and probably prime (we mainly want to avoid small factors)
*/
- const qSize = BigInteger.new(q.bitLength());
- const n150 = BigInteger.new(150);
+ const qSize = new BigInteger(q.bitLength());
+ const n150 = new BigInteger(150);
if (qSize.lt(n150) || !(await isProbablePrime(q, null, 32))) {
return false;
}
@@ -187,8 +187,8 @@ export async function validateParams(p, q, g, y, x) {
*
* Blinded exponentiation computes g**{rq + x} to compare to y
*/
- x = BigInteger.new(x);
- const two = BigInteger.new(2);
+ x = new BigInteger(x);
+ const two = new BigInteger(2);
const r = await getRandomBigInteger(two.leftShift(qSize.dec()), two.leftShift(qSize)); // draw r of same size as q
const rqx = q.mul(r).add(x);
if (!y.equal(g.modExp(rqx, p))) {
diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js
index 7e6790d64..2dc2c2fda 100644
--- a/src/crypto/public_key/elgamal.js
+++ b/src/crypto/public_key/elgamal.js
@@ -36,16 +36,16 @@ import util from '../../util';
export async function encrypt(data, p, g, y) {
const BigInteger = await util.getBigInteger();
- p = BigInteger.new(p);
- g = BigInteger.new(g);
- y = BigInteger.new(y);
+ p = new BigInteger(p);
+ g = new BigInteger(g);
+ y = new BigInteger(y);
const padded = emeEncode(data, p.byteLength());
- const m = BigInteger.new(padded);
+ const m = new BigInteger(padded);
// OpenPGP uses a "special" version of ElGamal where g is generator of the full group Z/pZ*
// hence g has order p-1, and to avoid that k = 0 mod p-1, we need to pick k in [1, p-2]
- const k = await getRandomBigInteger(BigInteger.new(1), p.dec());
+ const k = await getRandomBigInteger(new BigInteger(1), p.dec());
return {
c1: g.modExp(k, p).toUint8Array(),
c2: y.modExp(k, p).imul(m).imod(p).toUint8Array()
@@ -67,10 +67,10 @@ export async function encrypt(data, p, g, y) {
export async function decrypt(c1, c2, p, x, randomPayload) {
const BigInteger = await util.getBigInteger();
- c1 = BigInteger.new(c1);
- c2 = BigInteger.new(c2);
- p = BigInteger.new(p);
- x = BigInteger.new(x);
+ c1 = new BigInteger(c1);
+ c2 = new BigInteger(c2);
+ p = new BigInteger(p);
+ x = new BigInteger(x);
const padded = c1.modExp(x, p).modInv(p).imul(c2).imod(p);
return emeDecode(padded.toUint8Array('be', p.byteLength()), randomPayload);
@@ -88,19 +88,19 @@ export async function decrypt(c1, c2, p, x, randomPayload) {
export async function validateParams(p, g, y, x) {
const BigInteger = await util.getBigInteger();
- p = BigInteger.new(p);
- g = BigInteger.new(g);
- y = BigInteger.new(y);
+ p = new BigInteger(p);
+ g = new BigInteger(g);
+ y = new BigInteger(y);
- const one = BigInteger.new(1);
+ const one = new BigInteger(1);
// Check that 1 < g < p
if (g.lte(one) || g.gte(p)) {
return false;
}
// Expect p-1 to be large
- const pSize = BigInteger.new(p.bitLength());
- const n1023 = BigInteger.new(1023);
+ const pSize = new BigInteger(p.bitLength());
+ const n1023 = new BigInteger(1023);
if (pSize.lt(n1023)) {
return false;
}
@@ -120,8 +120,8 @@ export async function validateParams(p, g, y, x) {
* We just check g**i != 1 for all i up to a threshold
*/
let res = g;
- const i = BigInteger.new(1);
- const threshold = BigInteger.new(2).leftShift(BigInteger.new(17)); // we want order > threshold
+ const i = new BigInteger(1);
+ const threshold = new BigInteger(2).leftShift(new BigInteger(17)); // we want order > threshold
while (i.lt(threshold)) {
res = res.mul(g).imod(p);
if (res.isOne()) {
@@ -136,8 +136,8 @@ export async function validateParams(p, g, y, x) {
*
* Blinded exponentiation computes g**{r(p-1) + x} to compare to y
*/
- x = BigInteger.new(x);
- const two = BigInteger.new(2);
+ x = new BigInteger(x);
+ const two = new BigInteger(2);
const r = await getRandomBigInteger(two.leftShift(pSize.dec()), two.leftShift(pSize)); // draw r of same size as p-1
const rqx = p.dec().imul(r).iadd(x);
if (!y.equal(g.modExp(rqx, p))) {
diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js
index 18d3250e3..8045f6388 100644
--- a/src/crypto/public_key/prime.js
+++ b/src/crypto/public_key/prime.js
@@ -33,9 +33,9 @@ import { getRandomBigInteger } from '../random';
export async function randomProbablePrime(bits, e, k) {
const BigInteger = await util.getBigInteger();
- const one = BigInteger.new(1);
- const min = one.leftShift(BigInteger.new(bits - 1));
- const thirty = BigInteger.new(30);
+ const one = new BigInteger(1);
+ const min = one.leftShift(new BigInteger(bits - 1));
+ const thirty = new BigInteger(30);
/*
* We can avoid any multiples of 3 and 5 by looking at n mod 30
* n mod 30 = 0 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
@@ -48,7 +48,7 @@ export async function randomProbablePrime(bits, e, k) {
let i = n.mod(thirty).toNumber();
do {
- n.iadd(BigInteger.new(adds[i]));
+ n.iadd(new BigInteger(adds[i]));
i = (i + adds[i]) % adds.length;
// If reached the maximum, go back to the minimum.
if (n.bitLength() > bits) {
@@ -95,7 +95,7 @@ export async function isProbablePrime(n, e, k) {
export async function fermat(n, b) {
const BigInteger = await util.getBigInteger();
- b = b || BigInteger.new(2);
+ b = b || new BigInteger(2);
return b.modExp(n.dec(), n).isOne();
}
@@ -103,7 +103,7 @@ export async function divisionTest(n) {
const BigInteger = await util.getBigInteger();
return smallPrimes.every(m => {
- return n.mod(BigInteger.new(m)) !== 0;
+ return n.mod(new BigInteger(m)) !== 0;
});
}
@@ -243,10 +243,10 @@ export async function millerRabin(n, k, rand) {
// Find d and s, (n - 1) = (2 ^ s) * d;
let s = 0;
while (!n1.getBit(s)) { s++; }
- const d = n.rightShift(BigInteger.new(s));
+ const d = n.rightShift(new BigInteger(s));
for (; k > 0; k--) {
- const a = rand ? rand() : await getRandomBigInteger(BigInteger.new(2), n1);
+ const a = rand ? rand() : await getRandomBigInteger(new BigInteger(2), n1);
let x = a.modExp(d, n);
if (x.isOne() || x.equal(n1)) {
diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js
index 9050edcc4..6387bc255 100644
--- a/src/crypto/public_key/rsa.js
+++ b/src/crypto/public_key/rsa.js
@@ -160,7 +160,7 @@ export async function decrypt(data, n, e, d, p, q, u, randomPayload) {
export async function generate(bits, e) {
const BigInteger = await util.getBigInteger();
- e = BigInteger.new(e);
+ e = new BigInteger(e);
// Native RSA keygen using Web Crypto
if (util.getWebCrypto()) {
@@ -265,24 +265,24 @@ export async function generate(bits, e) {
export async function validateParams(n, e, d, p, q, u) {
const BigInteger = await util.getBigInteger();
- n = BigInteger.new(n);
- p = BigInteger.new(p);
- q = BigInteger.new(q);
+ n = new BigInteger(n);
+ p = new BigInteger(p);
+ q = new BigInteger(q);
// expect pq = n
if (!p.mul(q).equal(n)) {
return false;
}
- const two = BigInteger.new(2);
+ const two = new BigInteger(2);
// expect p*u = 1 mod q
- u = BigInteger.new(u);
+ u = new BigInteger(u);
if (!p.mul(u).mod(q).isOne()) {
return false;
}
- e = BigInteger.new(e);
- d = BigInteger.new(d);
+ e = new BigInteger(e);
+ d = new BigInteger(d);
/**
* In RSA pkcs#1 the exponents (d, e) are inverses modulo lcm(p-1, q-1)
* We check that [de = 1 mod (p-1)] and [de = 1 mod (q-1)]
@@ -290,7 +290,7 @@ export async function validateParams(n, e, d, p, q, u) {
*
* We blind the multiplication with r, and check that rde = r mod lcm(p-1, q-1)
*/
- const nSizeOver3 = BigInteger.new(Math.floor(n.bitLength() / 3));
+ const nSizeOver3 = new BigInteger(Math.floor(n.bitLength() / 3));
const r = await getRandomBigInteger(two, two.leftShift(nSizeOver3)); // r in [ 2, 2^{|n|/3} ) < p and q
const rde = r.mul(d).mul(e);
@@ -305,9 +305,9 @@ export async function validateParams(n, e, d, p, q, u) {
async function bnSign(hashAlgo, n, d, hashed) {
const BigInteger = await util.getBigInteger();
- n = BigInteger.new(n);
- const m = BigInteger.new(await emsaEncode(hashAlgo, hashed, n.byteLength()));
- d = BigInteger.new(d);
+ n = new BigInteger(n);
+ const m = new BigInteger(await emsaEncode(hashAlgo, hashed, n.byteLength()));
+ d = new BigInteger(d);
if (m.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
}
@@ -367,9 +367,9 @@ async function nodeSign(hashAlgo, data, n, e, d, p, q, u) {
async function bnVerify(hashAlgo, s, n, e, hashed) {
const BigInteger = await util.getBigInteger();
- n = BigInteger.new(n);
- s = BigInteger.new(s);
- e = BigInteger.new(e);
+ n = new BigInteger(n);
+ s = new BigInteger(s);
+ e = new BigInteger(e);
if (s.gte(n)) {
throw new Error('Signature size cannot exceed modulus size');
}
@@ -436,9 +436,9 @@ async function nodeEncrypt(data, n, e) {
async function bnEncrypt(data, n, e) {
const BigInteger = await util.getBigInteger();
- n = BigInteger.new(n);
- data = BigInteger.new(emeEncode(data, n.byteLength()));
- e = BigInteger.new(e);
+ n = new BigInteger(n);
+ data = new BigInteger(emeEncode(data, n.byteLength()));
+ e = new BigInteger(e);
if (data.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
}
@@ -489,20 +489,20 @@ async function nodeDecrypt(data, n, e, d, p, q, u, randomPayload) {
async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
const BigInteger = await util.getBigInteger();
- data = BigInteger.new(data);
- n = BigInteger.new(n);
- e = BigInteger.new(e);
- d = BigInteger.new(d);
- p = BigInteger.new(p);
- q = BigInteger.new(q);
- u = BigInteger.new(u);
+ data = new BigInteger(data);
+ n = new BigInteger(n);
+ e = new BigInteger(e);
+ d = new BigInteger(d);
+ p = new BigInteger(p);
+ q = new BigInteger(q);
+ u = new BigInteger(u);
if (data.gte(n)) {
throw new Error('Data too large.');
}
const dq = d.mod(q.dec()); // d mod (q-1)
const dp = d.mod(p.dec()); // d mod (p-1)
- const unblinder = (await getRandomBigInteger(BigInteger.new(2), n)).mod(n);
+ const unblinder = (await getRandomBigInteger(new BigInteger(2), n)).mod(n);
const blinder = unblinder.modInv(n).modExp(e, n);
data = data.mul(blinder).mod(n);
@@ -532,9 +532,9 @@ async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
async function privateToJWK(n, e, d, p, q, u) {
const BigInteger = await util.getBigInteger();
- const pNum = BigInteger.new(p);
- const qNum = BigInteger.new(q);
- const dNum = BigInteger.new(d);
+ const pNum = new BigInteger(p);
+ const qNum = new BigInteger(q);
+ const dNum = new BigInteger(d);
let dq = dNum.mod(qNum.dec()); // d mod (q-1)
let dp = dNum.mod(pNum.dec()); // d mod (p-1)
diff --git a/src/crypto/random.js b/src/crypto/random.js
index 1f5f81426..4936c97e8 100644
--- a/src/crypto/random.js
+++ b/src/crypto/random.js
@@ -63,6 +63,6 @@ export async function getRandomBigInteger(min, max) {
// Using a while loop is necessary to avoid bias introduced by the mod operation.
// However, we request 64 extra random bits so that the bias is negligible.
// Section B.1.1 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
- const r = BigInteger.new(await getRandomBytes(bytes + 8));
+ const r = new BigInteger(getRandomBytes(bytes + 8));
return r.mod(modulus).add(min);
}
From 86f5a8b71bf3784229258014b409b02510ce991e Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 23 Oct 2023 17:34:04 +0200
Subject: [PATCH 080/224] Rollup: use `preserveEntrySignatures =
'exports-only'` setting in lightweight build
This is the default setting and it ensures that the main chunk does not include
additional exports, which is is important when importing the module as `import *`
as shown in the readme.
In practice, this change does not affect the chunking with the current code.
---
rollup.config.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rollup.config.js b/rollup.config.js
index 1d723d6f8..d8091f787 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -98,7 +98,7 @@ export default Object.assign([
{ dir: 'dist/lightweight', entryFileNames: 'openpgp.mjs', chunkFileNames: chunkInfo => getChunkFileName(chunkInfo, 'mjs'), format: 'es', banner, intro },
{ dir: 'dist/lightweight', entryFileNames: 'openpgp.min.mjs', chunkFileNames: chunkInfo => getChunkFileName(chunkInfo, 'min.mjs'), format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
],
- preserveEntrySignatures: 'allow-extension',
+ preserveEntrySignatures: 'exports-only',
plugins: [
resolve({
browser: true
From 9a547b4553d5e469388243659b0b95322109a649 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 18 Oct 2023 19:32:11 +0200
Subject: [PATCH 081/224] Update rollup to v3
---
package-lock.json | 17 +++++++++--------
package.json | 2 +-
rollup.config.js | 14 +++++++-------
3 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index bff38d5e8..df83d7e48 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,7 +48,7 @@
"mocha": "^10.2.0",
"nyc": "^14.1.1",
"playwright": "^1.30.0",
- "rollup": "^2.79.1",
+ "rollup": "^3.29.4",
"sinon": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^4.1.2",
@@ -6140,15 +6140,16 @@
}
},
"node_modules/rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "version": "3.29.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+ "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
- "node": ">=10.0.0"
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
@@ -12236,9 +12237,9 @@
}
},
"rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "version": "3.29.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+ "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
"dev": true,
"requires": {
"fsevents": "~2.3.2"
diff --git a/package.json b/package.json
index 5befcbc04..98d3a89a5 100644
--- a/package.json
+++ b/package.json
@@ -98,7 +98,7 @@
"mocha": "^10.2.0",
"nyc": "^14.1.1",
"playwright": "^1.30.0",
- "rollup": "^2.79.1",
+ "rollup": "^3.29.4",
"sinon": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^4.1.2",
diff --git a/rollup.config.js b/rollup.config.js
index d8091f787..22a1b6c52 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,6 +1,7 @@
/* eslint-disable no-process-env */
import { builtinModules } from 'module';
+import { readFileSync } from 'fs';
import alias from '@rollup/plugin-alias';
import resolve from '@rollup/plugin-node-resolve';
@@ -9,7 +10,9 @@ import replace from '@rollup/plugin-replace';
import terser from '@rollup/plugin-terser';
import { wasm } from '@rollup/plugin-wasm';
-import pkg from './package.json';
+// ESlint does not support JSON module imports yet, see https://github.com/eslint/eslint/discussions/15305
+// import pkg from './package.json' assert { type: 'json' };
+const pkg = JSON.parse(readFileSync('./package.json'));
const nodeDependencies = Object.keys(pkg.dependencies);
const nodeBuiltinModules = builtinModules.concat(['module']);
@@ -55,8 +58,7 @@ export default Object.assign([
{ file: 'dist/openpgp.min.js', format: 'iife', name: pkg.name, banner, intro, plugins: [terser(terserOptions)], sourcemap: true },
{ file: 'dist/openpgp.mjs', format: 'es', banner, intro },
{ file: 'dist/openpgp.min.mjs', format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
- ],
- inlineDynamicImports: true,
+ ].map(options => ({ ...options, inlineDynamicImports: true })),
plugins: [
resolve({
browser: true
@@ -74,14 +76,13 @@ export default Object.assign([
},
{
input: 'src/index.js',
- inlineDynamicImports: true,
external: nodeBuiltinModules.concat(nodeDependencies),
output: [
{ file: 'dist/node/openpgp.cjs', format: 'cjs', name: pkg.name, banner, intro },
{ file: 'dist/node/openpgp.min.cjs', format: 'cjs', name: pkg.name, banner, intro, plugins: [terser(terserOptions)], sourcemap: true },
{ file: 'dist/node/openpgp.mjs', format: 'es', banner, intro },
{ file: 'dist/node/openpgp.min.mjs', format: 'es', banner, intro, plugins: [terser(terserOptions)], sourcemap: true }
- ],
+ ].map(options => ({ ...options, inlineDynamicImports: true })),
plugins: [
resolve(),
commonjs(),
@@ -117,9 +118,8 @@ export default Object.assign([
{
input: 'test/unittests.js',
output: [
- { file: 'test/lib/unittests-bundle.js', format: 'es', intro, sourcemap: true }
+ { file: 'test/lib/unittests-bundle.js', format: 'es', intro, sourcemap: true, inlineDynamicImports: true }
],
- inlineDynamicImports: true,
external: nodeBuiltinModules.concat(nodeDependencies),
plugins: [
alias({
From 690346a854f77c454725983f187651015f25b12c Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 11 Sep 2023 17:32:01 +0200
Subject: [PATCH 082/224] Refuse to use keys without key flags, add
`config.allowMissingKeyFlags`
Key flags are needed to restrict key usage to specific purposes:
https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-5.2.3.29 .
Some older keys (e.g. from OpenPGP.js v1) do not declare any key flags.
In previous OpenPGP.js versions, we've allowed such keys to be used for any operation for which they were compatible.
This behaviour has now changed, and these keys are not allowed to be used for any operation.
The setting `config.allowMissingKeyFlags` has been added to selectively revert to the past behaviour.
---
openpgp.d.ts | 1 +
src/config/config.js | 9 +++++-
src/key/helper.js | 61 +++++++++++++++++++++++++--------------
src/key/key.js | 6 ++--
test/general/key.js | 6 ++--
test/general/signature.js | 2 +-
6 files changed, 57 insertions(+), 28 deletions(-)
diff --git a/openpgp.d.ts b/openpgp.d.ts
index d50d8a493..2b5509b43 100644
--- a/openpgp.d.ts
+++ b/openpgp.d.ts
@@ -326,6 +326,7 @@ interface Config {
commentString: string;
allowInsecureDecryptionWithSigningKeys: boolean;
allowInsecureVerificationWithReformattedKeys: boolean;
+ allowMissingKeyFlags: boolean;
constantTimePKCS1Decryption: boolean;
constantTimePKCS1DecryptionSupportedSymmetricAlgorithms: Set;
v6Keys: boolean;
diff --git a/src/config/config.js b/src/config/config.js
index c03c0cadb..fe944d7aa 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -174,7 +174,14 @@ export default {
* @property {Boolean} allowInsecureDecryptionWithSigningKeys
*/
allowInsecureVerificationWithReformattedKeys: false,
-
+ /**
+ * Allow using keys that do not have any key flags set.
+ * Key flags are needed to restrict key usage to specific purposes: for instance, a signing key could only be allowed to certify other keys, and not sign messages
+ * (see https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-5.2.3.29).
+ * Some older keys do not declare any key flags, which means they are not allowed to be used for any operation.
+ * This setting allows using such keys for any operation for which they are compatible, based on their public key algorithm.
+ */
+ allowMissingKeyFlags: false,
/**
* Enable constant-time decryption of RSA- and ElGamal-encrypted session keys, to hinder Bleichenbacher-like attacks (https://link.springer.com/chapter/10.1007/BFb0055716).
* This setting has measurable performance impact and it is only helpful in application scenarios where both of the following conditions apply:
diff --git a/src/key/helper.js b/src/key/helper.js
index babaf3e6c..f2f48e383 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -357,32 +357,51 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
return options;
}
-export function isValidSigningKeyPacket(keyPacket, signature) {
- const keyAlgo = keyPacket.algorithm;
- return keyAlgo !== enums.publicKey.rsaEncrypt &&
- keyAlgo !== enums.publicKey.elgamal &&
- keyAlgo !== enums.publicKey.ecdh &&
- keyAlgo !== enums.publicKey.x25519 &&
- keyAlgo !== enums.publicKey.x448 &&
- (!signature.keyFlags ||
- (signature.keyFlags[0] & enums.keyFlags.signData) !== 0);
+export function isValidSigningKeyPacket(keyPacket, signature, config) {
+ switch (keyPacket.algorithm) {
+ case enums.publicKey.rsaEncryptSign:
+ case enums.publicKey.rsaSign:
+ case enums.publicKey.dsa:
+ case enums.publicKey.ecdsa:
+ case enums.publicKey.eddsaLegacy:
+ case enums.publicKey.ed25519:
+ case enums.publicKey.ed448: {
+ if (!signature.keyFlags && !config.allowMissingKeyFlags) {
+ throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`');
+ }
+
+ return !signature.keyFlags ||
+ (signature.keyFlags[0] & enums.keyFlags.signData) !== 0;
+ }
+ }
}
-export function isValidEncryptionKeyPacket(keyPacket, signature) {
- const keyAlgo = keyPacket.algorithm;
- return keyAlgo !== enums.publicKey.dsa &&
- keyAlgo !== enums.publicKey.rsaSign &&
- keyAlgo !== enums.publicKey.ecdsa &&
- keyAlgo !== enums.publicKey.eddsaLegacy &&
- keyAlgo !== enums.publicKey.ed25519 &&
- keyAlgo !== enums.publicKey.ed448 &&
- (!signature.keyFlags ||
- (signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
- (signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0);
+export function isValidEncryptionKeyPacket(keyPacket, signature, config) {
+ switch (keyPacket.algorithm) {
+ case enums.publicKey.rsaEncryptSign:
+ case enums.publicKey.rsaEncrypt:
+ case enums.publicKey.elgamal:
+ case enums.publicKey.ecdh:
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
+ if (!signature.keyFlags && !config.allowMissingKeyFlags) {
+ throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`');
+ }
+
+ return !signature.keyFlags ||
+ (signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
+ (signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0;
+ }
+ }
}
export function isValidDecryptionKeyPacket(signature, config) {
- if (config.allowInsecureDecryptionWithSigningKeys) {
+ if (!signature.keyFlags && !config.allowMissingKeyFlags) {
+ throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`');
+ }
+
+ const isValidSigningKeyPacket = !signature.keyFlags || (signature.keyFlags[0] & enums.keyFlags.signData) !== 0;
+ if (isValidSigningKeyPacket && config.allowInsecureDecryptionWithSigningKeys) {
// This is only relevant for RSA keys, all other signing algorithms cannot decrypt
return true;
}
diff --git a/src/key/key.js b/src/key/key.js
index 3b1ed8c2a..0349ae96c 100644
--- a/src/key/key.js
+++ b/src/key/key.js
@@ -269,7 +269,7 @@ class Key {
const bindingSignature = await helper.getLatestValidSignature(
subkey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config
);
- if (!helper.isValidSigningKeyPacket(subkey.keyPacket, bindingSignature)) {
+ if (!helper.isValidSigningKeyPacket(subkey.keyPacket, bindingSignature, config)) {
continue;
}
if (!bindingSignature.embeddedSignature) {
@@ -322,7 +322,7 @@ class Key {
await subkey.verify(date, config);
const dataToVerify = { key: primaryKey, bind: subkey.keyPacket };
const bindingSignature = await helper.getLatestValidSignature(subkey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
- if (helper.isValidEncryptionKeyPacket(subkey.keyPacket, bindingSignature)) {
+ if (helper.isValidEncryptionKeyPacket(subkey.keyPacket, bindingSignature, config)) {
helper.checkKeyRequirements(subkey.keyPacket, config);
return subkey;
}
@@ -336,7 +336,7 @@ class Key {
// if no valid subkey for encryption, evaluate primary key
const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
- helper.isValidEncryptionKeyPacket(primaryKey, selfCertification)) {
+ helper.isValidEncryptionKeyPacket(primaryKey, selfCertification, config)) {
helper.checkKeyRequirements(primaryKey, config);
return this;
}
diff --git a/test/general/key.js b/test/general/key.js
index f1ee51a19..341b95d8f 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -3402,7 +3402,7 @@ PzIEeL7UH3trraFmi+Gq8u4kAA==
expect(selfCertification.valid).to.be.true;
const certifyingKey = await openpgp.readKey({ armoredKey: certifying_key });
- const certifyingSigningKey = await certifyingKey.getSigningKey();
+ const certifyingSigningKey = await certifyingKey.getSigningKey(undefined, undefined, undefined, { ...openpgp.config, allowMissingKeyFlags: true });
const signatures = await pubKey.verifyPrimaryUser([certifyingKey]);
expect(signatures.length).to.equal(2);
expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
@@ -3411,7 +3411,9 @@ PzIEeL7UH3trraFmi+Gq8u4kAA==
expect(signatures[1].valid).to.be.false;
const { user } = await pubKey.getPrimaryUser();
- await expect(user.verifyCertificate(user.otherCertifications[0], [certifyingKey], undefined, openpgp.config)).to.be.rejectedWith('User certificate is revoked');
+ await expect(
+ user.verifyCertificate(user.otherCertifications[0], [certifyingKey], undefined, { ...openpgp.config, allowMissingKeyFlags: true })
+ ).to.be.rejectedWith('User certificate is revoked');
} finally {
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
}
diff --git a/test/general/signature.js b/test/general/signature.js
index 63ce14baf..01a3a0c03 100644
--- a/test/general/signature.js
+++ b/test/general/signature.js
@@ -2188,7 +2188,7 @@ uDvEBgD+LCEUOPejUTCMqPyd04ssdOq1AlMJOmUGUwLk7kFP7Aw=
const message = await openpgp.createMessage({ text: content });
await message.appendSignature(detachedSig);
- const { data, signatures } = await openpgp.verify({ verificationKeys:[publicKey], message, config: { minRSABits: 1024 } });
+ const { data, signatures } = await openpgp.verify({ verificationKeys:[publicKey], message, config: { minRSABits: 1024, allowMissingKeyFlags: true } });
expect(data).to.equal(content);
expect(signatures).to.have.length(1);
expect(await signatures[0].verified).to.be.true;
From 917faa56f55b7a3322a30c0451b4b1f6c3ae9aa0 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Mon, 18 Sep 2023 16:21:57 +0200
Subject: [PATCH 083/224] Rename internal functions, filter key algos on
decryption
---
src/key/helper.js | 45 ++++++++++++++++++++++++++----------------
src/key/key.js | 8 ++++----
src/key/private_key.js | 4 ++--
3 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/src/key/helper.js b/src/key/helper.js
index f2f48e383..d440cab20 100644
--- a/src/key/helper.js
+++ b/src/key/helper.js
@@ -357,7 +357,7 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
return options;
}
-export function isValidSigningKeyPacket(keyPacket, signature, config) {
+export function validateSigningKeyPacket(keyPacket, signature, config) {
switch (keyPacket.algorithm) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign:
@@ -365,50 +365,61 @@ export function isValidSigningKeyPacket(keyPacket, signature, config) {
case enums.publicKey.ecdsa:
case enums.publicKey.eddsaLegacy:
case enums.publicKey.ed25519:
- case enums.publicKey.ed448: {
+ case enums.publicKey.ed448:
if (!signature.keyFlags && !config.allowMissingKeyFlags) {
throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`');
}
-
return !signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.signData) !== 0;
- }
+ default:
+ return false;
}
}
-export function isValidEncryptionKeyPacket(keyPacket, signature, config) {
+export function validateEncryptionKeyPacket(keyPacket, signature, config) {
switch (keyPacket.algorithm) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt:
case enums.publicKey.elgamal:
case enums.publicKey.ecdh:
case enums.publicKey.x25519:
- case enums.publicKey.x448: {
+ case enums.publicKey.x448:
if (!signature.keyFlags && !config.allowMissingKeyFlags) {
throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`');
}
-
return !signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0;
- }
+ default:
+ return false;
}
}
-export function isValidDecryptionKeyPacket(signature, config) {
+export function validateDecryptionKeyPacket(keyPacket, signature, config) {
if (!signature.keyFlags && !config.allowMissingKeyFlags) {
throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`');
}
- const isValidSigningKeyPacket = !signature.keyFlags || (signature.keyFlags[0] & enums.keyFlags.signData) !== 0;
- if (isValidSigningKeyPacket && config.allowInsecureDecryptionWithSigningKeys) {
- // This is only relevant for RSA keys, all other signing algorithms cannot decrypt
- return true;
- }
+ switch (keyPacket.algorithm) {
+ case enums.publicKey.rsaEncryptSign:
+ case enums.publicKey.rsaEncrypt:
+ case enums.publicKey.elgamal:
+ case enums.publicKey.ecdh:
+ case enums.publicKey.x25519:
+ case enums.publicKey.x448: {
+ const isValidSigningKeyPacket = !signature.keyFlags || (signature.keyFlags[0] & enums.keyFlags.signData) !== 0;
+ if (isValidSigningKeyPacket && config.allowInsecureDecryptionWithSigningKeys) {
+ // This is only relevant for RSA keys, all other signing algorithms cannot decrypt
+ return true;
+ }
- return !signature.keyFlags ||
- (signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
- (signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0;
+ return !signature.keyFlags ||
+ (signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
+ (signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0;
+ }
+ default:
+ return false;
+ }
}
/**
diff --git a/src/key/key.js b/src/key/key.js
index 0349ae96c..43154a889 100644
--- a/src/key/key.js
+++ b/src/key/key.js
@@ -269,7 +269,7 @@ class Key {
const bindingSignature = await helper.getLatestValidSignature(
subkey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config
);
- if (!helper.isValidSigningKeyPacket(subkey.keyPacket, bindingSignature, config)) {
+ if (!helper.validateSigningKeyPacket(subkey.keyPacket, bindingSignature, config)) {
continue;
}
if (!bindingSignature.embeddedSignature) {
@@ -290,7 +290,7 @@ class Key {
try {
const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
- helper.isValidSigningKeyPacket(primaryKey, selfCertification, config)) {
+ helper.validateSigningKeyPacket(primaryKey, selfCertification, config)) {
helper.checkKeyRequirements(primaryKey, config);
return this;
}
@@ -322,7 +322,7 @@ class Key {
await subkey.verify(date, config);
const dataToVerify = { key: primaryKey, bind: subkey.keyPacket };
const bindingSignature = await helper.getLatestValidSignature(subkey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
- if (helper.isValidEncryptionKeyPacket(subkey.keyPacket, bindingSignature, config)) {
+ if (helper.validateEncryptionKeyPacket(subkey.keyPacket, bindingSignature, config)) {
helper.checkKeyRequirements(subkey.keyPacket, config);
return subkey;
}
@@ -336,7 +336,7 @@ class Key {
// if no valid subkey for encryption, evaluate primary key
const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
- helper.isValidEncryptionKeyPacket(primaryKey, selfCertification, config)) {
+ helper.validateEncryptionKeyPacket(primaryKey, selfCertification, config)) {
helper.checkKeyRequirements(primaryKey, config);
return this;
}
diff --git a/src/key/private_key.js b/src/key/private_key.js
index 9fe89ca99..3c6fe4741 100644
--- a/src/key/private_key.js
+++ b/src/key/private_key.js
@@ -85,7 +85,7 @@ class PrivateKey extends PublicKey {
try {
const dataToVerify = { key: primaryKey, bind: this.subkeys[i].keyPacket };
const bindingSignature = await helper.getLatestValidSignature(this.subkeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
- if (helper.isValidDecryptionKeyPacket(bindingSignature, config)) {
+ if (helper.validateDecryptionKeyPacket(this.subkeys[i].keyPacket, bindingSignature, config)) {
keys.push(this.subkeys[i]);
}
} catch (e) {}
@@ -95,7 +95,7 @@ class PrivateKey extends PublicKey {
// evaluate primary key
const selfCertification = await this.getPrimarySelfSignature(date, userID, config);
if ((!keyID || primaryKey.getKeyID().equals(keyID, true)) &&
- helper.isValidDecryptionKeyPacket(selfCertification, config)) {
+ helper.validateDecryptionKeyPacket(primaryKey, selfCertification, config)) {
keys.push(this);
}
From 30635c72e8862e89278accf917cdb0b2ec974890 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Thu, 19 Oct 2023 15:04:41 +0200
Subject: [PATCH 084/224] Lint: error on unnecessary switch-case braces
Also fix some indent issues with armoring code detected after required ESLint update.
s
---
.eslintrc.cjs | 4 +-
package-lock.json | 1109 ++++++++++++-----
package.json | 1 +
src/crypto/crypto.js | 3 +-
src/crypto/public_key/elliptic/ecdh.js | 7 +-
src/crypto/public_key/elliptic/ecdsa.js | 3 +-
src/crypto/public_key/elliptic/eddsa.js | 3 +-
src/crypto/public_key/elliptic/oid_curves.js | 3 +-
src/crypto/signature.js | 3 +-
src/encoding/armor.js | 12 +-
.../public_key_encrypted_session_key.js | 3 +-
11 files changed, 785 insertions(+), 366 deletions(-)
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 7d077cba4..2dd0f1c46 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -13,7 +13,8 @@ module.exports = {
'plugins': [
'chai-friendly',
- 'import'
+ 'import',
+ 'unicorn'
],
'globals': { // TODO are all these necessary?
@@ -118,6 +119,7 @@ module.exports = {
'max-lines': [2, { 'max': 620, 'skipBlankLines': true, 'skipComments': true }],
'no-unused-expressions': 0,
'chai-friendly/no-unused-expressions': [2, { 'allowShortCircuit': true }],
+ 'unicorn/switch-case-braces': ['error', 'avoid'],
// Custom warnings:
'no-console': 1
diff --git a/package-lock.json b/package-lock.json
index df83d7e48..1c9d18f1a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -36,6 +36,7 @@
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
+ "eslint-plugin-unicorn": "^48.0.1",
"fflate": "^0.7.4",
"http-server": "^14.1.1",
"karma": "^6.4.0",
@@ -58,6 +59,15 @@
"node": ">= 16.0.0"
}
},
+ "node_modules/@aashutoshrathi/word-wrap": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
@@ -141,9 +151,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -336,15 +346,39 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz",
+ "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
"node_modules/@eslint/eslintrc": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
- "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+ "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
- "espree": "^9.4.0",
+ "espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
@@ -383,9 +417,9 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "version": "13.23.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
+ "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -415,10 +449,19 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "node_modules/@eslint/js": {
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
+ "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.8",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
- "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
+ "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"dev": true,
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.1",
@@ -791,18 +834,6 @@
}
}
},
- "node_modules/@rollup/plugin-node-resolve/node_modules/builtin-modules": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
- "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/@rollup/plugin-node-resolve/node_modules/is-builtin-module": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
@@ -1053,6 +1084,12 @@
"integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==",
"dev": true
},
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz",
+ "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==",
+ "dev": true
+ },
"node_modules/@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
@@ -1073,9 +1110,9 @@
}
},
"node_modules/acorn": {
- "version": "8.8.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
- "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "version": "8.10.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+ "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
@@ -1551,12 +1588,15 @@
"dev": true
},
"node_modules/builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"dev": true,
"engines": {
- "node": ">=0.10.0"
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/bytes": {
@@ -1734,6 +1774,18 @@
"node": ">=8"
}
},
+ "node_modules/clean-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz",
+ "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -2304,49 +2356,47 @@
}
},
"node_modules/eslint": {
- "version": "8.34.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz",
- "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==",
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
+ "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
"dev": true,
"dependencies": {
- "@eslint/eslintrc": "^1.4.1",
- "@humanwhocodes/config-array": "^0.11.8",
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.2",
+ "@eslint/js": "8.51.0",
+ "@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
- "ajv": "^6.10.0",
+ "ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.1.1",
- "eslint-utils": "^3.0.0",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.4.0",
- "esquery": "^1.4.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"globals": "^13.19.0",
- "grapheme-splitter": "^1.0.4",
+ "graphemer": "^1.4.0",
"ignore": "^5.2.0",
- "import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
- "js-sdsl": "^4.1.4",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "regexpp": "^3.2.0",
+ "optionator": "^0.9.3",
"strip-ansi": "^6.0.1",
- "strip-json-comments": "^3.1.0",
"text-table": "^0.2.0"
},
"bin": {
@@ -2646,46 +2696,108 @@
"semver": "bin/semver.js"
}
},
- "node_modules/eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+ "node_modules/eslint-plugin-unicorn": {
+ "version": "48.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz",
+ "integrity": "sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==",
"dev": true,
"dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
+ "@babel/helper-validator-identifier": "^7.22.5",
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "ci-info": "^3.8.0",
+ "clean-regexp": "^1.0.0",
+ "esquery": "^1.5.0",
+ "indent-string": "^4.0.0",
+ "is-builtin-module": "^3.2.1",
+ "jsesc": "^3.0.2",
+ "lodash": "^4.17.21",
+ "pluralize": "^8.0.0",
+ "read-pkg-up": "^7.0.1",
+ "regexp-tree": "^0.1.27",
+ "regjsparser": "^0.10.0",
+ "semver": "^7.5.4",
+ "strip-indent": "^3.0.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1"
+ },
+ "peerDependencies": {
+ "eslint": ">=8.44.0"
}
},
- "node_modules/eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "node_modules/eslint-plugin-unicorn/node_modules/is-builtin-module": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
"dev": true,
"dependencies": {
- "eslint-visitor-keys": "^2.0.0"
+ "builtin-modules": "^3.3.0"
},
"engines": {
- "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ "node": ">=6"
},
"funding": {
- "url": "https://github.com/sponsors/mysticatea"
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint-plugin-unicorn/node_modules/jsesc": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
+ "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
},
- "peerDependencies": {
- "eslint": ">=5"
+ "engines": {
+ "node": ">=6"
}
},
- "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "node_modules/eslint-plugin-unicorn/node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
"engines": {
"node": ">=10"
}
},
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/eslint/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -2733,15 +2845,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/eslint/node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
"node_modules/eslint/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -2788,14 +2891,14 @@
"dev": true
},
"node_modules/espree": {
- "version": "9.4.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
- "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"dependencies": {
- "acorn": "^8.8.0",
+ "acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
+ "eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -2804,15 +2907,6 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -2827,9 +2921,9 @@
}
},
"node_modules/esquery": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
- "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true,
"dependencies": {
"estraverse": "^5.1.0"
@@ -3054,15 +3148,6 @@
"node": ">=6"
}
},
- "node_modules/find-cache-dir/node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/find-cache-dir/node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -3361,10 +3446,10 @@
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"dev": true
},
- "node_modules/grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
"node_modules/has": {
@@ -3618,6 +3703,15 @@
"node": ">=0.8.19"
}
},
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -3693,18 +3787,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-builtin-module": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
- "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
- "dev": true,
- "dependencies": {
- "builtin-modules": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -4142,16 +4224,6 @@
"node": ">=6"
}
},
- "node_modules/js-sdsl": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
- "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
- "dev": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/js-sdsl"
- }
- },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -4198,6 +4270,12 @@
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -4605,6 +4683,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
"node_modules/linkify-it": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
@@ -4764,6 +4848,24 @@
"get-func-name": "^2.0.0"
}
},
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lru-cache/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
"node_modules/magic-string": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
@@ -4920,6 +5022,15 @@
"node": ">= 0.6"
}
},
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/minimalistic-assert": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
@@ -5323,13 +5434,13 @@
}
},
"node_modules/normalize-package-data": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
- "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"dependencies": {
"hosted-git-info": "^2.1.4",
- "is-builtin-module": "^1.0.0",
+ "resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
@@ -5434,15 +5545,6 @@
"node": ">=6"
}
},
- "node_modules/nyc/node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/nyc/node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -5603,17 +5705,17 @@
}
},
"node_modules/optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+ "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
"dev": true,
"dependencies": {
+ "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
+ "type-check": "^0.4.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -5658,6 +5760,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/package-hash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz",
@@ -5691,6 +5802,24 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -5806,6 +5935,15 @@
"node": ">=14"
}
},
+ "node_modules/pluralize": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
+ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -5970,27 +6108,129 @@
"unpipe": "1.0.0"
},
"engines": {
- "node": ">= 0.8"
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/raw-body/node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "dependencies": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
}
},
- "node_modules/raw-body/node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "node_modules/read-pkg-up/node_modules/type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true,
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=8"
}
},
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "node_modules/read-pkg/node_modules/type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
"dev": true,
- "peer": true
+ "engines": {
+ "node": ">=8"
+ }
},
"node_modules/readdirp": {
"version": "3.6.0",
@@ -6011,6 +6251,15 @@
"dev": true,
"peer": true
},
+ "node_modules/regexp-tree": {
+ "version": "0.1.27",
+ "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
+ "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==",
+ "dev": true,
+ "bin": {
+ "regexp-tree": "bin/regexp-tree"
+ }
+ },
"node_modules/regexp.prototype.flags": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@@ -6028,16 +6277,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "node_modules/regjsparser": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz",
+ "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==",
"dev": true,
- "engines": {
- "node": ">=8"
+ "dependencies": {
+ "jsesc": "~0.5.0"
},
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
}
},
"node_modules/release-zalgo": {
@@ -6648,6 +6906,18 @@
"node": ">=4"
}
},
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -6829,15 +7099,6 @@
"node": ">=6"
}
},
- "node_modules/test-exclude/node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/test-exclude/node_modules/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
@@ -7272,15 +7533,6 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
- "node_modules/word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/workerpool": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
@@ -7498,15 +7750,6 @@
"node": ">=6"
}
},
- "node_modules/yargs/node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/yargs/node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -7539,6 +7782,12 @@
}
},
"dependencies": {
+ "@aashutoshrathi/word-wrap": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "dev": true
+ },
"@babel/code-frame": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
@@ -7601,9 +7850,9 @@
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/highlight": {
@@ -7759,15 +8008,30 @@
}
}
},
+ "@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
+ "@eslint-community/regexpp": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz",
+ "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==",
+ "dev": true
+ },
"@eslint/eslintrc": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
- "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+ "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
- "espree": "^9.4.0",
+ "espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
@@ -7792,9 +8056,9 @@
}
},
"globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "version": "13.23.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
+ "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
@@ -7817,10 +8081,16 @@
}
}
},
+ "@eslint/js": {
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
+ "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
+ "dev": true
+ },
"@humanwhocodes/config-array": {
- "version": "0.11.8",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
- "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
+ "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"dev": true,
"requires": {
"@humanwhocodes/object-schema": "^1.2.1",
@@ -8086,12 +8356,6 @@
"resolve": "^1.22.1"
},
"dependencies": {
- "builtin-modules": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
- "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
- "dev": true
- },
"is-builtin-module": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
@@ -8299,6 +8563,12 @@
"integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==",
"dev": true
},
+ "@types/normalize-package-data": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz",
+ "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==",
+ "dev": true
+ },
"@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
@@ -8316,9 +8586,9 @@
}
},
"acorn": {
- "version": "8.8.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
- "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "version": "8.10.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+ "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true
},
"acorn-jsx": {
@@ -8696,9 +8966,9 @@
"dev": true
},
"builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"dev": true
},
"bytes": {
@@ -8825,6 +9095,15 @@
"integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
"dev": true
},
+ "clean-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz",
+ "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -9291,49 +9570,47 @@
"dev": true
},
"eslint": {
- "version": "8.34.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz",
- "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==",
+ "version": "8.51.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
+ "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
"dev": true,
"requires": {
- "@eslint/eslintrc": "^1.4.1",
- "@humanwhocodes/config-array": "^0.11.8",
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.2",
+ "@eslint/js": "8.51.0",
+ "@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
- "ajv": "^6.10.0",
+ "ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.1.1",
- "eslint-utils": "^3.0.0",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.4.0",
- "esquery": "^1.4.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"globals": "^13.19.0",
- "grapheme-splitter": "^1.0.4",
+ "graphemer": "^1.4.0",
"ignore": "^5.2.0",
- "import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
- "js-sdsl": "^4.1.4",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "regexpp": "^3.2.0",
+ "optionator": "^0.9.3",
"strip-ansi": "^6.0.1",
- "strip-json-comments": "^3.1.0",
"text-table": "^0.2.0"
},
"dependencies": {
@@ -9367,12 +9644,6 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
- "eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true
- },
"glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -9636,50 +9907,80 @@
"peer": true,
"requires": {}
},
- "eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
- "dev": true,
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- }
- },
- "eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "eslint-plugin-unicorn": {
+ "version": "48.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz",
+ "integrity": "sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==",
"dev": true,
"requires": {
- "eslint-visitor-keys": "^2.0.0"
+ "@babel/helper-validator-identifier": "^7.22.5",
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "ci-info": "^3.8.0",
+ "clean-regexp": "^1.0.0",
+ "esquery": "^1.5.0",
+ "indent-string": "^4.0.0",
+ "is-builtin-module": "^3.2.1",
+ "jsesc": "^3.0.2",
+ "lodash": "^4.17.21",
+ "pluralize": "^8.0.0",
+ "read-pkg-up": "^7.0.1",
+ "regexp-tree": "^0.1.27",
+ "regjsparser": "^0.10.0",
+ "semver": "^7.5.4",
+ "strip-indent": "^3.0.0"
},
"dependencies": {
- "eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "is-builtin-module": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+ "dev": true,
+ "requires": {
+ "builtin-modules": "^3.3.0"
+ }
+ },
+ "jsesc": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
+ "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
"dev": true
+ },
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
}
}
},
+ "eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true
+ },
"espree": {
- "version": "9.4.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
- "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"requires": {
- "acorn": "^8.8.0",
+ "acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true
- }
+ "eslint-visitor-keys": "^3.4.1"
}
},
"esprima": {
@@ -9689,9 +9990,9 @@
"dev": true
},
"esquery": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
- "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
@@ -9876,12 +10177,6 @@
"p-limit": "^2.0.0"
}
},
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -10105,10 +10400,10 @@
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"dev": true
},
- "grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
"has": {
@@ -10302,6 +10597,12 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -10362,15 +10663,6 @@
"has-tostringtag": "^1.0.0"
}
},
- "is-builtin-module": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
- "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
- "dev": true,
- "requires": {
- "builtin-modules": "^1.0.0"
- }
- },
"is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -10684,12 +10976,6 @@
"html-escaper": "^2.0.0"
}
},
- "js-sdsl": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
- "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
- "dev": true
- },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -10727,6 +11013,12 @@
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
+ "json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -11063,6 +11355,12 @@
"type-check": "~0.4.0"
}
},
+ "lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
"linkify-it": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
@@ -11194,6 +11492,23 @@
"get-func-name": "^2.0.0"
}
},
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ }
+ }
+ },
"magic-string": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
@@ -11317,6 +11632,12 @@
"mime-db": "1.51.0"
}
},
+ "min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true
+ },
"minimalistic-assert": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
@@ -11633,13 +11954,13 @@
}
},
"normalize-package-data": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
- "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
- "is-builtin-module": "^1.0.0",
+ "resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
@@ -11720,12 +12041,6 @@
"p-limit": "^2.0.0"
}
},
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -11843,17 +12158,17 @@
"dev": true
},
"optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+ "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
"dev": true,
"requires": {
+ "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
+ "type-check": "^0.4.0"
}
},
"os-homedir": {
@@ -11880,6 +12195,12 @@
"p-limit": "^3.0.2"
}
},
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
"package-hash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz",
@@ -11909,6 +12230,18 @@
"callsites": "^3.0.0"
}
},
+ "parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -11990,6 +12323,12 @@
"integrity": "sha512-7AnRmTCf+GVYhHbLJsGUtskWTE33SwMZkybJ0v6rqR1boxq2x36U7p1vDRV7HO2IwTZgmycracLxPEJI49wu4g==",
"dev": true
},
+ "pluralize": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
+ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
+ "dev": true
+ },
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -12129,6 +12468,82 @@
"dev": true,
"peer": true
},
+ "read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "requires": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ }
+ }
+ },
"readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -12145,6 +12560,12 @@
"dev": true,
"peer": true
},
+ "regexp-tree": {
+ "version": "0.1.27",
+ "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
+ "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==",
+ "dev": true
+ },
"regexp.prototype.flags": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@@ -12156,11 +12577,22 @@
"functions-have-names": "^1.2.2"
}
},
- "regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true
+ "regjsparser": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz",
+ "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==",
+ "dev": true,
+ "requires": {
+ "jsesc": "~0.5.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+ "dev": true
+ }
+ }
},
"release-zalgo": {
"version": "1.0.0",
@@ -12639,6 +13071,15 @@
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true
},
+ "strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "requires": {
+ "min-indent": "^1.0.0"
+ }
+ },
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -12775,12 +13216,6 @@
"p-limit": "^2.0.0"
}
},
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
@@ -13097,12 +13532,6 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
- "word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "dev": true
- },
"workerpool": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
@@ -13232,12 +13661,6 @@
"p-limit": "^2.0.0"
}
},
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
diff --git a/package.json b/package.json
index 98d3a89a5..cd04fb7a4 100644
--- a/package.json
+++ b/package.json
@@ -86,6 +86,7 @@
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
+ "eslint-plugin-unicorn": "^48.0.1",
"fflate": "^0.7.4",
"http-server": "^14.1.1",
"karma": "^6.4.0",
diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js
index 2576bd882..f24c4a74f 100644
--- a/src/crypto/crypto.js
+++ b/src/crypto/crypto.js
@@ -331,12 +331,11 @@ export function generateParams(algo, bits, oid) {
switch (algo) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign:
- case enums.publicKey.rsaSign: {
+ case enums.publicKey.rsaSign:
return publicKey.rsa.generate(bits, 65537).then(({ n, e, d, p, q, u }) => ({
privateParams: { d, p, q, u },
publicParams: { n, e }
}));
- }
case enums.publicKey.ecdsa:
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret }) => ({
privateParams: { d: secret },
diff --git a/src/crypto/public_key/elliptic/ecdh.js b/src/crypto/public_key/elliptic/ecdh.js
index 3ea593d72..7d749d635 100644
--- a/src/crypto/public_key/elliptic/ecdh.js
+++ b/src/crypto/public_key/elliptic/ecdh.js
@@ -110,9 +110,9 @@ async function genPublicEphemeralKey(curve, Q) {
break;
case 'node':
return nodePublicEphemeralKey(curve, Q);
- default: {
+ default:
return jsPublicEphemeralKey(curve, Q);
- }
+
}
}
@@ -173,9 +173,8 @@ async function genPrivateEphemeralKey(curve, V, Q, d) {
break;
case 'node':
return nodePrivateEphemeralKey(curve, V, d);
- default: {
+ default:
return jsPrivateEphemeralKey(curve, V, d);
- }
}
}
diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js
index b90bed2b3..8c186d46b 100644
--- a/src/crypto/public_key/elliptic/ecdsa.js
+++ b/src/crypto/public_key/elliptic/ecdsa.js
@@ -48,7 +48,7 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
if (message && !util.isStream(message)) {
const keyPair = { publicKey, privateKey };
switch (curve.type) {
- case 'web': {
+ case 'web':
// If browser doesn't support a curve, we'll catch it
try {
// Need to await to make sure browser succeeds
@@ -63,7 +63,6 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed
util.printDebugError('Browser did not support signing: ' + err.message);
}
break;
- }
case 'node': {
const signature = await nodeSign(curve, hashAlgo, message, keyPair);
return {
diff --git a/src/crypto/public_key/elliptic/eddsa.js b/src/crypto/public_key/elliptic/eddsa.js
index c13665ea8..1e6aac2fe 100644
--- a/src/crypto/public_key/elliptic/eddsa.js
+++ b/src/crypto/public_key/elliptic/eddsa.js
@@ -100,9 +100,8 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
throw new Error('Hash algorithm too weak for EdDSA.');
}
switch (algo) {
- case enums.publicKey.ed25519: {
+ case enums.publicKey.ed25519:
return ed25519.sign.detached.verify(hashed, RS, publicKey);
- }
case enums.publicKey.ed448: {
const ed448 = await util.getNobleCurve(enums.publicKey.ed448);
return ed448.verify(RS, hashed, publicKey);
diff --git a/src/crypto/public_key/elliptic/oid_curves.js b/src/crypto/public_key/elliptic/oid_curves.js
index 75c238274..57bcc4df4 100644
--- a/src/crypto/public_key/elliptic/oid_curves.js
+++ b/src/crypto/public_key/elliptic/oid_curves.js
@@ -192,9 +192,8 @@ class CurveWithOID {
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
return { publicKey, privateKey };
}
- default: {
+ default:
return jsGenKeyPair(this.name);
- }
}
}
}
diff --git a/src/crypto/signature.js b/src/crypto/signature.js
index 5f0ceeabe..d9574ad1a 100644
--- a/src/crypto/signature.js
+++ b/src/crypto/signature.js
@@ -153,9 +153,8 @@ export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, da
const { x } = privateKeyParams;
return publicKey.dsa.sign(hashAlgo, hashed, g, p, q, x);
}
- case enums.publicKey.elgamal: {
+ case enums.publicKey.elgamal:
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
- }
case enums.publicKey.ecdsa: {
const { oid, Q } = publicKeyParams;
const { d } = privateKeyParams;
diff --git a/src/encoding/armor.js b/src/encoding/armor.js
index 2177683f4..8686d1315 100644
--- a/src/encoding/armor.js
+++ b/src/encoding/armor.js
@@ -47,33 +47,33 @@ function getType(text) {
// parts, and this is the Xth part out of Y.
if (/MESSAGE, PART \d+\/\d+/.test(header[1])) {
return enums.armor.multipartSection;
- } else
+ }
// BEGIN PGP MESSAGE, PART X
// Used for multi-part messages, where this is the Xth part of an
// unspecified number of parts. Requires the MESSAGE-ID Armor
// Header to be used.
if (/MESSAGE, PART \d+/.test(header[1])) {
return enums.armor.multipartLast;
- } else
+ }
// BEGIN PGP SIGNED MESSAGE
if (/SIGNED MESSAGE/.test(header[1])) {
return enums.armor.signed;
- } else
+ }
// BEGIN PGP MESSAGE
// Used for signed, encrypted, or compressed files.
if (/MESSAGE/.test(header[1])) {
return enums.armor.message;
- } else
+ }
// BEGIN PGP PUBLIC KEY BLOCK
// Used for armoring public keys.
if (/PUBLIC KEY BLOCK/.test(header[1])) {
return enums.armor.publicKey;
- } else
+ }
// BEGIN PGP PRIVATE KEY BLOCK
// Used for armoring private keys.
if (/PRIVATE KEY BLOCK/.test(header[1])) {
return enums.armor.privateKey;
- } else
+ }
// BEGIN PGP SIGNATURE
// Used for detached signatures, OpenPGP/MIME signatures, and
// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js
index 2618ce321..1f6c1d04e 100644
--- a/src/packet/public_key_encrypted_session_key.js
+++ b/src/packet/public_key_encrypted_session_key.js
@@ -218,14 +218,13 @@ function encodeSessionKey(version, keyAlgo, cipherAlgo, sessionKeyData) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.elgamal:
- case enums.publicKey.ecdh: {
+ case enums.publicKey.ecdh:
// add checksum
return util.concatUint8Array([
new Uint8Array(version === 6 ? [] : [cipherAlgo]),
sessionKeyData,
util.writeChecksum(sessionKeyData.subarray(sessionKeyData.length % 8))
]);
- }
case enums.publicKey.x25519:
case enums.publicKey.x448:
return sessionKeyData;
From 0da131cd9aa7791d64f9c2507cb845d819a2fbc0 Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Tue, 24 Oct 2023 17:19:10 +0200
Subject: [PATCH 085/224] Update README
---
README.md | 48 +++++++++++++++++++++++-------------------------
1 file changed, 23 insertions(+), 25 deletions(-)
diff --git a/README.md b/README.md
index 030ff8004..72e5bf2f7 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
OpenPGP.js [](https://automate.browserstack.com/public-build/N1l2eHFOanVBMU9wYWxJM3ZnWERnc1lidkt5UkRqa3BralV3SWVhOGpGTT0tLVljSjE4Z3dzVmdiQjl6RWgxb2c3T2c9PQ==--5864052cd523f751b6b907d547ac9c4c5f88c8a3) [](https://gitter.im/openpgpjs/openpgpjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
==========
-[OpenPGP.js](https://openpgpjs.org/) is a JavaScript implementation of the OpenPGP protocol. It implements [RFC4880](https://tools.ietf.org/html/rfc4880) and parts of [RFC4880bis](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10).
+[OpenPGP.js](https://openpgpjs.org/) is a JavaScript implementation of the OpenPGP protocol. It implements the [crypto-refresh](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh) (superseding [RFC4880](https://tools.ietf.org/html/rfc4880) and [RFC4880bis](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10)).
**Table of Contents**
@@ -33,22 +33,22 @@ OpenPGP.js [ bundle works with recent versions of Chrome, Firefox, Edge and Safari 13+.
-* The `dist/node/openpgp.min.js` bundle works well in Node.js. It is used by default when you `require('openpgp')` in Node.js.
+* The `dist/node/openpgp.min.mjs` (or `.cjs`) bundle works in Node.js v16+: it is used by default when you `import ... from 'openpgp'` (resp. `require('openpgp')`).
-* Currently, Chrome, Safari and Edge have partial implementations of the
-[Streams specification](https://streams.spec.whatwg.org/), and Firefox
-has a partial implementation behind feature flags. Chrome is the only
-browser that implements `TransformStream`s, which we need, so we include
-a [polyfill](https://github.com/MattiasBuelens/web-streams-polyfill) for
-all other browsers. Please note that in those browsers, the global
-`ReadableStream` property gets overwritten with the polyfill version if
-it exists. In some edge cases, you might need to use the native
+* Streaming support: the latest versions of Chrome, Firefox, Edge and Safari implement the
+[Streams specification](https://streams.spec.whatwg.org/), including `TransformStream`s.
+These are needed if you use the library with streamed inputs.
+In previous versions of OpenPGP.js, WebStreams were automatically polyfilled by the library,
+but from v6 this task is left up to the library user, due to the more extensive browser support, and the
+polyfilling side-effects. If you're working with [older browsers versions which do not implement e.g. TransformStreams](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream), you can manually
+load [WebStream polyfill](https://github.com/MattiasBuelens/web-streams-polyfills).
+Please note that when you load the polyfills, the global `ReadableStream` property (if it exists) gets overwritten with the polyfill version.
+In some edge cases, you might need to use the native
`ReadableStream` (for example when using it to create a `Response`
object), in which case you should store a reference to it before loading
-OpenPGP.js. There is also the
-[web-streams-adapter](https://github.com/MattiasBuelens/web-streams-adapter)
+the polyfills. There is also the [web-streams-adapter](https://github.com/MattiasBuelens/web-streams-adapter)
library to convert back and forth between them.
### Performance
@@ -71,21 +71,20 @@ library to convert back and forth between them.
\** the curve25519 and ed25519 implementations are algorithmically constant-time, but may not be constant-time after optimizations of the JavaScript compiler
\*** these curves are only constant-time if the underlying native implementation is available and constant-time
-* Version 2.x of the library has been built from the ground up with Uint8Arrays. This allows for much better performance and memory usage than strings.
-
* If the user's browser supports [native WebCrypto](https://caniuse.com/#feat=cryptography) via the `window.crypto.subtle` API, this will be used. Under Node.js the native [crypto module](https://nodejs.org/api/crypto.html#crypto_crypto) is used.
-* The library implements the [IETF proposal](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10) for authenticated encryption using native AES-EAX, OCB, or GCM. This makes symmetric encryption up to 30x faster on supported platforms. Since the specification has not been finalized and other OpenPGP implementations haven't adopted it yet, the feature is currently behind a flag. **Note: activating this setting can break compatibility with other OpenPGP implementations, and also with future versions of OpenPGP.js. Don't use it with messages you want to store on disk or in a database.** You can enable it by setting `openpgp.config.aeadProtect = true`.
+* The library implements authenticated encryption (AEAD) as per the ["crypto refresh" draft standard](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh) using AES-OCB, EAX, or GCM. This makes symmetric encryption faster on platforms with native implementations. However, since the specification is very recent and other OpenPGP implementations are in the process of adopting it, the feature is currently behind a flag. **Note: activating this setting can break compatibility with other OpenPGP implementations which have yet to implement the feature.** You can enable it by setting `openpgp.config.aeadProtect = true`.
+Note that this setting has a different effect from the one in OpenPGP.js v5, which implemented support for a provisional version of AEAD from [RFC4880bis](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10), which was modified in a later draft of the crypto refresh.
You can change the AEAD mode by setting one of the following options:
```
- openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax // Default, native
- openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb // Non-native
- openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM // **Non-standard**, fastest
+ openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb; // Default (widest ecosystem support), non-native
+ openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.gcm; // Native in WebCrypto and Node.js
+ openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax; // Native in Node.js
```
-* For environments that don't provide native crypto, the library falls back to [asm.js](https://caniuse.com/#feat=asmjs) implementations of AES, SHA-1, and SHA-256.
+* For environments that don't provide native crypto, the library falls back to [asm.js](https://caniuse.com/#feat=asmjs) AES and AEAD implementations.
### Getting started
@@ -98,16 +97,15 @@ Install OpenPGP.js using npm and save it in your dependencies:
npm install --save openpgp
```
-And import it as a CommonJS module:
-
+And import it as an ES module, from a .mjs file:
```js
-const openpgp = require('openpgp');
+import * as openpgp from 'openpgp';
```
-Or as an ES6 module, from an .mjs file:
+Or as a CommonJS module:
```js
-import * as openpgp from 'openpgp';
+const openpgp = require('openpgp');
```
#### Deno (experimental)
From 7881b850ec303df735acff4614aa4dd31663a5ad Mon Sep 17 00:00:00 2001
From: larabr <7375870+larabr@users.noreply.github.com>
Date: Wed, 25 Oct 2023 12:55:43 +0200
Subject: [PATCH 086/224] 6.0.0-alpha.0
---
docs/AEADEncryptedDataPacket.html | 227 +-
docs/Argon2S2K.html | 986 +++
docs/CleartextMessage.html | 16 +-
docs/CompressedDataPacket.html | 22 +-
docs/Key.html | 300 +-
docs/LiteralDataPacket.html | 24 +-
docs/MarkerPacket.html | 8 +-
docs/Message.html | 79 +-
docs/OnePassSignaturePacket.html | 154 +-
docs/PacketList.html | 18 +-
docs/PaddingPacket.html | 600 ++
docs/PrivateKey.html | 36 +-
docs/PublicKey.html | 12 +-
docs/PublicKeyEncryptedSessionKeyPacket.html | 18 +-
docs/PublicKeyPacket.html | 50 +-
docs/PublicSubkeyPacket.html | 50 +-
docs/SecretKeyPacket.html | 76 +-
docs/SecretSubkeyPacket.html | 76 +-
docs/Signature.html | 12 +-
docs/SignaturePacket.html | 28 +-
...EncryptedIntegrityProtectedDataPacket.html | 154 +-
docs/SymEncryptedSessionKeyPacket.html | 20 +-
docs/SymmetricallyEncryptedDataPacket.html | 14 +-
docs/TrustPacket.html | 8 +-
docs/UserAttributePacket.html | 12 +-
docs/UserIDPacket.html | 14 +-
docs/global.html | 1247 +++-
docs/index.html | 52 +-
docs/module-config.html | 462 +-
docs/module-crypto.html | 184 +
docs/module-crypto_aes_kw.html | 553 ++
docs/module-crypto_cipher.html | 1430 ++++
docs/module-crypto_cmac.html | 413 ++
docs/module-crypto_crypto.html | 3000 ++++++++
docs/module-crypto_hash.html | 596 ++
docs/module-crypto_hkdf.html | 167 +
docs/module-crypto_mode.html | 439 ++
docs/module-crypto_mode_cfb.html | 548 ++
docs/module-crypto_mode_eax.html | 748 ++
docs/module-crypto_mode_gcm.html | 334 +
docs/module-crypto_mode_ocb.html | 747 ++
docs/module-crypto_pkcs1.html | 882 +++
docs/module-crypto_public_key.html | 439 ++
docs/module-crypto_public_key_dsa.html | 1084 +++
docs/module-crypto_public_key_elgamal.html | 981 +++
docs/module-crypto_public_key_elliptic.html | 180 +
...dule-crypto_public_key_elliptic_curve.html | 1149 ++++
...odule-crypto_public_key_elliptic_ecdh.html | 6011 +++++++++++++++++
...dule-crypto_public_key_elliptic_ecdsa.html | 1017 +++
...dule-crypto_public_key_elliptic_eddsa.html | 1106 +++
...ypto_public_key_elliptic_eddsa_legacy.html | 927 +++
docs/module-crypto_public_key_prime.html | 954 +++
docs/module-crypto_public_key_rsa.html | 2279 +++++++
docs/module-crypto_random.html | 516 ++
docs/module-crypto_signature.html | 917 +++
docs/module-encoding_base64.html | 769 +++
docs/module-enums.html | 272 +-
docs/module-key_Subkey-Subkey.html | 47 +-
docs/module-key_Subkey.html | 92 +
docs/module-key_User-User.html | 27 +-
docs/module-key_User.html | 92 +
docs/module-key_helper.html | 2867 ++++++++
docs/module-packet_packet.html | 866 +++
docs/module-type_ecdh_symkey.html | 167 +
docs/module-type_kdf_params-KDFParams.html | 10 +-
docs/module-type_keyid-KeyID.html | 21 +-
docs/module-type_keyid.html | 92 +
docs/module-type_oid.html | 178 +
...K.html => module-type_s2k-GenericS2K.html} | 29 +-
docs/module-type_s2k.html | 180 +
docs/module-type_x25519x448_symkey.html | 6 +-
docs/module-util.html | 167 +
package-lock.json | 4 +-
package.json | 2 +-
74 files changed, 37225 insertions(+), 1039 deletions(-)
create mode 100644 docs/Argon2S2K.html
create mode 100644 docs/PaddingPacket.html
create mode 100644 docs/module-crypto.html
create mode 100644 docs/module-crypto_aes_kw.html
create mode 100644 docs/module-crypto_cipher.html
create mode 100644 docs/module-crypto_cmac.html
create mode 100644 docs/module-crypto_crypto.html
create mode 100644 docs/module-crypto_hash.html
create mode 100644 docs/module-crypto_hkdf.html
create mode 100644 docs/module-crypto_mode.html
create mode 100644 docs/module-crypto_mode_cfb.html
create mode 100644 docs/module-crypto_mode_eax.html
create mode 100644 docs/module-crypto_mode_gcm.html
create mode 100644 docs/module-crypto_mode_ocb.html
create mode 100644 docs/module-crypto_pkcs1.html
create mode 100644 docs/module-crypto_public_key.html
create mode 100644 docs/module-crypto_public_key_dsa.html
create mode 100644 docs/module-crypto_public_key_elgamal.html
create mode 100644 docs/module-crypto_public_key_elliptic.html
create mode 100644 docs/module-crypto_public_key_elliptic_curve.html
create mode 100644 docs/module-crypto_public_key_elliptic_ecdh.html
create mode 100644 docs/module-crypto_public_key_elliptic_ecdsa.html
create mode 100644 docs/module-crypto_public_key_elliptic_eddsa.html
create mode 100644 docs/module-crypto_public_key_elliptic_eddsa_legacy.html
create mode 100644 docs/module-crypto_public_key_prime.html
create mode 100644 docs/module-crypto_public_key_rsa.html
create mode 100644 docs/module-crypto_random.html
create mode 100644 docs/module-crypto_signature.html
create mode 100644 docs/module-encoding_base64.html
create mode 100644 docs/module-key_Subkey.html
create mode 100644 docs/module-key_User.html
create mode 100644 docs/module-key_helper.html
create mode 100644 docs/module-packet_packet.html
create mode 100644 docs/module-type_ecdh_symkey.html
create mode 100644 docs/module-type_keyid.html
create mode 100644 docs/module-type_oid.html
rename docs/{module-type_s2k-S2K.html => module-type_s2k-GenericS2K.html} (51%)
create mode 100644 docs/module-type_s2k.html
create mode 100644 docs/module-util.html
diff --git a/docs/AEADEncryptedDataPacket.html b/docs/AEADEncryptedDataPacket.html
index cd95975d1..da6470c60 100644
--- a/docs/AEADEncryptedDataPacket.html
+++ b/docs/AEADEncryptedDataPacket.html
@@ -98,7 +98,7 @@ Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/UserAttributePacket.html b/docs/UserAttributePacket.html
index d48d39066..1e4856676 100644
--- a/docs/UserAttributePacket.html
+++ b/docs/UserAttributePacket.html
@@ -107,7 +107,7 @@ ne
Source:
@@ -266,7 +266,7 @@ Parameters:
Source:
@@ -427,7 +427,7 @@ Parameters:
Source:
@@ -517,7 +517,7 @@ writeSource:
@@ -585,13 +585,13 @@ Returns:
- Home Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/UserIDPacket.html b/docs/UserIDPacket.html
index 746a07790..78afa3356 100644
--- a/docs/UserIDPacket.html
+++ b/docs/UserIDPacket.html
@@ -100,7 +100,7 @@ new UserI
Source:
@@ -207,7 +207,7 @@ Type:
Source:
@@ -338,7 +338,7 @@ Parameters:
Source:
@@ -495,7 +495,7 @@ Parameters:
Source:
@@ -585,7 +585,7 @@ writeSource:
@@ -653,13 +653,13 @@ Returns:
- Home Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/global.html b/docs/global.html
index 53c0c87b8..c2ff19a6d 100644
--- a/docs/global.html
+++ b/docs/global.html
@@ -161,7 +161,7 @@ aesSource:
@@ -443,7 +443,7 @@ Parameters:
Source:
@@ -656,7 +656,7 @@ Properties
Source:
@@ -795,7 +795,7 @@ Parameters:
Source:
@@ -1204,7 +1204,7 @@ Properties
Source:
@@ -1785,7 +1785,7 @@ Properties
Source:
@@ -1828,7 +1828,8 @@ Returns:
]
}
-where `signatures` contains a separate entry for each signature packet found in the input message.
+where `signatures` contains a separate entry for each signature packet found in the input message.
+
@@ -2087,7 +2088,7 @@ Properties
Source:
@@ -2446,7 +2447,7 @@ Properties
Source:
@@ -2511,6 +2512,103 @@ Returns:
+
+
+
+
+
+
+ detectBigInt()
+
+
+
+
+
+
+
+
We don't use the BigIntegerInterface wrapper from noble-hashes because:
+
+importing the instance results in it being shared with noble-hashes, which separately calls setImplementation()
+on load, causing it to throw due to duplicate initialization.
+even duplicating the interface code here to keep a separate instance requires handing a race-conditions the first time
+getBigInteger
is called, when the code needs to check if the implementation is set, and initialize it if not.
+Ultimately, the interface provides no advantages and it's only needed because of TS.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3250,7 +3348,7 @@ Properties
Source:
@@ -3538,7 +3636,7 @@ Properties
Source:
@@ -4158,7 +4256,7 @@ Properties
Source:
@@ -4374,7 +4472,7 @@ Parameters:
Source:
@@ -4442,7 +4540,8 @@ (async) ge
-
Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type.
+
Generates a new OpenPGP key pair. Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519 keys.
+By default, primary and subkeys will be of same type.
The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated.
@@ -4573,6 +4672,12 @@ Properties
|
'rsa'
+|
+
+'curve448'
+|
+
+'curve25519'
@@ -4598,7 +4703,8 @@ Properties
- The primary key algorithm type: ECC (default) or RSA
+ The primary key algorithm type: ECC (default for v4 keys), RSA, Curve448 or Curve25519 (new format, default for v6 keys).
+Note: Curve448 and Curve25519 (new format) are not widely supported yet.
@@ -4710,13 +4816,13 @@ Properties
- 'curve25519'
+ 'curve25519Legacy'
Elliptic curve for ECC keys:
-curve25519 (default), p256, p384, p521, secp256k1,
+curve25519Legacy (default), p256, p384, p521, secp256k1,
brainpoolP256r1, brainpoolP384r1, or brainpoolP512r1
@@ -4967,7 +5073,7 @@ Properties
Source:
@@ -5317,7 +5423,7 @@ Properties
Source:
@@ -5501,7 +5607,7 @@ Parameters:
Source:
@@ -5591,7 +5697,7 @@ Returns:
- (async) readCleartextMessage(options) → {Promise.<CleartextMessage >}
+ newS2KFromConfig() → {Object}
@@ -5599,7 +5705,7 @@ (async)
-
Reads an OpenPGP cleartext signed message and returns a CleartextMessage object
+
Instantiate a new S2K instance based on the config settings
@@ -5610,183 +5716,830 @@ (async)
- Parameters:
-
-
-
-
-
- Name
-
- Type
-
-
+
- Description
-
-
+
-
-
-
- options
-
+
-
-
-
-Object
+
+
-
-
+
-
+
-
+
-
- Properties
-
+
-
-
-
-
- Name
-
+
- Type
+
-
- Attributes
-
+
-
+
- Description
-
-
+
+ Source:
+
+
-
-
-
- cleartextMessage
-
+
-
-
-
-String
+
+
-
-
-
-
-
-
-
-
-
-
- Text to be parsed
-
-
-
-
- config
-
-
-
-
-Object
-
-
-
-
-
- <optional>
-
+Throws:
-
+
+
+
+
+
for unknown or unsupported types
+
+
+
+
+
+
+ Type
+
+
-
-
+Error
-
- Custom configuration settings to overwrite those in config
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+Returns:
+
+
+
+
+ Type
+
+
+
+Object
-
+
+
-
-
-
-
-
+
+
-
+ newS2KFromType(type) → {Object}
-
-
-
+
+
Instantiate a new S2K instance of the given type
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ type
+
+
+
+
+
+module:enums.s2k
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
for unknown or unsupported types
+
+
+
+
+
+
+ Type
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) produceEncryptionKey(keyVersion, s2k, passphrase, cipherAlgo, aeadModeopt , serializedPacketTag)
+
+
+
+
+
+
+
+
Derive encryption key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ keyVersion
+
+
+
+
+
+Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ key derivation differs for v5 keys
+
+
+
+
+
+
+ s2k
+
+
+
+
+
+module:type/s2k
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ passphrase
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ cipherAlgo
+
+
+
+
+
+module:enums.symmetric
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ aeadMode
+
+
+
+
+
+module:enums.aead
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ for AEAD-encrypted keys only (excluding v5)
+
+
+
+
+
+
+ serializedPacketTag
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ for AEAD-encrypted keys only (excluding v5)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) readCleartextMessage(options) → {Promise.<CleartextMessage >}
+
+
+
+
+
+
+
+
Reads an OpenPGP cleartext signed message and returns a CleartextMessage object
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ options
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+ Properties
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ cleartextMessage
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Text to be parsed
+
+
+
+
+
+
+ config
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ Custom configuration settings to overwrite those in config
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Source:
@@ -6074,7 +6827,7 @@ Properties
Source:
@@ -6362,7 +7115,7 @@ Properties
Source:
@@ -6656,7 +7409,7 @@ Properties
Source:
@@ -6944,7 +7697,7 @@ Properties
Source:
@@ -7232,7 +7985,7 @@ Properties
Source:
@@ -7520,7 +8273,7 @@ Properties
Source:
@@ -7982,7 +8735,7 @@ Properties
Source:
@@ -8511,7 +9264,7 @@ Properties
Source:
@@ -8571,6 +9324,215 @@ Returns:
+ (async) runAEAD(fn, key, data) → {Promise.<(Uint8Array|ReadableStream.<Uint8Array>)>}
+
+
+
+
+
+
+
+
En/decrypt the payload.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ fn
+
+
+
+
+
+encrypt
+|
+
+decrypt
+
+
+
+
+
+
+
+
+
+ Whether to encrypt or decrypt
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The session key used to en/decrypt the payload
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+|
+
+ReadableStream.<Uint8Array>
+
+
+
+
+
+
+
+
+
+ The data to en/decrypt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<(Uint8Array|ReadableStream.<Uint8Array>)>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(async) sign(options) → {Promise.<MaybeStream.<(String|Uint8Array)>>}
@@ -9066,7 +10028,7 @@ Properties
Source:
@@ -9228,7 +10190,7 @@ Parameters:
Source:
@@ -9690,7 +10652,7 @@ Properties
Source:
@@ -9732,7 +10694,8 @@ Returns:
]
}
-where `signatures` contains a separate entry for each signature packet found in the input message.
+where `signatures` contains a separate entry for each signature packet found in the input message.
+
@@ -9934,7 +10897,7 @@ Parameters:
Source:
@@ -9998,13 +10961,13 @@ Returns:
- Home Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/index.html b/docs/index.html
index 8a2c2ba62..275ca4406 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -44,7 +44,7 @@
OpenPGP.js
-OpenPGP.js is a JavaScript implementation of the OpenPGP protocol. It implements RFC4880 and parts of RFC4880bis .
+OpenPGP.js is a JavaScript implementation of the OpenPGP protocol. It implements the crypto-refresh (superseding RFC4880 and RFC4880bis ).
Table of Contents
OpenPGP.js
@@ -85,24 +85,24 @@
Platform Support
-The dist/openpgp.min.js
bundle works well with recent versions of Chrome, Firefox, Safari and Edge.
+The dist/openpgp.min.js
(or .mjs
) bundle works with recent versions of Chrome, Firefox, Edge and Safari 13+.
-The dist/node/openpgp.min.js
bundle works well in Node.js. It is used by default when you require('openpgp')
in Node.js.
+The dist/node/openpgp.min.mjs
(or .cjs
) bundle works in Node.js v16+: it is used by default when you import ... from 'openpgp'
(resp. require('openpgp')
).
-Currently, Chrome, Safari and Edge have partial implementations of the
-Streams specification , and Firefox
-has a partial implementation behind feature flags. Chrome is the only
-browser that implements TransformStream
s, which we need, so we include
-a polyfill for
-all other browsers. Please note that in those browsers, the global
-ReadableStream
property gets overwritten with the polyfill version if
-it exists. In some edge cases, you might need to use the native
+
Streaming support: the latest versions of Chrome, Firefox, Edge and Safari implement the
+Streams specification , including TransformStream
s.
+These are needed if you use the library with streamed inputs.
+In previous versions of OpenPGP.js, WebStreams were automatically polyfilled by the library,
+but from v6 this task is left up to the library user, due to the more extensive browser support, and the
+polyfilling side-effects. If you're working with older browsers versions which do not implement e.g. TransformStreams , you can manually
+load WebStream polyfill .
+Please note that when you load the polyfills, the global ReadableStream
property (if it exists) gets overwritten with the polyfill version.
+In some edge cases, you might need to use the native
ReadableStream
(for example when using it to create a Response
object), in which case you should store a reference to it before loading
-OpenPGP.js. There is also the
-web-streams-adapter
+the polyfills. There is also the web-streams-adapter
library to convert back and forth between them.
@@ -201,21 +201,19 @@ Performance
*** these curves are only constant-time if the underlying native implementation is available and constant-time
-Version 2.x of the library has been built from the ground up with Uint8Arrays. This allows for much better performance and memory usage than strings.
-
-
If the user's browser supports native WebCrypto via the window.crypto.subtle
API, this will be used. Under Node.js the native crypto module is used.
-The library implements the IETF proposal for authenticated encryption using native AES-EAX, OCB, or GCM. This makes symmetric encryption up to 30x faster on supported platforms. Since the specification has not been finalized and other OpenPGP implementations haven't adopted it yet, the feature is currently behind a flag. Note: activating this setting can break compatibility with other OpenPGP implementations, and also with future versions of OpenPGP.js. Don't use it with messages you want to store on disk or in a database. You can enable it by setting openpgp.config.aeadProtect = true
.
+The library implements authenticated encryption (AEAD) as per the "crypto refresh" draft standard using AES-OCB, EAX, or GCM. This makes symmetric encryption faster on platforms with native implementations. However, since the specification is very recent and other OpenPGP implementations are in the process of adopting it, the feature is currently behind a flag. Note: activating this setting can break compatibility with other OpenPGP implementations which have yet to implement the feature. You can enable it by setting openpgp.config.aeadProtect = true
.
+Note that this setting has a different effect from the one in OpenPGP.js v5, which implemented support for a provisional version of AEAD from RFC4880bis , which was modified in a later draft of the crypto refresh.
You can change the AEAD mode by setting one of the following options:
-openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax // Default, native
-openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb // Non-native
-openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM // **Non-standard**, fastest
+openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb; // Default (widest ecosystem support), non-native
+openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.gcm; // Native in WebCrypto and Node.js
+openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax; // Native in Node.js
-For environments that don't provide native crypto, the library falls back to asm.js implementations of AES, SHA-1, and SHA-256.
+For environments that don't provide native crypto, the library falls back to asm.js AES and AEAD implementations.
Getting started
@@ -223,12 +221,12 @@ Node.js
Install OpenPGP.js using npm and save it in your dependencies:
npm install --save openpgp
-And import it as a CommonJS module:
-const openpgp = require('openpgp');
-
-Or as an ES6 module, from an .mjs file:
+And import it as an ES module, from a .mjs file:
import * as openpgp from 'openpgp';
+Or as a CommonJS module:
+const openpgp = require('openpgp');
+
Deno (experimental)
Import as an ES6 module, using /dist/openpgp.mjs.
import * as openpgp from './openpgpjs/dist/openpgp.mjs';
@@ -708,13 +706,13 @@ License
- Home Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/module-config.html b/docs/module-config.html
index 51fef1bbe..315e50106 100644
--- a/docs/module-config.html
+++ b/docs/module-config.html
@@ -89,7 +89,7 @@ Module: config
Source:
@@ -247,7 +247,7 @@ Properties:
Source:
@@ -365,7 +365,7 @@ Properties:
Source:
@@ -390,8 +390,14 @@ (static)
Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption.
-Note: not all OpenPGP implementations are compatible with this option.
-FUTURE OPENPGP.JS VERSIONS MAY BREAK COMPATIBILITY WHEN USING THIS OPTION
+This option is applicable to:
+
+key generation (encryption key preferences),
+password-based message encryption, and
+private key encryption.
+In the case of message encryption using public keys, the encryption key preferences are respected instead.
+Note: not all OpenPGP implementations are compatible with this option.
+
@@ -483,7 +489,7 @@ Properties:
Source:
@@ -493,7 +499,7 @@ Properties:
See:
@@ -608,7 +614,7 @@ Properties:
Source:
@@ -727,7 +733,7 @@ Properties:
Source:
@@ -848,7 +854,7 @@ Properties:
Source:
@@ -875,7 +881,13 @@ (
Allow streaming unauthenticated data before its integrity has been checked. This would allow the application to
process large streams while limiting memory usage by releasing the decrypted chunks as soon as possible
and deferring checking their integrity until the decrypted stream has been read in full.
-This setting is insecure if the partially decrypted message is processed further or displayed to the user.
+This setting is insecure if the encrypted data has been corrupted by a malicious entity:
+
+if the partially decrypted message is processed further or displayed to the user, it opens up the possibility of attacks such as EFAIL
+(see https://efail.de/).
+an attacker with access to traces or timing info of internal processing errors could learn some info about the data.
+
+NB: this setting does not apply to AEAD-encrypted data, where the AEAD data chunk is never released until integrity is confirmed.
@@ -967,7 +979,7 @@ Properties:
Source:
@@ -985,7 +997,7 @@ Properties:
-(static) checksumRequired
+
@@ -1022,13 +1034,13 @@ Properties:
- checksumRequired
+ commentString
-Boolean
+String
@@ -1038,7 +1050,7 @@ Properties:
- Do not throw error when armor is missing a checksum
+ A comment string to be included in armored messages
@@ -1079,7 +1091,7 @@ Properties:
Source:
@@ -1097,11 +1109,21 @@ Properties:
-
+(static) constantTimePKCS1Decryption
+
+
Enable constant-time decryption of RSA- and ElGamal-encrypted session keys, to hinder Bleichenbacher-like attacks (https://link.springer.com/chapter/10.1007/BFb0055716).
+This setting has measurable performance impact and it is only helpful in application scenarios where both of the following conditions apply:
+
+new/incoming messages are automatically decrypted (without user interaction);
+an attacker can determine how long it takes to decrypt each message (e.g. due to decryption errors being logged remotely).
+See also constantTimePKCS1DecryptionSupportedSymmetricAlgorithms
.
+
+
+
@@ -1134,13 +1156,13 @@ Properties:
- commentString
+ constantTimePKCS1Decryption
-String
+Boolean
@@ -1150,7 +1172,7 @@ Properties:
- A comment string to be included in armored messages
+
@@ -1191,7 +1213,7 @@ Properties:
Source:
@@ -1209,19 +1231,15 @@ Properties:
-(static) constantTimePKCS1Decryption
+(static) constantTimePKCS1DecryptionSupportedSymmetricAlgorithms
-
Enable constant-time decryption of RSA- and ElGamal-encrypted session keys, to hinder Bleichenbacher-like attacks (https://link.springer.com/chapter/10.1007/BFb0055716).
-This setting has measurable performance impact and it is only helpful in application scenarios where both of the following conditions apply:
-
-new/incoming messages are automatically decrypted (without user interaction);
-an attacker can determine how long it takes to decrypt each message (e.g. due to decryption errors being logged remotely).
-See also constantTimePKCS1DecryptionSupportedSymmetricAlgorithms
.
-
+
This setting is only meaningful if constantTimePKCS1Decryption
is enabled.
+Decryption of RSA- and ElGamal-encrypted session keys of symmetric algorithms different from the ones specified here will fail.
+However, the more algorithms are added, the slower the decryption procedure becomes.
@@ -1256,13 +1274,13 @@ Properties:
- constantTimePKCS1Decryption
+ constantTimePKCS1DecryptionSupportedSymmetricAlgorithms
-Boolean
+Set.<Integer>
@@ -1272,7 +1290,7 @@ Properties:
-
+ module:enums.symmetric
@@ -1313,7 +1331,7 @@ Properties:
Source:
@@ -1331,16 +1349,10 @@ Properties:
-(static) constantTimePKCS1DecryptionSupportedSymmetricAlgorithms
-
+(static) deflateLevel
-
-
This setting is only meaningful if constantTimePKCS1Decryption
is enabled.
-Decryption of RSA- and ElGamal-encrypted session keys of symmetric algorithms different from the ones specified here will fail.
-However, the more algorithms are added, the slower the decryption procedure becomes.
-
@@ -1374,13 +1386,13 @@ Properties:
- constantTimePKCS1DecryptionSupportedSymmetricAlgorithms
+ deflateLevel
-Set.<Integer>
+Integer
@@ -1390,7 +1402,7 @@ Properties:
- module:enums.symmetric
+ Default zip/zlib compression level, between 1 and 9
@@ -1431,7 +1443,7 @@ Properties:
Source:
@@ -1449,7 +1461,7 @@ Properties:
-(static) deflateLevel
+(static) ignoreMalformedPackets
@@ -1486,13 +1498,13 @@ Properties:
- deflateLevel
+ ignoreMalformedPackets
-Integer
+Boolean
@@ -1502,7 +1514,7 @@ Properties:
- Default zip/zlib compression level, between 1 and 9
+ Ignore malformed packets on parsing instead of throwing an error
@@ -1543,7 +1555,7 @@ Properties:
Source:
@@ -1561,7 +1573,7 @@ Properties:
-(static) ignoreMalformedPackets
+(static) ignoreUnsupportedPackets
@@ -1598,7 +1610,7 @@ Properties:
- ignoreMalformedPackets
+ ignoreUnsupportedPackets
@@ -1614,7 +1626,7 @@ Properties:
- Ignore malformed packets on parsing instead of throwing an error
+ Ignore unsupported/unrecognizable packets on parsing instead of throwing an error
@@ -1655,7 +1667,7 @@ Properties:
Source:
@@ -1673,10 +1685,15 @@ Properties:
-(static) ignoreUnsupportedPackets
+(static) knownNotations
+
+
+
Contains notatations that are considered "known". Known notations do not trigger
+validation error when the notation is marked as critical.
+
@@ -1710,13 +1727,13 @@ Properties:
- ignoreUnsupportedPackets
+ knownNotations
-Boolean
+Array
@@ -1726,7 +1743,7 @@ Properties:
- Ignore unsupported/unrecognizable packets on parsing instead of throwing an error
+
@@ -1767,7 +1784,7 @@ Properties:
Source:
@@ -1785,14 +1802,13 @@ Properties:
-(static) knownNotations
+(static) maxUserIDLength
-
Contains notatations that are considered "known". Known notations do not trigger
-validation error when the notation is marked as critical.
+
Max userID string length (used for parsing)
@@ -1827,13 +1843,13 @@ Properties:
- knownNotations
+ maxUserIDLength
-Array
+Integer
@@ -1884,7 +1900,7 @@ Properties:
Source:
@@ -1902,13 +1918,14 @@ Properties:
-(static) maxUserIDLength
+(static) minRSABits
-
Max userID string length (used for parsing)
+
Minimum RSA key size allowed for key generation and message signing, verification and encryption.
+The default is 2047 since due to a bug, previous versions of OpenPGP.js could generate 2047-bit keys instead of 2048-bit ones.
@@ -1943,13 +1960,13 @@ Properties:
- maxUserIDLength
+ minRSABits
-Integer
+Number
@@ -2000,7 +2017,7 @@ Properties:
Source:
@@ -2018,10 +2035,15 @@ Properties:
-(static) minBytesForWebCrypto
+(static) passwordCollisionCheck
+
+
+
Work-around for rare GPG decryption bug when encrypting with multiple passwords.
+Slower and slightly less secure
+
@@ -2055,13 +2077,13 @@ Properties:
- minBytesForWebCrypto
+ passwordCollisionCheck
-Integer
+Boolean
@@ -2071,7 +2093,7 @@ Properties:
- The minimum amount of bytes for which to use native WebCrypto APIs when available
+
@@ -2112,7 +2134,7 @@ Properties:
Source:
@@ -2130,14 +2152,14 @@ Properties:
-(static) minRSABits
+(static) preferredAEADAlgorithm
-
Minimum RSA key size allowed for key generation and message signing, verification and encryption.
-The default is 2047 since due to a bug, previous versions of OpenPGP.js could generate 2047-bit keys instead of 2048-bit ones.
+
Default Authenticated Encryption with Additional Data (AEAD) encryption mode
+Only has an effect when aeadProtect is set to true.
@@ -2172,13 +2194,13 @@ Properties:
- minRSABits
+ preferredAEADAlgorithm
-Number
+Integer
@@ -2188,7 +2210,7 @@ Properties:
-
+ Default AEAD mode module:enums.aead
@@ -2229,7 +2251,7 @@ Properties:
Source:
@@ -2247,15 +2269,10 @@ Properties:
-(static) passwordCollisionCheck
-
+(static) preferredCompressionAlgorithm
-
-
Work-around for rare GPG decryption bug when encrypting with multiple passwords.
-Slower and slightly less secure
-
@@ -2289,13 +2306,13 @@ Properties:
- passwordCollisionCheck
+ compression
-Boolean
+Integer
@@ -2305,7 +2322,7 @@ Properties:
-
+ Default compression algorithm module:enums.compression
@@ -2346,7 +2363,7 @@ Properties:
Source:
@@ -2364,15 +2381,10 @@ Properties:
-(static) preferredAEADAlgorithm
-
+(static) preferredHashAlgorithm
-
-
Default Authenticated Encryption with Additional Data (AEAD) encryption mode
-Only has an effect when aeadProtect is set to true.
-
@@ -2406,7 +2418,7 @@ Properties:
- preferredAEADAlgorithm
+ preferredHashAlgorithm
@@ -2422,7 +2434,7 @@ Properties:
- Default AEAD mode module:enums.aead
+ Default hash algorithm module:enums.hash
@@ -2463,7 +2475,7 @@ Properties:
Source:
@@ -2481,7 +2493,7 @@ Properties:
-(static) preferredCompressionAlgorithm
+(static) preferredSymmetricAlgorithm
@@ -2518,7 +2530,7 @@ Properties:
- compression
+ preferredSymmetricAlgorithm
@@ -2534,7 +2546,7 @@ Properties:
- Default compression algorithm module:enums.compression
+ Default encryption cipher module:enums.symmetric
@@ -2575,7 +2587,7 @@ Properties:
Source:
@@ -2593,11 +2605,15 @@ Properties:
-(static) preferredHashAlgorithm
+(static) rejectCurves
+
+
Reject non-standard curves for key generation, message encryption, signing or verification
+
+
@@ -2630,13 +2646,13 @@ Properties:
- preferredHashAlgorithm
+ rejectCurves
-Integer
+Set.<String>
@@ -2646,7 +2662,7 @@ Properties:
- Default hash algorithm module:enums.hash
+ module:enums.curve
@@ -2687,7 +2703,7 @@ Properties:
Source:
@@ -2705,10 +2721,14 @@ Properties:
-(static) preferredSymmetricAlgorithm
+(static) rejectHashAlgorithms
+
+
+
Reject insecure hash algorithms
+
@@ -2742,13 +2762,13 @@ Properties:
- preferredSymmetricAlgorithm
+ rejectHashAlgorithms
-Integer
+Set.<Integer>
@@ -2758,7 +2778,7 @@ Properties:
- Default encryption cipher module:enums.symmetric
+ module:enums.hash
@@ -2799,7 +2819,7 @@ Properties:
Source:
@@ -2817,13 +2837,13 @@ Properties:
-(static) rejectCurves
+(static) rejectMessageHashAlgorithms
-
Reject non-standard curves for key generation, message encryption, signing or verification
+
Reject insecure message hash algorithms
@@ -2858,13 +2878,13 @@ Properties:
- rejectCurves
+ rejectMessageHashAlgorithms
-Set.<String>
+Set.<Integer>
@@ -2874,7 +2894,7 @@ Properties:
- module:enums.curve
+ module:enums.hash
@@ -2915,7 +2935,7 @@ Properties:
Source:
@@ -2933,13 +2953,13 @@ Properties:
-(static) rejectHashAlgorithms
+(static) rejectPublicKeyAlgorithms
-
Reject insecure hash algorithms
+
Reject insecure public key algorithms for key generation and message encryption, signing or verification
@@ -2974,7 +2994,7 @@ Properties:
- rejectHashAlgorithms
+ rejectPublicKeyAlgorithms
@@ -2990,7 +3010,7 @@ Properties:
- module:enums.hash
+ module:enums.publicKey
@@ -3031,7 +3051,7 @@ Properties:
Source:
@@ -3049,14 +3069,10 @@ Properties:
-(static) rejectMessageHashAlgorithms
-
+(static) revocationsExpire
-
-
Reject insecure message hash algorithms
-
@@ -3090,13 +3106,13 @@ Properties:
- rejectMessageHashAlgorithms
+ revocationsExpire
-Set.<Integer>
+Boolean
@@ -3106,7 +3122,7 @@ Properties:
- module:enums.hash
+ If true, expired revocation signatures are ignored
@@ -3147,7 +3163,7 @@ Properties:
Source:
@@ -3165,13 +3181,18 @@ Properties:
-(static) rejectPublicKeyAlgorithms
+(static) s2kArgon2Params
-
Reject insecure public key algorithms for key generation and message encryption, signing or verification
+
draft-crypto-refresh 3.7.1.4 :
+Argon2 parameters for S2K (String to Key).
+Only relevant if config.s2kType
is set to enums.s2k.argon2
.
+Default settings correspond to the second recommendation from RFC9106 ("uniformly safe option"),
+to ensure compatibility with memory-constrained environments.
+For more details on the choice of parameters, see https://tools.ietf.org/html/rfc9106#section-4.
@@ -3206,13 +3227,13 @@ Properties:
- rejectPublicKeyAlgorithms
+ params
-Set.<Integer>
+Object
@@ -3222,7 +3243,101 @@ Properties:
- module:enums.publicKey
+
+ Properties
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ passes
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ number of iterations t
+
+
+
+
+
+
+ parallelism
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ degree of parallelism p
+
+
+
+
+
+
+ memoryExponent
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ one-octet exponent indicating the memory size, which will be: 2**memoryExponent kibibytes.
+
+
+
+
+
+
+
@@ -3263,7 +3378,7 @@ Properties:
Source:
@@ -3281,11 +3396,18 @@ Properties:
-(static) revocationsExpire
+(static) s2kIterationCountByte
+
+
RFC4880 3.7.1.3 :
+Iteration Count Byte for Iterated and Salted S2K (String to Key).
+Only relevant if config.s2kType
is set to enums.s2k.iterated
.
+Note: this is the exponent value, not the final number of iterations (refer to specs for more details).
+
+
@@ -3318,13 +3440,13 @@ Properties:
- revocationsExpire
+ s2kIterationCountByte
-Boolean
+Integer
@@ -3334,7 +3456,7 @@ Properties:
- If true, expired revocation signatures are ignored
+
@@ -3375,7 +3497,7 @@ Properties:
Source:
@@ -3393,14 +3515,16 @@ Properties:
-(static) s2kIterationCountByte
+(static) s2kType
-
RFC4880 3.7.1.3 :
-Iteration Count Byte for S2K (String to Key)
+
S2K (String to Key) type, used for key derivation in the context of secret key encryption
+and password-encrypted data. Weaker s2k options are not allowed.
+Note: Argon2 is the strongest option but not all OpenPGP implementations are compatible with it
+(pending standardisation).
@@ -3435,13 +3559,16 @@ Properties:
- s2kIterationCountByte
+ s2kType
-Integer
+enums.s2k.argon2
+|
+
+enums.s2k.iterated
@@ -3451,7 +3578,7 @@ Properties:
-
+ module:enums.s2k
@@ -3492,7 +3619,7 @@ Properties:
Source:
@@ -3604,7 +3731,7 @@ Properties:
Source:
@@ -3716,7 +3843,7 @@ Properties:
Source:
@@ -3734,15 +3861,14 @@ Properties:
-(static) useIndutnyElliptic
+(static) useEllipticFallback
-
Whether to use the indutny/elliptic library for curves (other than Curve25519) that are not supported by the available native crypto API.
-When false, certain standard curves will not be supported (depending on the platform).
-Note: the indutny/elliptic curve library is not designed to be constant time.
+
Whether to use the the noble-curves library for curves (other than Curve25519) that are not supported by the available native crypto API.
+When false, certain standard curves will not be supported (depending on the platform).
@@ -3777,7 +3903,7 @@ Properties:
- useIndutnyElliptic
+ useEllipticFallback
@@ -3834,7 +3960,7 @@ Properties:
Source:
@@ -3852,13 +3978,13 @@ Properties:
-(static) v5Keys
+(static) v6Keys
-
Use V5 keys.
+
Use v6 keys.
Note: not all OpenPGP implementations are compatible with this option.
FUTURE OPENPGP.JS VERSIONS MAY BREAK COMPATIBILITY WHEN USING THIS OPTION
@@ -3895,7 +4021,7 @@ Properties:
- v5Keys
+ v6Keys
@@ -3952,7 +4078,7 @@ Properties:
Source:
@@ -4064,7 +4190,7 @@ Properties:
Source:
@@ -4098,13 +4224,13 @@ Properties:
- Home Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/module-crypto.html b/docs/module-crypto.html
new file mode 100644
index 000000000..6360dce95
--- /dev/null
+++ b/docs/module-crypto.html
@@ -0,0 +1,184 @@
+
+
+
+
+ JSDoc: Module: crypto
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides access to all cryptographic primitives used in OpenPGP.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_aes_kw.html b/docs/module-crypto_aes_kw.html
new file mode 100644
index 000000000..2150278b7
--- /dev/null
+++ b/docs/module-crypto_aes_kw.html
@@ -0,0 +1,553 @@
+
+
+
+
+ JSDoc: Module: crypto/aes_kw
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/aes_kw
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Implementation of RFC 3394 AES Key Wrap & Key Unwrap funcions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) unwrap(key, data) → {Uint8Array}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) wrap(key, data) → {Uint8Array}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_cipher.html b/docs/module-crypto_cipher.html
new file mode 100644
index 000000000..089085be1
--- /dev/null
+++ b/docs/module-crypto_cipher.html
@@ -0,0 +1,1430 @@
+
+
+
+
+ JSDoc: Module: crypto/cipher
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/cipher
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Symmetric cryptography functions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) aes128(key) → {Object}
+
+
+
+
+
+
+
+
AES-128 encryption and decryption (ID 7)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 128-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) aes192(key) → {Object}
+
+
+
+
+
+
+
+
AES-128 Block Cipher (ID 8)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 192-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) aes256(key) → {Object}
+
+
+
+
+
+
+
+
AES-128 Block Cipher (ID 9)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 256-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) blowfish(key) → {Object}
+
+
+
+
+
+
+
+
Blowfish Block Cipher (ID 4)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 128-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) cast5(key) → {Object}
+
+
+
+
+
+
+
+
CAST-128 Block Cipher (ID 3)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 128-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) idea()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) tripledes(key) → {Object}
+
+
+
+
+
+
+
+
Triple DES Block Cipher (ID 2)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 192-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) twofish(key) → {Object}
+
+
+
+
+
+
+
+
Twofish Block Cipher (ID 10)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ key
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ 256-bit key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_cmac.html b/docs/module-crypto_cmac.html
new file mode 100644
index 000000000..31aaadf1c
--- /dev/null
+++ b/docs/module-crypto_cmac.html
@@ -0,0 +1,413 @@
+
+
+
+
+ JSDoc: Module: crypto/cmac
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/cmac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This module implements AES-CMAC on top of
+native AES-CBC using either the WebCrypto API or Node.js' crypto API.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+(inner, constant) blockLength
+
+
+
+
+
+
This implementation of CMAC is based on the description of OMAC in
+http://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf. As per that
+document:
+
We have made a small modification to the OMAC algorithm as it was
+originally presented, changing one of its two constants.
+Specifically, the constant 4 at line 85 was the constant 1/2 (the
+multiplicative inverse of 2) in the original definition of OMAC [14].
+The OMAC authors indicate that they will promulgate this modification
+[15], which slightly simplifies implementations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (inner) rightXORMut(data, padding)
+
+
+
+
+
+
+
+
xor padding
into the end of data
. This function implements "the
+operation xor→ [which] xors the shorter string into the end of longer
+one". Since data is always as least as long as padding, we can
+simplify the implementation.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ padding
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_crypto.html b/docs/module-crypto_crypto.html
new file mode 100644
index 000000000..a0105d175
--- /dev/null
+++ b/docs/module-crypto_crypto.html
@@ -0,0 +1,3000 @@
+
+
+
+
+ JSDoc: Module: crypto/crypto
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/crypto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides functions for asymmetric encryption and decryption as
+well as key generation and parameter handling for all public-key cryptosystems.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) generateParams(algo, bits, oid) → {Promise.<{publicParams: {Object}, privateParams: {Object}}>}
+
+
+
+
+
+
+
+
Generate algorithm-specific key parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ The public key algorithm
+
+
+
+
+
+
+ bits
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Bit length for RSA keys
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Object identifier for ECC keys
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The parameters referenced by name.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicParams: {Object}, privateParams: {Object}}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) generateSessionKey(algo) → {Uint8Array}
+
+
+
+
+
+
+
+
Generating a session key for the specified symmetric algorithm
+See RFC 4880 9.2 for algorithms.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.symmetric
+
+
+
+
+
+
+
+
+
+ Symmetric encryption algorithm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Random bytes as a string to be used as a key.
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) getAEADMode(algo) → {Object}
+
+
+
+
+
+
+
+
Get implementation of the given AEAD mode
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+enums.aead
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) getCurvePayloadSize(algo, oidopt )
+
+
+
+
+
+
+
+
Get encoded secret size for a given elliptic algo
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ alrogithm identifier
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ curve OID if needed by algo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) getPreferredCurveHashAlgo(algo, oidopt )
+
+
+
+
+
+
+
+
Get preferred signing hash algo for a given elliptic algo
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ alrogithm identifier
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ curve OID if needed by algo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) getPrefixRandom(algo) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Generates a random byte prefix for the specified algorithm
+See RFC 4880 9.2 for algorithms.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.symmetric
+
+
+
+
+
+
+
+
+
+ Symmetric encryption algorithm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Random bytes with length equal to the block size of the cipher, plus the last two bytes repeated.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) parseEncSessionKeyParams(algo, bytes) → {Object}
+
+
+
+
+
+
+
+
Returns the types comprising the encrypted session key of an algorithm
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ The key algorithm
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The key material to parse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The session key parameters referenced by name.
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) parsePrivateKeyParams(algo, bytes, publicParams) → {Object}
+
+
+
+
+
+
+
+
Parse private key material in binary form to get the key parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ The key algorithm
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The key material to parse
+
+
+
+
+
+
+ publicParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ (ECC only) public params, needed to format some private params
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Number of read bytes plus the key parameters referenced by name.
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) parsePublicKeyParams(algo, bytes) → {Object}
+
+
+
+
+
+
+
+
Parse public key material in binary form to get the key parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ The key algorithm
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The key material to parse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Number of read bytes plus key parameters referenced by name.
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, sessionKeyParams, fingerprint, randomPayloadopt ) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypts data using specified algorithm and private key parameters.
+See RFC 4880 5.5.3
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Public key algorithm
+
+
+
+
+
+
+ publicKeyParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Algorithm-specific public key parameters
+
+
+
+
+
+
+ privateKeyParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Algorithm-specific private key parameters
+
+
+
+
+
+
+ sessionKeyParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Encrypted session key parameters
+
+
+
+
+
+
+ fingerprint
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Recipient fingerprint
+
+
+
+
+
+
+ randomPayload
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ Data to return on decryption error, instead of throwing
+(needed for constant-time processing in RSA and ElGamal)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
on sensitive decryption error, unless randomPayload
is given
+
+
+
+
+
+
+ Type
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, data, fingerprint) → {Promise.<Object>}
+
+
+
+
+
+
+
+
Encrypts data using specified algorithm and public key parameters.
+See RFC 4880 9.1 for public key algorithms.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ keyAlgo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Public key algorithm
+
+
+
+
+
+
+ symmetricAlgo
+
+
+
+
+
+module:enums.symmetric
+
+
+
+
+
+
+
+
+
+ Cipher algorithm
+
+
+
+
+
+
+ publicParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Algorithm-specific public key parameters
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Session key data to be encrypted
+
+
+
+
+
+
+ fingerprint
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient fingerprint
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Encrypted session key parameters.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Object>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) serializeParams(algo, params) → {Uint8Array}
+
+
+
+
+
+
+
+
Convert params to MPI and serializes them in the proper order
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ The public key algorithm
+
+
+
+
+
+
+ params
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ The key parameters indexed by name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The array containing the MPIs.
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(algo, publicParams, privateParams) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate algorithm-specific key parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ The public key algorithm
+
+
+
+
+
+
+ publicParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Algorithm-specific public key parameters
+
+
+
+
+
+
+ privateParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Algorithm-specific private key parameters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether the parameters are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) checkSupportedCurve(oid)
+
+
+
+
+
+
+
+
Check whether the given curve OID is supported
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ EC object identifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
if curve is not supported
+
+
+
+
+
+
+ Type
+
+
+
+UnsupportedError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_hash.html b/docs/module-crypto_hash.html
new file mode 100644
index 000000000..1e4de57d4
--- /dev/null
+++ b/docs/module-crypto_hash.html
@@ -0,0 +1,596 @@
+
+
+
+
+ JSDoc: Module: crypto/hash
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/hash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides an interface to hashing functions available in Node.js or external libraries.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+(static) md5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) digest(algo, data) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Create a hash on the specified data using the specified algorithm
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm type (see RFC 4880 9.4 )
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data to be hashed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) getHashByteLength(algo) → {Integer}
+
+
+
+
+
+
+
+
Returns the hash size in bytes of the specified hash algorithm type
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm type (See RFC 4880 9.4 )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Size in bytes of the resulting hash.
+
+
+
+
+
+
+ Type
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_hkdf.html b/docs/module-crypto_hkdf.html
new file mode 100644
index 000000000..08e03208d
--- /dev/null
+++ b/docs/module-crypto_hkdf.html
@@ -0,0 +1,167 @@
+
+
+
+
+ JSDoc: Module: crypto/hkdf
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/hkdf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This module implements HKDF using either the WebCrypto API or Node.js' crypto API.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_mode.html b/docs/module-crypto_mode.html
new file mode 100644
index 000000000..766568b78
--- /dev/null
+++ b/docs/module-crypto_mode.html
@@ -0,0 +1,439 @@
+
+
+
+
+ JSDoc: Module: crypto/mode
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+(static) cfb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(static) eax
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(static) gcm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(static) ocb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_mode_cfb.html b/docs/module-crypto_mode_cfb.html
new file mode 100644
index 000000000..2aa1d2091
--- /dev/null
+++ b/docs/module-crypto_mode_cfb.html
@@ -0,0 +1,548 @@
+
+
+
+
+ JSDoc: Module: crypto/mode/cfb
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/mode/cfb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) decrypt(algo, key, ciphertext, iv)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+enums.symmetric
+
+
+
+
+
+
+
+
+
+ block cipher algorithm
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ciphertext
+
+
+
+
+
+MaybeStream.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ iv
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) encrypt(algo, key, plaintext, iv, config)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+enums.symmetric
+
+
+
+
+
+
+
+
+
+ block cipher algorithm
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ plaintext
+
+
+
+
+
+MaybeStream.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ iv
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ config
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ full configuration, defaults to openpgp.config
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_mode_eax.html b/docs/module-crypto_mode_eax.html
new file mode 100644
index 000000000..76aa35511
--- /dev/null
+++ b/docs/module-crypto_mode_eax.html
@@ -0,0 +1,748 @@
+
+
+
+
+ JSDoc: Module: crypto/mode/eax
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/mode/eax
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This module implements AES-EAX en/decryption on top of
+native AES-CTR using either the WebCrypto API or Node.js' crypto API.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (inner) decrypt(ciphertext, nonce, adata) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypt ciphertext input.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ ciphertext
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The ciphertext input to be decrypted
+
+
+
+
+
+
+ nonce
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The nonce (16 bytes)
+
+
+
+
+
+
+ adata
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Associated data to verify
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The plaintext output.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) EAX(cipher, key)
+
+
+
+
+
+
+
+
Class to en/decrypt using EAX mode.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ cipher
+
+
+
+
+
+enums.symmetric
+
+
+
+
+
+
+
+
+
+ The symmetric cipher algorithm to use
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The encryption key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) encrypt(plaintext, nonce, adata) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Encrypt plaintext input.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ plaintext
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The cleartext input to be encrypted
+
+
+
+
+
+
+ nonce
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The nonce (16 bytes)
+
+
+
+
+
+
+ adata
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Associated data to sign
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The ciphertext output.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_mode_gcm.html b/docs/module-crypto_mode_gcm.html
new file mode 100644
index 000000000..c9911464d
--- /dev/null
+++ b/docs/module-crypto_mode_gcm.html
@@ -0,0 +1,334 @@
+
+
+
+
+ JSDoc: Module: crypto/mode/gcm
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/mode/gcm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This module wraps native AES-GCM en/decryption for both
+the WebCrypto api as well as node.js' crypto api.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, inner) GCM(cipher, key)
+
+
+
+
+
+
+
+
Class to en/decrypt using GCM mode.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ cipher
+
+
+
+
+
+enums.symmetric
+
+
+
+
+
+
+
+
+
+ The symmetric cipher algorithm to use
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The encryption key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_mode_ocb.html b/docs/module-crypto_mode_ocb.html
new file mode 100644
index 000000000..19dceb00a
--- /dev/null
+++ b/docs/module-crypto_mode_ocb.html
@@ -0,0 +1,747 @@
+
+
+
+
+ JSDoc: Module: crypto/mode/ocb
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/mode/ocb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This module implements AES-OCB en/decryption.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (inner) decrypt(ciphertext, nonce, adata) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypt ciphertext input.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ ciphertext
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The ciphertext input to be decrypted
+
+
+
+
+
+
+ nonce
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The nonce (15 bytes)
+
+
+
+
+
+
+ adata
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Associated data to sign
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The ciphertext output.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) encrypt(plaintext, nonce, adata) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Encrypt plaintext input.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ plaintext
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The cleartext input to be encrypted
+
+
+
+
+
+
+ nonce
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The nonce (15 bytes)
+
+
+
+
+
+
+ adata
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Associated data to sign
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
The ciphertext output.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) OCB(cipher, key)
+
+
+
+
+
+
+
+
Class to en/decrypt using OCB mode.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ cipher
+
+
+
+
+
+enums.symmetric
+
+
+
+
+
+
+
+
+
+ The symmetric cipher algorithm to use
+
+
+
+
+
+
+ key
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The encryption key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_pkcs1.html b/docs/module-crypto_pkcs1.html
new file mode 100644
index 000000000..2a8616b5c
--- /dev/null
+++ b/docs/module-crypto_pkcs1.html
@@ -0,0 +1,882 @@
+
+
+
+
+ JSDoc: Module: crypto/pkcs1
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/pkcs1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides EME-PKCS1-v1_5 encoding and decoding and EMSA-PKCS1-v1_5 encoding function
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+
+
+
+
+
+
+
ASN1 object identifiers for hashes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) emeDecode(encoded, randomPayload) → {Uint8Array}
+
+
+
+
+
+
+
+
Decode a EME-PKCS1-v1_5 padded message
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ encoded
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Encoded message bytes
+
+
+
+
+
+
+ randomPayload
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data to return in case of decoding error (needed for constant-time processing)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
on decoding failure, unless randomPayload
is provided
+
+
+
+
+
+
+ Type
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
decoded data or randomPayload
(on error, if given)
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) emeEncode(message, keyLength) → {Uint8Array}
+
+
+
+
+
+
+
+
Create a EME-PKCS1-v1_5 padded message
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ message
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to be encoded
+
+
+
+
+
+
+ keyLength
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ The length in octets of the key modulus
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
EME-PKCS1 padded message.
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) emsaEncode(algo, hashed, emLen) → {Uint8Array}
+
+
+
+
+
+
+
+
Create a EMSA-PKCS1-v1_5 padded message
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Hash algorithm type used
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to be encoded
+
+
+
+
+
+
+ emLen
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Intended length in octets of the encoded message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key.html b/docs/module-crypto_public_key.html
new file mode 100644
index 000000000..c052971fc
--- /dev/null
+++ b/docs/module-crypto_public_key.html
@@ -0,0 +1,439 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Asymmetric cryptography functions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+(static) dsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(static) elgamal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(static) elliptic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(static) rsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_dsa.html b/docs/module-crypto_public_key_dsa.html
new file mode 100644
index 000000000..aa017beee
--- /dev/null
+++ b/docs/module-crypto_public_key_dsa.html
@@ -0,0 +1,1084 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/dsa
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/dsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
A Digital signature algorithm implementation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+(inner) x
+
+
+
+
+
+
Re-derive public key y' = g ** x mod p
+Expect y == y'
+
Blinded exponentiation computes g**{rq + x} to compare to y
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) sign(hashAlgo, hashed, g, p, q, x) → {Promise.<{r: Uint8Array, s: Uint8Array}>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ g
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ x
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{r: Uint8Array, s: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(p, q, g, y, x) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate DSA parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ DSA prime
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ DSA group order
+
+
+
+
+
+
+ g
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ DSA sub-group generator
+
+
+
+
+
+
+ y
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ DSA public key
+
+
+
+
+
+
+ x
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ DSA private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) verify(hashAlgo, r, s, hashed, g, p, q, y) → {boolean}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ r
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ s
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ g
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ y
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elgamal.html b/docs/module-crypto_public_key_elgamal.html
new file mode 100644
index 000000000..a4e8c423a
--- /dev/null
+++ b/docs/module-crypto_public_key_elgamal.html
@@ -0,0 +1,981 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elgamal
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elgamal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Members
+
+
+
+(inner) x
+
+
+
+
+
+
Re-derive public key y' = g ** x mod p
+Expect y == y'
+
Blinded exponentiation computes g**{r(p-1) + x} to compare to y
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) decrypt(c1, c2, p, x, randomPayload) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
ElGamal Encryption function
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ c1
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ c2
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ x
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ randomPayload
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data to return on unpadding error, instead of throwing
+(needed for constant-time processing)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
on decryption error, unless randomPayload
is given
+
+
+
+
+
+
+ Type
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) encrypt(data, p, g, y) → {Promise.<{c1: Uint8Array, c2: Uint8Array}>}
+
+
+
+
+
+
+
+
ElGamal Encryption function
+Note that in OpenPGP, the message needs to be padded with PKCS#1 (same as RSA)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ To be padded and encrypted
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ g
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ y
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{c1: Uint8Array, c2: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(p, g, y, x) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ElGamal parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ElGamal prime
+
+
+
+
+
+
+ g
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ElGamal group generator
+
+
+
+
+
+
+ y
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ElGamal public key
+
+
+
+
+
+
+ x
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ElGamal private exponent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elliptic.html b/docs/module-crypto_public_key_elliptic.html
new file mode 100644
index 000000000..f116206b9
--- /dev/null
+++ b/docs/module-crypto_public_key_elliptic.html
@@ -0,0 +1,180 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elliptic
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elliptic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Functions to access Elliptic Curve Cryptography
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elliptic_curve.html b/docs/module-crypto_public_key_elliptic_curve.html
new file mode 100644
index 000000000..b925f1443
--- /dev/null
+++ b/docs/module-crypto_public_key_elliptic_curve.html
@@ -0,0 +1,1149 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elliptic/curve
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elliptic/curve
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Wrapper of an instance of an Elliptic Curve
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (inner) getPreferredHashAlgo(oid) → {enums.hash}
+
+
+
+
+
+
+
+
Get preferred hash algo to use with the given curve
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ curve oid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+enums.hash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) jwkToRawPublic(jwk) → {Uint8Array}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ jwk
+
+
+
+
+
+JsonWebKey
+
+
+
+
+
+
+
+
+
+ key for conversion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) privateToJWK(payloadSize, name, publicKey, privateKey) → {JsonWebKey}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ payloadSize
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ ec payload size
+
+
+
+
+
+
+ name
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ curve name
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ public key
+
+
+
+
+
+
+ privateKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Private key in jwk format.
+
+
+
+
+
+
+ Type
+
+
+
+JsonWebKey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) rawPublicToJWK(payloadSize, name, publicKey) → {JsonWebKey}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ payloadSize
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ ec payload size
+
+
+
+
+
+
+ name
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ curve name
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Public key in jwk format.
+
+
+
+
+
+
+ Type
+
+
+
+JsonWebKey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) validateStandardParams(algo, oid, Q, d) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ECDH and ECDSA parameters
+Not suitable for EdDSA (different secret key format)
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ EC algorithm, to filter supported curves
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ EC object identifier
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ EC public point
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ EC secret scalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elliptic_ecdh.html b/docs/module-crypto_public_key_elliptic_ecdh.html
new file mode 100644
index 000000000..8c83d5128
--- /dev/null
+++ b/docs/module-crypto_public_key_elliptic_ecdh.html
@@ -0,0 +1,6011 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elliptic/ecdh
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elliptic/ecdh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key encryption and decryption for RFC 6637 ECDH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) decrypt(oid, kdfParams, V, C, Q, d, fingerprint) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypt and unwrap the value derived from session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ kdfParams
+
+
+
+
+
+module:type/kdf_params
+
+
+
+
+
+
+
+
+
+ KDF params including cipher and algorithm to use
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ C
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Encrypted and wrapped value derived from session key
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+ fingerprint
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient fingerprint
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Value derived from session key.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) decrypt(algo, ephemeralPublicKey, wrappedKey,, A, k) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypt and unwrap the session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ ephemeralPublicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ (K_A)
+
+
+
+
+
+
+ wrappedKey,
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key (K_b), needed for KDF
+
+
+
+
+
+
+ k
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient secret key (b)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
decrypted session key data
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) encrypt(oid, kdfParams, data, Q, fingerprint) → {Promise.<{publicKey: Uint8Array, wrappedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Encrypt and wrap a session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ kdfParams
+
+
+
+
+
+module:type/kdf_params
+
+
+
+
+
+
+
+
+
+ KDF params including cipher and algorithm to use
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Unpadded session key data
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ fingerprint
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient fingerprint
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, wrappedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) encrypt(algo, data, recipientA) → {Promise.<{ephemeralPublicKey: Uint8Array, wrappedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Wrap and encrypt a session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ session key data to be encrypted
+
+
+
+
+
+
+ recipientA
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key (K_B)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
ephemeral public key (K_A) and encrypted key
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{ephemeralPublicKey: Uint8Array, wrappedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) generate(algo) → {Promise.<{A: Uint8Array, k: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDH key for Montgomery curves
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{A: Uint8Array, k: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(oid, Q, d) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ECDH parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH public point
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH secret scalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(algo, A, k) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ECDH parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ A
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH public point
+
+
+
+
+
+
+ k
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH secret scalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) genPrivateEphemeralKey(curve, V, Q, d) → {Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE secret from private key and public part of ephemeral key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) genPublicEphemeralKey(curve, Q) → {Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE ephemeral key and secret from public key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) nodePrivateEphemeralKey(curve, V, d) → {Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE secret from private key and public part of ephemeral key using nodeCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) nodePublicEphemeralKey(curve, Q) → {Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE ephemeral key and secret from public key using nodeCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) webPrivateEphemeralKey(curve, V, Q, d) → {Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE secret from private key and public part of ephemeral key using webCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) webPublicEphemeralKey(curve, Q) → {Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE ephemeral key and secret from public key using webCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key encryption and decryption for RFC 6637 ECDH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) decrypt(oid, kdfParams, V, C, Q, d, fingerprint) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypt and unwrap the value derived from session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ kdfParams
+
+
+
+
+
+module:type/kdf_params
+
+
+
+
+
+
+
+
+
+ KDF params including cipher and algorithm to use
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ C
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Encrypted and wrapped value derived from session key
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+ fingerprint
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient fingerprint
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Value derived from session key.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) decrypt(algo, ephemeralPublicKey, wrappedKey,, A, k) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
Decrypt and unwrap the session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ ephemeralPublicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ (K_A)
+
+
+
+
+
+
+ wrappedKey,
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key (K_b), needed for KDF
+
+
+
+
+
+
+ k
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient secret key (b)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
decrypted session key data
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) encrypt(oid, kdfParams, data, Q, fingerprint) → {Promise.<{publicKey: Uint8Array, wrappedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Encrypt and wrap a session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ kdfParams
+
+
+
+
+
+module:type/kdf_params
+
+
+
+
+
+
+
+
+
+ KDF params including cipher and algorithm to use
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Unpadded session key data
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ fingerprint
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient fingerprint
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, wrappedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) encrypt(algo, data, recipientA) → {Promise.<{ephemeralPublicKey: Uint8Array, wrappedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Wrap and encrypt a session key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ session key data to be encrypted
+
+
+
+
+
+
+ recipientA
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key (K_B)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
ephemeral public key (K_A) and encrypted key
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{ephemeralPublicKey: Uint8Array, wrappedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) generate(algo) → {Promise.<{A: Uint8Array, k: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDH key for Montgomery curves
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{A: Uint8Array, k: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(oid, Q, d) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ECDH parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH public point
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH secret scalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(algo, A, k) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ECDH parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ A
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH public point
+
+
+
+
+
+
+ k
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDH secret scalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) genPrivateEphemeralKey(curve, V, Q, d) → {Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE secret from private key and public part of ephemeral key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) genPublicEphemeralKey(curve, Q) → {Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE ephemeral key and secret from public key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) nodePrivateEphemeralKey(curve, V, d) → {Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE secret from private key and public part of ephemeral key using nodeCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) nodePublicEphemeralKey(curve, Q) → {Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE ephemeral key and secret from public key using nodeCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) webPrivateEphemeralKey(curve, V, Q, d) → {Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE secret from private key and public part of ephemeral key using webCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ V
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public part of ephemeral key
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient private key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{secretKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) webPublicEphemeralKey(curve, Q) → {Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate ECDHE ephemeral key and secret from public key using webCrypto
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ curve
+
+
+
+
+
+CurveWithOID
+
+
+
+
+
+
+
+
+
+ Elliptic curve object
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Recipient public key
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{publicKey: Uint8Array, sharedKey: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elliptic_ecdsa.html b/docs/module-crypto_public_key_elliptic_ecdsa.html
new file mode 100644
index 000000000..ff155f0bc
--- /dev/null
+++ b/docs/module-crypto_public_key_elliptic_ecdsa.html
@@ -0,0 +1,1017 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elliptic/ecdsa
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elliptic/ecdsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Implementation of ECDSA following RFC6637 for Openpgpjs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) sign(oid, hashAlgo, message, publicKey, privateKey, hashed) → {Promise.<{r: Uint8Array, s: Uint8Array}>}
+
+
+
+
+
+
+
+
Sign a message using the provided key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm used to sign
+
+
+
+
+
+
+ message
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to sign
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public key
+
+
+
+
+
+
+ privateKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Private key used to sign the message
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Signature of the message
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{r: Uint8Array, s: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(oid, Q, d) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate ECDSA parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDSA public point
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ ECDSA secret scalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) verify(oid, hashAlgo, signature, message, publicKey, hashed) → {Boolean}
+
+
+
+
+
+
+
+
Verifies if a signature is valid for a message
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm used in the signature
+
+
+
+
+
+
+ signature
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Signature to verify
+
+
+
+
+
+
+ message
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to verify
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public key used to verify the message
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) jsVerify()
+
+
+
+
+
+
+
+
Fallback javascript implementation of ECDSA verification.
+To be used if no native implementation is available for the given curve/operation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elliptic_eddsa.html b/docs/module-crypto_public_key_elliptic_eddsa.html
new file mode 100644
index 000000000..21bb2eb81
--- /dev/null
+++ b/docs/module-crypto_public_key_elliptic_eddsa.html
@@ -0,0 +1,1106 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elliptic/eddsa
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elliptic/eddsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Implementation of EdDSA following RFC4880bis-03 for OpenPGP
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) generate(algo) → {Promise.<{A: Uint8Array, seed: Uint8Array}>}
+
+
+
+
+
+
+
+
Generate (non-legacy) EdDSA key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{A: Uint8Array, seed: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) sign(algo, hashAlgo, message, publicKey, privateKey, hashed) → {Promise.<{RS: Uint8Array}>}
+
+
+
+
+
+
+
+
Sign a message using the provided key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm used to sign (must be sha256 or stronger)
+
+
+
+
+
+
+ message
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to sign
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public key
+
+
+
+
+
+
+ privateKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Private key used to sign the message
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Signature of the message
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{RS: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(algo, A, seed, oid) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate (non-legacy) EdDSA parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ A
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ EdDSA public point
+
+
+
+
+
+
+ seed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ EdDSA secret seed
+
+
+
+
+
+
+ oid
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ (legacy only) EdDSA OID
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) verify(algo, hashAlgo, signature, m, publicKey, hashed) → {Boolean}
+
+
+
+
+
+
+
+
Verifies if a signature is valid for a message
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Algorithm identifier
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm used in the signature
+
+
+
+
+
+
+ signature
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Signature to verify the message
+
+
+
+
+
+
+ m
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to verify
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public key used to verify the message
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_elliptic_eddsa_legacy.html b/docs/module-crypto_public_key_elliptic_eddsa_legacy.html
new file mode 100644
index 000000000..b9a68f12d
--- /dev/null
+++ b/docs/module-crypto_public_key_elliptic_eddsa_legacy.html
@@ -0,0 +1,927 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/elliptic/eddsa_legacy
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/elliptic/eddsa_legacy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Implementation of legacy EdDSA following RFC4880bis-03 for OpenPGP.
+This key type has been deprecated by the crypto-refresh RFC.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) sign(oid, hashAlgo, message, publicKey, privateKey, hashed) → {Promise.<{r: Uint8Array, s: Uint8Array}>}
+
+
+
+
+
+
+
+
Sign a message using the provided legacy EdDSA key
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm used to sign (must be sha256 or stronger)
+
+
+
+
+
+
+ message
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to sign
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public key
+
+
+
+
+
+
+ privateKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Private key used to sign the message
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Signature of the message
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<{r: Uint8Array, s: Uint8Array}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(oid, Q, k) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate legacy EdDSA parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ Q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ EdDSA public point
+
+
+
+
+
+
+ k
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ EdDSA secret seed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) verify(oid, hashAlgo, signature, m, publicKey, hashed) → {Boolean}
+
+
+
+
+
+
+
+
Verifies if a legacy EdDSA signature is valid for a message
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ oid
+
+
+
+
+
+module:type/oid
+
+
+
+
+
+
+
+
+
+ Elliptic curve object identifier
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm used in the signature
+
+
+
+
+
+
+ signature
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Signature to verify the message
+
+
+
+
+
+
+ m
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message to verify
+
+
+
+
+
+
+ publicKey
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Public key used to verify the message
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_prime.html b/docs/module-crypto_public_key_prime.html
new file mode 100644
index 000000000..f26a9c247
--- /dev/null
+++ b/docs/module-crypto_public_key_prime.html
@@ -0,0 +1,954 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/prime
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/prime
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Algorithms for probabilistic random prime generation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) fermat(n, b) → {boolean}
+
+
+
+
+
+
+
+
Tests whether n is probably prime or not using Fermat's test with b = 2.
+Fails if b^(n-1) mod n != 1.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ n
+
+
+
+
+
+BigInteger
+
+
+
+
+
+
+
+
+
+ Number to test
+
+
+
+
+
+
+ b
+
+
+
+
+
+BigInteger
+
+
+
+
+
+
+
+
+
+ Optional Fermat test base
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) isProbablePrime(n, e, k) → {boolean}
+
+
+
+
+
+
+
+
Probabilistic primality testing
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ n
+
+
+
+
+
+BigInteger
+
+
+
+
+
+
+
+
+
+ Number to test
+
+
+
+
+
+
+ e
+
+
+
+
+
+BigInteger
+
+
+
+
+
+
+
+
+
+ Optional RSA exponent to check against the prime
+
+
+
+
+
+
+ k
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Optional number of iterations of Miller-Rabin test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) millerRabin(n, k, rand) → {boolean}
+
+
+
+
+
+
+
+
Tests whether n is probably prime or not using the Miller-Rabin test.
+See HAC Remark 4.28.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ n
+
+
+
+
+
+BigInteger
+
+
+
+
+
+
+
+
+
+ Number to test
+
+
+
+
+
+
+ k
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Optional number of iterations of Miller-Rabin test
+
+
+
+
+
+
+ rand
+
+
+
+
+
+function
+
+
+
+
+
+
+
+
+
+ Optional function to generate potential witnesses
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) randomProbablePrime(bits, e, k)
+
+
+
+
+
+
+
+
Generate a probably prime random number
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ bits
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Bit length of the prime
+
+
+
+
+
+
+ e
+
+
+
+
+
+BigInteger
+
+
+
+
+
+
+
+
+
+ Optional RSA exponent to check against the prime
+
+
+
+
+
+
+ k
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Optional number of iterations of Miller-Rabin test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_public_key_rsa.html b/docs/module-crypto_public_key_rsa.html
new file mode 100644
index 000000000..7cc1eccfa
--- /dev/null
+++ b/docs/module-crypto_public_key_rsa.html
@@ -0,0 +1,2279 @@
+
+
+
+
+ JSDoc: Module: crypto/public_key/rsa
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/public_key/rsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) decrypt(m, n, e, d, p, q, u, randomPayload) → {Promise.<String>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ m
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public modulus
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public exponent
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private exponent
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private prime p
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private prime q
+
+
+
+
+
+
+ u
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private coefficient
+
+
+
+
+
+
+ randomPayload
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data to return on decryption error, instead of throwing
+(needed for constant-time processing)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Throws:
+
+
+
+
+
+
+
on decryption error, unless randomPayload
is given
+
+
+
+
+
+
+ Type
+
+
+
+Error
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<String>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) encrypt(data, n, e) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public modulus
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public exponent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) generate(bits, e) → {Object}
+
+
+
+
+
+
+
+
Generate a new random private key B bits long with public exponent E.
+
When possible, webCrypto or nodeCrypto is used. Otherwise, primes are generated using
+40 rounds of the Miller-Rabin probabilistic random prime generation algorithm.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ bits
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ RSA bit length
+
+
+
+
+
+
+ e
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ RSA public exponent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+ See:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
RSA public modulus, RSA public exponent, RSA private exponent,
+RSA private prime p, RSA private prime q, u = p ** -1 mod q
+
+
+
+
+
+
+ Type
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) sign(hashAlgo, data, n, e, d, p, q, u, hashed) → {Promise.<Uint8Array>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public modulus
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public exponent
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private exponent
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private prime p
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private prime q
+
+
+
+
+
+
+ u
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private coefficient
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) validateParams(n, e, d, p, q, u) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Validate RSA parameters
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public modulus
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public exponent
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private exponent
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private prime p
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA private prime q
+
+
+
+
+
+
+ u
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA inverse of p w.r.t. q
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Whether params are valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) verify(hashAlgo, data, s, n, e, hashed) → {Boolean}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Message
+
+
+
+
+
+
+ s
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Signature
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public modulus
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ RSA public exponent
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Hashed message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+ Type
+
+
+
+Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, inner) privateToJWK(hashAlgo, n, e, d, p, q, u)
+
+
+
+
+
+
+
+
Convert Openpgp private key params to jwk key according to
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ d
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ p
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ q
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ u
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (inner) publicToJWK(hashAlgo, n, e)
+
+
+
+
+
+
+
+
Convert Openpgp key public params to jwk key according to
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ n
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ e
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_random.html b/docs/module-crypto_random.html
new file mode 100644
index 000000000..fa8b2c6cd
--- /dev/null
+++ b/docs/module-crypto_random.html
@@ -0,0 +1,516 @@
+
+
+
+
+ JSDoc: Module: crypto/random
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/random
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides tools for retrieving secure randomness from browsers or Node.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) getRandomBigInteger(min, max) → {Promise.<module:BigInteger>}
+
+
+
+
+
+
+
+
Create a secure random BigInteger that is greater than or equal to min and less than max.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ min
+
+
+
+
+
+module:BigInteger
+
+
+
+
+
+
+
+
+
+ Lower bound, included
+
+
+
+
+
+
+ max
+
+
+
+
+
+module:BigInteger
+
+
+
+
+
+
+
+
+
+ Upper bound, excluded
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<module:BigInteger>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) getRandomBytes(length) → {Uint8Array}
+
+
+
+
+
+
+
+
Retrieve secure random byte array of the specified length
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ length
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+ Length in bytes to generate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-crypto_signature.html b/docs/module-crypto_signature.html
new file mode 100644
index 000000000..accef42e1
--- /dev/null
+++ b/docs/module-crypto_signature.html
@@ -0,0 +1,917 @@
+
+
+
+
+ JSDoc: Module: crypto/signature
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: crypto/signature
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides functions for asymmetric signing and signature verification
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (async, static) parseSignatureParams(algo, signature) → {Promise.<Object>}
+
+
+
+
+
+
+
+
Parse signature in binary form to get the parameters.
+The returned values are only padded for EdDSA, since in the other cases their expected length
+depends on the key params, hence we delegate the padding to the signature verification function.
+See RFC 4880 9.1
+See RFC 4880 5.2.2.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Public key algorithm
+
+
+
+
+
+
+ signature
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data for which the signature was created
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
True if signature is valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Object>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) sign(algo, hashAlgo, publicKeyParams, privateKeyParams, data, hashed) → {Promise.<Object>}
+
+
+
+
+
+
+
+
Creates a signature on data using specified algorithms and private key parameters.
+See RFC 4880 9.1
+and RFC 4880 9.4
+for public key and hash algorithms.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Public key algorithm
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm
+
+
+
+
+
+
+ publicKeyParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Algorithm-specific public and private key parameters
+
+
+
+
+
+
+ privateKeyParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Algorithm-specific public and private key parameters
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data to be signed
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed data
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Signature Object containing named signature parameters.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Object>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async, static) verify(algo, hashAlgo, signature, publicParams, data, hashed) → {Promise.<Boolean>}
+
+
+
+
+
+
+
+
Verifies the signature provided for data using specified algorithms and public key parameters.
+See RFC 4880 9.1
+and RFC 4880 9.4
+for public key and hash algorithms.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ algo
+
+
+
+
+
+module:enums.publicKey
+
+
+
+
+
+
+
+
+
+ Public key algorithm
+
+
+
+
+
+
+ hashAlgo
+
+
+
+
+
+module:enums.hash
+
+
+
+
+
+
+
+
+
+ Hash algorithm
+
+
+
+
+
+
+ signature
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Named algorithm-specific signature parameters
+
+
+
+
+
+
+ publicParams
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Algorithm-specific public key parameters
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ Data for which the signature was created
+
+
+
+
+
+
+ hashed
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ The hashed data
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
True if signature is valid.
+
+
+
+
+
+
+ Type
+
+
+
+Promise.<Boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-encoding_base64.html b/docs/module-encoding_base64.html
new file mode 100644
index 000000000..11035aa07
--- /dev/null
+++ b/docs/module-encoding_base64.html
@@ -0,0 +1,769 @@
+
+
+
+
+ JSDoc: Module: encoding/base64
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: encoding/base64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+
+ (static) b64ToUint8Array(base64) → {Uint8Array}
+
+
+
+
+
+
+
+
Convert a Base-64 encoded string an array of 8-bit integer
+
Note: accepts both Radix-64 and URL-safe strings
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ base64
+
+
+
+
+
+String
+
+
+
+
+
+
+
+
+
+ Base-64 encoded string to convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
An array of 8-bit integers.
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) decode(data) → {Uint8Array|ReadableStream.<Uint8Array>}
+
+
+
+
+
+
+
+
Convert radix-64 to binary array
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+String
+|
+
+ReadableStream.<String>
+
+
+
+
+
+
+
+
+
+ Radix-64 string to convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Binary array version of input string.
+
+
+
+
+
+
+ Type
+
+
+
+Uint8Array
+|
+
+ReadableStream.<Uint8Array>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) encode(data) → {String|ReadableStream.<String>}
+
+
+
+
+
+
+
+
Convert binary array to radix-64
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+Uint8Array
+|
+
+ReadableStream.<Uint8Array>
+
+
+
+
+
+
+
+
+
+ Uint8Array to convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Radix-64 version of input string.
+
+
+
+
+
+
+ Type
+
+
+
+String
+|
+
+ReadableStream.<String>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (static) uint8ArrayToB64(bytes, url) → {String}
+
+
+
+
+
+
+
+
Convert an array of 8-bit integer to a Base-64 encoded string
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+Uint8Array
+
+
+
+
+
+
+
+
+
+ An array of 8-bit integers to convert
+
+
+
+
+
+
+ url
+
+
+
+
+
+bool
+
+
+
+
+
+
+
+
+
+ If true, output is URL-safe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+
Base-64 encoded string.
+
+
+
+
+
+
+ Type
+
+
+
+String
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home Functions Modules Classes
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/module-enums.html b/docs/module-enums.html
index 848ff7295..af3da9526 100644
--- a/docs/module-enums.html
+++ b/docs/module-enums.html
@@ -148,6 +148,29 @@ Properties:
+
+
+
+
+
+
+
+ gcm
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
@@ -212,7 +235,7 @@ Properties:
Source:
@@ -476,7 +499,7 @@ Properties:
Source:
@@ -671,7 +694,7 @@ Properties:
Source:
@@ -1924,7 +1947,7 @@ Properties:
Source:
@@ -2068,6 +2091,29 @@ Properties:
+
+
+
+ seipdv2
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2105,7 +2151,7 @@ Properties:
Source:
@@ -2328,6 +2374,52 @@ Properties:
+
+
+
+
+
+
+
+ sha3_256
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sha3_512
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
@@ -2369,7 +2461,7 @@ Properties:
Source:
@@ -2635,7 +2727,7 @@ Properties:
Source:
@@ -2830,7 +2922,7 @@ Properties:
Source:
@@ -3306,6 +3398,29 @@ Properties:
+
+
+
+
+
+
+
+ padding
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
@@ -3347,7 +3462,7 @@ Properties:
Source:
@@ -3599,52 +3714,6 @@ Properties:
-
-
- ed25519Legacy
-
-
-
-
-
-Integer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- eddsa
-
-
-
-
-
-Integer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
aedh
@@ -3819,7 +3888,7 @@ Properties:
Source:
@@ -4037,7 +4106,7 @@ Properties:
Source:
@@ -4168,6 +4237,29 @@ Properties:
+
+
+
+
+
+
+
+ argon2
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
@@ -4232,7 +4324,7 @@ Properties:
Source:
@@ -4749,7 +4841,7 @@ Properties:
Source:
@@ -5048,7 +5140,7 @@ Properties:
- issuer
+ issuerKeyID
@@ -5409,6 +5501,29 @@ Properties:
+
+
+
+
+
+
+
+ preferredCipherSuites
+
+
+
+
+
+Integer
+
+
+
+
+
+
+
+
+
@@ -5450,7 +5565,7 @@ Properties:
Source:
@@ -5517,29 +5632,6 @@ Properties:
-
-
- plaintext
-
-
-
-
-
-Integer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
idea
@@ -5760,7 +5852,7 @@ Properties:
Source:
@@ -5956,7 +6048,7 @@ Properties:
Source:
@@ -6110,7 +6202,7 @@ Parameters:
Source:
@@ -6326,7 +6418,7 @@ Parameters:
Source:
@@ -6423,13 +6515,13 @@ Returns:
- Home Functions Modules Classes
+ Home Functions Modules Classes
diff --git a/docs/module-key_Subkey-Subkey.html b/docs/module-key_Subkey-Subkey.html
index 5f486957b..87f2ab7f2 100644
--- a/docs/module-key_Subkey-Subkey.html
+++ b/docs/module-key_Subkey-Subkey.html
@@ -28,7 +28,8 @@ Class: Subkey