mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00
Compare commits
16 Commits
main
...
@proton/v6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e28b39db5f | ||
![]() |
61c744e769 | ||
![]() |
299342946d | ||
![]() |
55de9c0dc4 | ||
![]() |
8e497f419b | ||
![]() |
f1f7ca972f | ||
![]() |
0ebf5797a5 | ||
![]() |
9fe278241a | ||
![]() |
7cf978092b | ||
![]() |
55f8ab2629 | ||
![]() |
bec09a16fa | ||
![]() |
9cf7a384aa | ||
![]() |
44327e9c95 | ||
![]() |
07bedf3392 | ||
![]() |
d8bdf2bed3 | ||
![]() |
cc79face33 |
@ -1,10 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
# The redundant target-branch directive is needed to set two different update schedules for npm,
|
||||
# working around a dependabot limitation:
|
||||
# see https://github.com/dependabot/dependabot-core/issues/1778#issuecomment-1988140219 .
|
||||
target-branch: main
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
@ -30,4 +26,4 @@ updates:
|
||||
- "@noble*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
- "patch"
|
3
.github/test-suite/config.json.template
vendored
3
.github/test-suite/config.json.template
vendored
@ -4,7 +4,8 @@
|
||||
"id": "sop-openpgpjs-branch",
|
||||
"path": "__SOP_OPENPGPJS__",
|
||||
"env": {
|
||||
"OPENPGPJS_PATH": "__OPENPGPJS_BRANCH__"
|
||||
"OPENPGPJS_PATH": "__OPENPGPJS_BRANCH__",
|
||||
"OPENPGPJS_CUSTOM_PROFILES": "{\"generate-key\": { \"post-quantum\": { \"description\": \"generate post-quantum v6 keys (relying on ML-DSA + ML-KEM)\", \"options\": { \"type\": \"pqc\", \"config\": { \"v6Keys\": true } } } } }"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
@ -106,7 +106,6 @@ jobs:
|
||||
npx playwright install --with-deps firefox
|
||||
|
||||
- name: Install WebKit # caching not possible, external shared libraries required
|
||||
if: ${{ matrix.runner == 'macos-latest' }} # do not install on ubuntu, since the X25519 WebCrypto implementation has issues
|
||||
run: npx playwright install --with-deps webkit
|
||||
|
||||
- name: Run browser tests
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
509
docs/global.html
509
docs/global.html
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
179
docs/module-type_kdf_params.html
Normal file
179
docs/module-type_kdf_params.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
616
docs/type_enum.module_js.html
Normal file
616
docs/type_enum.module_js.html
Normal file
File diff suppressed because one or more lines are too long
35
openpgp.d.ts
vendored
35
openpgp.d.ts
vendored
@ -326,8 +326,10 @@ interface Config {
|
||||
showVersion: boolean;
|
||||
showComment: boolean;
|
||||
aeadProtect: boolean;
|
||||
ignoreSEIPDv2FeatureFlag: boolean;
|
||||
allowUnauthenticatedMessages: boolean;
|
||||
allowUnauthenticatedStream: boolean;
|
||||
allowForwardedMessages: boolean;
|
||||
minRSABits: number;
|
||||
passwordCollisionCheck: boolean;
|
||||
ignoreUnsupportedPackets: boolean;
|
||||
@ -702,7 +704,7 @@ export type EllipticCurveName = 'ed25519Legacy' | 'curve25519Legacy' | 'nistP256
|
||||
interface GenerateKeyOptions {
|
||||
userIDs: MaybeArray<UserID>;
|
||||
passphrase?: string;
|
||||
type?: 'ecc' | 'rsa' | 'curve25519' | 'curve448';
|
||||
type?: 'ecc' | 'rsa' | 'curve25519' | 'curve448' | 'pqc';
|
||||
curve?: EllipticCurveName;
|
||||
rsaBits?: number;
|
||||
keyExpirationTime?: number;
|
||||
@ -713,8 +715,9 @@ interface GenerateKeyOptions {
|
||||
}
|
||||
export type KeyOptions = GenerateKeyOptions;
|
||||
|
||||
export interface SubkeyOptions extends Pick<GenerateKeyOptions, 'type' | 'curve' | 'rsaBits' | 'keyExpirationTime' | 'date' | 'config'> {
|
||||
export interface SubkeyOptions extends Pick<GenerateKeyOptions, 'type' | 'curve' | 'rsaBits' | 'keyExpirationTime' | 'date' | 'config' > {
|
||||
sign?: boolean;
|
||||
forwarding?: boolean;
|
||||
}
|
||||
|
||||
export declare class KeyID {
|
||||
@ -822,7 +825,7 @@ export namespace enums {
|
||||
aeadEncryptedData = 20
|
||||
}
|
||||
|
||||
export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsaLegacy' | 'aedh' | 'aedsa' | 'ed25519' | 'x25519' | 'ed448' | 'x448';
|
||||
export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsaLegacy' | 'aedh' | 'aedsa' | 'ed25519' | 'x25519' | 'ed448' | 'x448' | 'pqc_mlkem_x25519' | 'pqc_mldsa_ed25519';
|
||||
export enum publicKey {
|
||||
rsaEncryptSign = 1,
|
||||
rsaEncrypt = 2,
|
||||
@ -837,7 +840,9 @@ export namespace enums {
|
||||
x25519 = 25,
|
||||
x448 = 26,
|
||||
ed25519 = 27,
|
||||
ed448 = 28
|
||||
ed448 = 28,
|
||||
pqc_mlkem_x25519 = 105,
|
||||
pqc_mldsa_ed25519 = 107
|
||||
}
|
||||
|
||||
export enum curve {
|
||||
@ -891,6 +896,7 @@ export namespace enums {
|
||||
encryptStorage = 8,
|
||||
splitPrivateKey = 16,
|
||||
authentication = 32,
|
||||
forwardedCommunication = 64,
|
||||
sharedPrivateKey = 128
|
||||
}
|
||||
|
||||
@ -937,3 +943,24 @@ export namespace enums {
|
||||
gnu = 101
|
||||
}
|
||||
}
|
||||
|
||||
export declare class Argon2S2K {
|
||||
static reloadWasmModule(): void;
|
||||
static ARGON2_WASM_MEMORY_THRESHOLD_RELOAD: number;
|
||||
constructor(config: Config);
|
||||
salt: Uint8Array;
|
||||
/** @throws Argon2OutOfMemoryError */
|
||||
produceKey(passphrase: string, keySize: number): Promise<Uint8Array>;
|
||||
}
|
||||
|
||||
interface KDFParamsData {
|
||||
version: number;
|
||||
hash: enums.hash;
|
||||
cipher: enums.symmetric;
|
||||
replacementFingerprint?: Uint8Array;
|
||||
}
|
||||
|
||||
export class KDFParams {
|
||||
constructor(data: KDFParamsData);
|
||||
write(forReplacementParams?: boolean): Uint8Array;
|
||||
}
|
||||
|
589
package-lock.json
generated
589
package-lock.json
generated
@ -1,17 +1,19 @@
|
||||
{
|
||||
"name": "openpgp",
|
||||
"version": "6.1.0",
|
||||
"name": "@protontech/openpgp",
|
||||
"version": "6.1.0-patch.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "openpgp",
|
||||
"version": "6.1.0",
|
||||
"name": "@protontech/openpgp",
|
||||
"version": "6.1.0-patch.0",
|
||||
"license": "LGPL-3.0+",
|
||||
"devDependencies": {
|
||||
"@noble/ciphers": "^1.2.1",
|
||||
"@noble/curves": "^1.8.1",
|
||||
"@noble/ciphers": "^1.0.0",
|
||||
"@noble/curves": "^1.7.0",
|
||||
"@noble/ed25519": "^1.7.3",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@noble/post-quantum": "^0.2.1",
|
||||
"@openpgp/jsdoc": "^3.6.11",
|
||||
"@openpgp/seek-bzip": "^1.0.5-git",
|
||||
"@openpgp/tweetnacl": "^1.0.4-1",
|
||||
@ -45,9 +47,9 @@
|
||||
"eslint-plugin-chai-friendly": "^0.7.4",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-unicorn": "^48.0.1",
|
||||
"fflate": "^0.8.2",
|
||||
"fflate": "^0.7.4",
|
||||
"mocha": "^10.7.3",
|
||||
"playwright": "^1.51.1",
|
||||
"playwright": "^1.48.2",
|
||||
"rollup": "^4.24.2",
|
||||
"sinon": "^18.0.1",
|
||||
"ts-node": "^10.9.2",
|
||||
@ -929,9 +931,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ciphers": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz",
|
||||
"integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.0.0.tgz",
|
||||
"integrity": "sha512-wH5EHOmLi0rEazphPbecAzmjd12I6/Yv/SiHdkA9LSycsQk7RuuTp7am5/o62qYr0RScE7Pc9icXGBbsr6cesA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -942,13 +944,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz",
|
||||
"integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==",
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz",
|
||||
"integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.7.1"
|
||||
"@noble/hashes": "1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
@ -957,10 +959,22 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ed25519": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
|
||||
"integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz",
|
||||
"integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==",
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz",
|
||||
"integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -970,6 +984,19 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/post-quantum": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/post-quantum/-/post-quantum-0.2.1.tgz",
|
||||
"integrity": "sha512-ImgfMp9notXSEocz464o1AefYfFWEkkszKMGO+ZiTn73yIBFeNyEHKQUMS+SheJwSNymldSts6YyVcQDjcnVVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.6.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -2763,85 +2790,6 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-chrome/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"internal-ip": "^6.2.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-chrome/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-chrome/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-chrome/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-commands": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-commands/-/test-runner-commands-0.9.0.tgz",
|
||||
@ -2856,11 +2804,10 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-commands/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"node_modules/@web/test-runner-core": {
|
||||
"version": "0.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-core/-/test-runner-core-0.13.3.tgz",
|
||||
"integrity": "sha512-ilDqF/v2sj0sD69FNSIDT7uw4M1yTVedLBt32/lXy3MMi6suCM7m/ZlhsBy8PXhf879WMvzBOl/vhJBpEMB9vA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -2872,8 +2819,8 @@
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"@web/dev-server-core": "^0.7.2",
|
||||
"chokidar": "^3.4.3",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
@ -2895,11 +2842,11 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-commands/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"node_modules/@web/test-runner-core/node_modules/@web/dev-server-core/node_modules/chokidar": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
||||
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
||||
"extraneous": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
@ -2911,21 +2858,7 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-commands/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-commands/node_modules/source-map": {
|
||||
"node_modules/@web/test-runner-core/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
@ -2952,85 +2885,6 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-coverage-v8/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"internal-ip": "^6.2.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-coverage-v8/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-coverage-v8/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-coverage-v8/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-mocha": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-mocha/-/test-runner-mocha-0.9.0.tgz",
|
||||
@ -3044,85 +2898,6 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-mocha/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"internal-ip": "^6.2.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-mocha/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-mocha/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-mocha/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-playwright": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-playwright/-/test-runner-playwright-0.11.0.tgz",
|
||||
@ -3138,85 +2913,6 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-playwright/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"internal-ip": "^6.2.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-playwright/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-playwright/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-playwright/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-webdriver": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@web/test-runner-webdriver/-/test-runner-webdriver-0.8.0.tgz",
|
||||
@ -3231,154 +2927,6 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-webdriver/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"internal-ip": "^6.2.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-webdriver/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-webdriver/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner-webdriver/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner/node_modules/@web/test-runner-core": {
|
||||
"name": "@openpgp/wtr-test-runner-core",
|
||||
"version": "0.13.4-patch.0",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/wtr-test-runner-core/-/wtr-test-runner-core-0.13.4-patch.0.tgz",
|
||||
"integrity": "sha512-vcQXfDvDyVhQo4IpqHk/ksNayC/hKNjaN7ykXygtrGmOSdsVs1IGopNVzOgjjeISpZUytHnivJNEMtNWNPGgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@types/babel__code-frame": "^7.0.2",
|
||||
"@types/co-body": "^6.1.0",
|
||||
"@types/convert-source-map": "^2.0.0",
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/istanbul-lib-coverage": "^2.0.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@web/browser-logs": "^0.4.0",
|
||||
"@web/dev-server-core": "^0.7.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"co-body": "^6.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debounce": "^1.2.0",
|
||||
"dependency-graph": "^0.11.0",
|
||||
"globby": "^11.0.1",
|
||||
"internal-ip": "^6.2.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.0.2",
|
||||
"log-update": "^4.0.0",
|
||||
"nanocolors": "^0.2.1",
|
||||
"nanoid": "^3.1.25",
|
||||
"open": "^8.0.2",
|
||||
"picomatch": "^2.2.2",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner/node_modules/readdirp": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@web/test-runner/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
@ -6554,11 +6102,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"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",
|
||||
@ -9995,13 +9542,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.51.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz",
|
||||
"integrity": "sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==",
|
||||
"version": "1.48.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz",
|
||||
"integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.51.1"
|
||||
"playwright-core": "1.48.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@ -10014,9 +9561,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.51.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz",
|
||||
"integrity": "sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==",
|
||||
"version": "1.48.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz",
|
||||
"integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
21
package.json
21
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "openpgp",
|
||||
"name": "@protontech/openpgp",
|
||||
"description": "OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.",
|
||||
"version": "6.1.0",
|
||||
"version": "6.1.0-patch.0",
|
||||
"license": "LGPL-3.0+",
|
||||
"homepage": "https://openpgpjs.org/",
|
||||
"engines": {
|
||||
@ -59,12 +59,14 @@
|
||||
"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 --follow-tags && npm publish"
|
||||
"postversion": "git push && git push --tags && npm publish"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@noble/ciphers": "^1.2.1",
|
||||
"@noble/curves": "^1.8.1",
|
||||
"@noble/ciphers": "^1.0.0",
|
||||
"@noble/curves": "^1.7.0",
|
||||
"@noble/ed25519": "^1.7.3",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@noble/post-quantum": "^0.2.1",
|
||||
"@openpgp/jsdoc": "^3.6.11",
|
||||
"@openpgp/seek-bzip": "^1.0.5-git",
|
||||
"@openpgp/tweetnacl": "^1.0.4-1",
|
||||
@ -98,9 +100,9 @@
|
||||
"eslint-plugin-chai-friendly": "^0.7.4",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-unicorn": "^48.0.1",
|
||||
"fflate": "^0.8.2",
|
||||
"fflate": "^0.7.4",
|
||||
"mocha": "^10.7.3",
|
||||
"playwright": "^1.51.1",
|
||||
"playwright": "^1.48.2",
|
||||
"rollup": "^4.24.2",
|
||||
"sinon": "^18.0.1",
|
||||
"ts-node": "^10.9.2",
|
||||
@ -110,11 +112,10 @@
|
||||
"web-streams-polyfill": "^4.0.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@web/dev-server-core": "npm:@openpgp/wtr-dev-server-core@0.7.3-patch.1",
|
||||
"@web/test-runner-core": "npm:@openpgp/wtr-test-runner-core@0.13.4-patch.0"
|
||||
"@web/dev-server-core": "npm:@openpgp/wtr-dev-server-core@0.7.3-patch.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openpgpjs/openpgpjs"
|
||||
"url": "https://github.com/ProtonMail/openpgpjs"
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,15 @@ const terserOptions = {
|
||||
compress: {
|
||||
unsafe: true
|
||||
},
|
||||
/**
|
||||
* The Babel plugin `@babel/plugin-transform-regenerator` used in the web-app Jest tests
|
||||
* (as part of @babel/preset-env) introduces a bug when transforming the minified lightweight built.
|
||||
* The issue is that the mangled `ArrayStream` class name (`n` in the specific case) gets wrongly
|
||||
* reused and shadowed by a local variable in the `readPacket` function (see https://github.com/babel/babel/issues/16334).
|
||||
* As a workaround for the problem, and to not have to amend the babel config for each monorepo workspace, we disable mangling
|
||||
* the specific class name.
|
||||
*/
|
||||
mangle: { reserved: ['ArrayStream'] },
|
||||
output: {
|
||||
comments: '/^(?:!|#__)/',
|
||||
preserve_annotations: true
|
||||
@ -61,8 +70,8 @@ const nodeBuild = {
|
||||
input: 'src/index.js',
|
||||
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.cjs', format: 'cjs', name: 'openpgp', banner, intro },
|
||||
{ file: 'dist/node/openpgp.min.cjs', format: 'cjs', name: 'openpgp', 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 })),
|
||||
@ -85,8 +94,8 @@ const fullBrowserBuild = {
|
||||
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 },
|
||||
{ file: 'dist/openpgp.js', format: 'iife', name: 'openpgp', banner, intro },
|
||||
{ file: 'dist/openpgp.min.js', format: 'iife', name: 'openpgp', 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 }
|
||||
].map(options => ({ ...options, inlineDynamicImports: true })),
|
||||
@ -100,6 +109,13 @@ const fullBrowserBuild = {
|
||||
commonjs({
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies)
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
@ -127,6 +143,13 @@ const lightweightBrowserBuild = {
|
||||
commonjs({
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies)
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
'OpenPGP.js VERSION': `OpenPGP.js ${pkg.version}`,
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
@ -145,7 +168,7 @@ const testBuild = {
|
||||
plugins: [
|
||||
alias({
|
||||
entries: {
|
||||
openpgp: `./dist/${process.env.npm_config_lightweight ? 'lightweight/' : ''}openpgp.mjs`
|
||||
'@protontech/openpgp': `./dist/${process.env.npm_config_lightweight ? 'lightweight/' : ''}openpgp.mjs`
|
||||
}
|
||||
}),
|
||||
resolve({
|
||||
@ -158,6 +181,13 @@ const testBuild = {
|
||||
ignore: nodeBuiltinModules.concat(nodeDependencies),
|
||||
requireReturnsDefault: 'preferred'
|
||||
}),
|
||||
replace({
|
||||
include: 'node_modules/@noble/ed25519/**',
|
||||
// Rollup ignores the `browser: { crypto: false }` directive in package.json, since `exports` are present,
|
||||
// hence we need to manually drop it.
|
||||
"import * as nodeCrypto from 'crypto'": 'const nodeCrypto = null',
|
||||
delimiters: ['', '']
|
||||
}),
|
||||
replace({
|
||||
"import { createRequire } from 'module';": 'const createRequire = () => () => {}',
|
||||
delimiters: ['', '']
|
||||
|
@ -50,6 +50,14 @@ export default {
|
||||
* @property {Boolean} aeadProtect
|
||||
*/
|
||||
aeadProtect: false,
|
||||
/**
|
||||
* Whether to disable encrypton using SEIPDv2 even if the encryption keys include the SEIPDv2 feature flag.
|
||||
* If true, SEIPDv1 (i.e. no AEAD) packets are always used instead.
|
||||
* SEIPDv2 is a more secure and faster choice, but it is not necessarily compatible with other libs and our mobile apps.
|
||||
* @memberof module:config
|
||||
* @property {Boolean} ignoreSEIPDv2FeatureFlag
|
||||
*/
|
||||
ignoreSEIPDv2FeatureFlag: false,
|
||||
/**
|
||||
* When reading OpenPGP v4 private keys (e.g. those generated in OpenPGP.js when not setting `config.v5Keys = true`)
|
||||
* which were encrypted by OpenPGP.js v5 (or older) using `config.aeadProtect = true`,
|
||||
@ -149,6 +157,13 @@ export default {
|
||||
* @property {Boolean} allowUnauthenticatedStream
|
||||
*/
|
||||
allowUnauthenticatedStream: false,
|
||||
/**
|
||||
* Allow decrypting forwarded messages, using keys with 0x40 ('forwarded communication') flag.
|
||||
* Note: this is related to a **non-standard feature**.
|
||||
* @memberof module:config
|
||||
* @property {Boolean} allowForwardedMessages
|
||||
*/
|
||||
allowForwardedMessages: 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.
|
||||
|
@ -73,8 +73,9 @@ async function OCB(cipher, key) {
|
||||
// `encipher` and `decipher` cannot be async, since `crypt` shares state across calls,
|
||||
// hence its execution cannot be broken up.
|
||||
// As a result, WebCrypto cannot currently be used for `encipher`.
|
||||
const encipher = block => nobleAesCbc(key, zeroBlock, { disablePadding: true }).encrypt(block);
|
||||
const decipher = block => nobleAesCbc(key, zeroBlock, { disablePadding: true }).decrypt(block);
|
||||
const aes = nobleAesCbc(key, zeroBlock, { disablePadding: true });
|
||||
const encipher = block => aes.encrypt(block);
|
||||
const decipher = block => aes.decrypt(block);
|
||||
let mask;
|
||||
|
||||
constructKeyVariables(cipher, key);
|
||||
|
@ -23,16 +23,21 @@
|
||||
* @module crypto/crypto
|
||||
*/
|
||||
|
||||
import { rsa, elliptic, elgamal, dsa } from './public_key';
|
||||
import { rsa, elliptic, elgamal, dsa, hmac, postQuantum } from './public_key';
|
||||
import { getRandomBytes } from './random';
|
||||
import { getCipherParams } from './cipher';
|
||||
import ECDHSymkey from '../type/ecdh_symkey';
|
||||
import ShortByteString from '../type/short_byte_string';
|
||||
import { computeDigest, getHashByteLength } from './hash';
|
||||
import config from '../config';
|
||||
import KDFParams from '../type/kdf_params';
|
||||
import { SymAlgoEnum, AEADEnum, HashEnum } from '../type/enum';
|
||||
import enums from '../enums';
|
||||
import util from '../util';
|
||||
import OID from '../type/oid';
|
||||
import { UnsupportedError } from '../packet/packet';
|
||||
import ECDHXSymmetricKey from '../type/ecdh_x_symkey';
|
||||
import { getAEADMode } from './cipherMode';
|
||||
|
||||
/**
|
||||
* Encrypts data using specified algorithm and public key parameters.
|
||||
@ -40,12 +45,13 @@ import ECDHXSymmetricKey from '../type/ecdh_x_symkey';
|
||||
* @param {module:enums.publicKey} keyAlgo - Public key algorithm
|
||||
* @param {module:enums.symmetric|null} symmetricAlgo - Cipher algorithm (v3 only)
|
||||
* @param {Object} publicParams - Algorithm-specific public key parameters
|
||||
* @param {Uint8Array} data - Session key data to be encrypted
|
||||
* @param {Object} privateParams - Algorithm-specific private key parameters
|
||||
* @param {Uint8Array} data - Data to be encrypted
|
||||
* @param {Uint8Array} fingerprint - Recipient fingerprint
|
||||
* @returns {Promise<Object>} Encrypted session key parameters.
|
||||
* @async
|
||||
*/
|
||||
export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, data, fingerprint) {
|
||||
export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, privateParams, data, fingerprint) {
|
||||
switch (keyAlgo) {
|
||||
case enums.publicKey.rsaEncrypt:
|
||||
case enums.publicKey.rsaEncryptSign: {
|
||||
@ -75,6 +81,27 @@ export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, dat
|
||||
const C = ECDHXSymmetricKey.fromObject({ algorithm: symmetricAlgo, wrappedKey });
|
||||
return { ephemeralPublicKey, C };
|
||||
}
|
||||
case enums.publicKey.aead: {
|
||||
if (!privateParams) {
|
||||
throw new Error('Cannot encrypt with symmetric key missing private parameters');
|
||||
}
|
||||
const { cipher: algo } = publicParams;
|
||||
const algoValue = algo.getValue();
|
||||
const { keyMaterial } = privateParams;
|
||||
const aeadMode = config.preferredAEADAlgorithm;
|
||||
const mode = getAEADMode(config.preferredAEADAlgorithm);
|
||||
const { ivLength } = mode;
|
||||
const iv = getRandomBytes(ivLength);
|
||||
const modeInstance = await mode(algoValue, keyMaterial);
|
||||
const c = await modeInstance.encrypt(data, iv, new Uint8Array());
|
||||
return { aeadMode: new AEADEnum(aeadMode), iv, c: new ShortByteString(c) };
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { eccPublicKey, mlkemPublicKey } = publicParams;
|
||||
const { eccCipherText, mlkemCipherText, wrappedKey } = await postQuantum.kem.encrypt(keyAlgo, eccPublicKey, mlkemPublicKey, data);
|
||||
const C = ECDHXSymmetricKey.fromObject({ algorithm: symmetricAlgo, wrappedKey });
|
||||
return { eccCipherText, mlkemCipherText, C };
|
||||
}
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
@ -94,8 +121,8 @@ export async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, dat
|
||||
* @throws {Error} on sensitive decryption error, unless `randomPayload` is given
|
||||
* @async
|
||||
*/
|
||||
export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, sessionKeyParams, fingerprint, randomPayload) {
|
||||
switch (algo) {
|
||||
export async function publicKeyDecrypt(keyAlgo, publicKeyParams, privateKeyParams, sessionKeyParams, fingerprint, randomPayload) {
|
||||
switch (keyAlgo) {
|
||||
case enums.publicKey.rsaEncryptSign:
|
||||
case enums.publicKey.rsaEncrypt: {
|
||||
const { c } = sessionKeyParams;
|
||||
@ -125,7 +152,24 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
|
||||
throw new Error('AES session key expected');
|
||||
}
|
||||
return elliptic.ecdhX.decrypt(
|
||||
algo, ephemeralPublicKey, C.wrappedKey, A, k);
|
||||
keyAlgo, ephemeralPublicKey, C.wrappedKey, A, k);
|
||||
}
|
||||
case enums.publicKey.aead: {
|
||||
const { cipher: algo } = publicKeyParams;
|
||||
const algoValue = algo.getValue();
|
||||
const { keyMaterial } = privateKeyParams;
|
||||
|
||||
const { aeadMode, iv, c } = sessionKeyParams;
|
||||
|
||||
const mode = getAEADMode(aeadMode.getValue());
|
||||
const modeInstance = await mode(algoValue, keyMaterial);
|
||||
return modeInstance.decrypt(c.data, iv, new Uint8Array());
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { eccSecretKey, mlkemSecretKey } = privateKeyParams;
|
||||
const { eccPublicKey, mlkemPublicKey } = publicKeyParams;
|
||||
const { eccCipherText, mlkemCipherText, C } = sessionKeyParams;
|
||||
return postQuantum.kem.decrypt(keyAlgo, eccCipherText, mlkemCipherText, eccSecretKey, eccPublicKey, mlkemSecretKey, mlkemPublicKey, C.wrappedKey);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unknown public key encryption algorithm.');
|
||||
@ -191,6 +235,23 @@ export function parsePublicKeyParams(algo, bytes) {
|
||||
const A = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(algo)); read += A.length;
|
||||
return { read, publicParams: { A } };
|
||||
}
|
||||
case enums.publicKey.hmac:
|
||||
case enums.publicKey.aead: {
|
||||
const algo = new SymAlgoEnum(); read += algo.read(bytes);
|
||||
const digestLength = getHashByteLength(enums.hash.sha256);
|
||||
const digest = bytes.subarray(read, read + digestLength); read += digestLength;
|
||||
return { read: read, publicParams: { cipher: algo, digest } };
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const eccPublicKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.x25519)); read += eccPublicKey.length;
|
||||
const mlkemPublicKey = util.readExactSubarray(bytes, read, read + 1184); read += mlkemPublicKey.length;
|
||||
return { read, publicParams: { eccPublicKey, mlkemPublicKey } };
|
||||
}
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const eccPublicKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.ed25519)); read += eccPublicKey.length;
|
||||
const mldsaPublicKey = util.readExactSubarray(bytes, read, read + 1952); read += mldsaPublicKey.length;
|
||||
return { read, publicParams: { eccPublicKey, mldsaPublicKey } };
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedError('Unknown public key encryption algorithm.');
|
||||
}
|
||||
@ -200,10 +261,10 @@ export function parsePublicKeyParams(algo, bytes) {
|
||||
* Parse private key material in binary form to get the key parameters
|
||||
* @param {module:enums.publicKey} algo - The key algorithm
|
||||
* @param {Uint8Array} bytes - The key material to parse
|
||||
* @param {Object} publicParams - (ECC only) public params, needed to format some private params
|
||||
* @param {Object} publicParams - (ECC and symmetric only) public params, needed to format some private params
|
||||
* @returns {{ read: Number, privateParams: Object }} Number of read bytes plus the key parameters referenced by name.
|
||||
*/
|
||||
export function parsePrivateKeyParams(algo, bytes, publicParams) {
|
||||
export async function parsePrivateKeyParams(algo, bytes, publicParams) {
|
||||
let read = 0;
|
||||
switch (algo) {
|
||||
case enums.publicKey.rsaEncrypt:
|
||||
@ -248,6 +309,32 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) {
|
||||
const k = util.readExactSubarray(bytes, read, read + payloadSize); read += k.length;
|
||||
return { read, privateParams: { k } };
|
||||
}
|
||||
case enums.publicKey.hmac: {
|
||||
const { cipher: algo } = publicParams;
|
||||
const keySize = getHashByteLength(algo.getValue());
|
||||
const hashSeed = bytes.subarray(read, read + 32); read += 32;
|
||||
const keyMaterial = bytes.subarray(read, read + keySize); read += keySize;
|
||||
return { read, privateParams: { hashSeed, keyMaterial } };
|
||||
}
|
||||
case enums.publicKey.aead: {
|
||||
const { cipher: algo } = publicParams;
|
||||
const hashSeed = bytes.subarray(read, read + 32); read += 32;
|
||||
const { keySize } = getCipherParams(algo.getValue());
|
||||
const keyMaterial = bytes.subarray(read, read + keySize); read += keySize;
|
||||
return { read, privateParams: { hashSeed, keyMaterial } };
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const eccSecretKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.x25519)); read += eccSecretKey.length;
|
||||
const mlkemSeed = util.readExactSubarray(bytes, read, read + 64); read += mlkemSeed.length;
|
||||
const { mlkemSecretKey } = await postQuantum.kem.mlkemExpandSecretSeed(algo, mlkemSeed);
|
||||
return { read, privateParams: { eccSecretKey, mlkemSecretKey, mlkemSeed } };
|
||||
}
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const eccSecretKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.ed25519)); read += eccSecretKey.length;
|
||||
const mldsaSeed = util.readExactSubarray(bytes, read, read + 32); read += mldsaSeed.length;
|
||||
const { mldsaSecretKey } = await postQuantum.signature.mldsaExpandSecretSeed(algo, mldsaSeed);
|
||||
return { read, privateParams: { eccSecretKey, mldsaSecretKey, mldsaSeed } };
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedError('Unknown public key encryption algorithm.');
|
||||
}
|
||||
@ -297,6 +384,26 @@ export function parseEncSessionKeyParams(algo, bytes) {
|
||||
const C = new ECDHXSymmetricKey(); C.read(bytes.subarray(read));
|
||||
return { ephemeralPublicKey, C };
|
||||
}
|
||||
// Algorithm-Specific Fields for symmetric AEAD encryption:
|
||||
// - AEAD algorithm
|
||||
// - Starting initialization vector
|
||||
// - Symmetric key encryption of "m" dependent on cipher and AEAD mode prefixed with a one-octet length
|
||||
// - An authentication tag generated by the AEAD mode.
|
||||
case enums.publicKey.aead: {
|
||||
const aeadMode = new AEADEnum(); read += aeadMode.read(bytes.subarray(read));
|
||||
const { ivLength } = getAEADMode(aeadMode.getValue());
|
||||
|
||||
const iv = bytes.subarray(read, read + ivLength); read += ivLength;
|
||||
const c = new ShortByteString(); read += c.read(bytes.subarray(read));
|
||||
|
||||
return { aeadMode, iv, c };
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const eccCipherText = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.x25519)); read += eccCipherText.length;
|
||||
const mlkemCipherText = util.readExactSubarray(bytes, read, read + 1088); read += mlkemCipherText.length;
|
||||
const C = new ECDHXSymmetricKey(); C.read(bytes.subarray(read));
|
||||
return { eccCipherText, mlkemCipherText, C }; // eccCipherText || mlkemCipherText || len(C) || C
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedError('Unknown public key encryption algorithm.');
|
||||
}
|
||||
@ -314,9 +421,23 @@ export function serializeParams(algo, params) {
|
||||
enums.publicKey.ed25519,
|
||||
enums.publicKey.x25519,
|
||||
enums.publicKey.ed448,
|
||||
enums.publicKey.x448
|
||||
enums.publicKey.x448,
|
||||
enums.publicKey.aead,
|
||||
enums.publicKey.hmac,
|
||||
enums.publicKey.pqc_mlkem_x25519,
|
||||
enums.publicKey.pqc_mldsa_ed25519
|
||||
]);
|
||||
|
||||
const excludedFields = {
|
||||
[enums.publicKey.pqc_mlkem_x25519]: new Set(['mlkemSecretKey']), // only `mlkemSeed` is serialized
|
||||
[enums.publicKey.pqc_mldsa_ed25519]: new Set(['mldsaSecretKey']) // only `mldsaSeed` is serialized
|
||||
};
|
||||
|
||||
const orderedParams = Object.keys(params).map(name => {
|
||||
if (excludedFields[algo]?.has(name)) {
|
||||
return new Uint8Array();
|
||||
}
|
||||
|
||||
const param = params[name];
|
||||
if (!util.isUint8Array(param)) return param.write();
|
||||
return algosWithNativeRepresentation.has(algo) ? param : util.uint8ArrayToMPI(param);
|
||||
@ -329,10 +450,11 @@ export function serializeParams(algo, params) {
|
||||
* @param {module:enums.publicKey} algo - The public key algorithm
|
||||
* @param {Integer} bits - Bit length for RSA keys
|
||||
* @param {module:type/oid} oid - Object identifier for ECC keys
|
||||
* @param {module:enums.symmetric|enums.hash} symmetric - Hash or cipher algorithm for symmetric keys
|
||||
* @returns {Promise<{ publicParams: {Object}, privateParams: {Object} }>} The parameters referenced by name.
|
||||
* @async
|
||||
*/
|
||||
export function generateParams(algo, bits, oid) {
|
||||
export async function generateParams(algo, bits, oid, symmetric) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.rsaEncrypt:
|
||||
case enums.publicKey.rsaEncryptSign:
|
||||
@ -372,6 +494,24 @@ export function generateParams(algo, bits, oid) {
|
||||
privateParams: { k },
|
||||
publicParams: { A }
|
||||
}));
|
||||
case enums.publicKey.hmac: {
|
||||
const keyMaterial = await hmac.generate(symmetric);
|
||||
return createSymmetricParams(keyMaterial, new HashEnum(symmetric));
|
||||
}
|
||||
case enums.publicKey.aead: {
|
||||
const keyMaterial = generateSessionKey(symmetric);
|
||||
return createSymmetricParams(keyMaterial, new SymAlgoEnum(symmetric));
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519:
|
||||
return postQuantum.kem.generate(algo).then(({ eccSecretKey, eccPublicKey, mlkemSeed, mlkemSecretKey, mlkemPublicKey }) => ({
|
||||
privateParams: { eccSecretKey, mlkemSeed, mlkemSecretKey },
|
||||
publicParams: { eccPublicKey, mlkemPublicKey }
|
||||
}));
|
||||
case enums.publicKey.pqc_mldsa_ed25519:
|
||||
return postQuantum.signature.generate(algo).then(({ eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey }) => ({
|
||||
privateParams: { eccSecretKey, mldsaSeed, mldsaSecretKey },
|
||||
publicParams: { eccPublicKey, mldsaPublicKey }
|
||||
}));
|
||||
case enums.publicKey.dsa:
|
||||
case enums.publicKey.elgamal:
|
||||
throw new Error('Unsupported algorithm for key generation.');
|
||||
@ -380,6 +520,21 @@ export function generateParams(algo, bits, oid) {
|
||||
}
|
||||
}
|
||||
|
||||
async function createSymmetricParams(key, algo) {
|
||||
const seed = getRandomBytes(32);
|
||||
const bindingHash = await computeDigest(enums.hash.sha256,seed);
|
||||
return {
|
||||
privateParams: {
|
||||
hashSeed: seed,
|
||||
keyMaterial: key
|
||||
},
|
||||
publicParams: {
|
||||
cipher: algo,
|
||||
digest: bindingHash
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate algorithm-specific key parameters
|
||||
* @param {module:enums.publicKey} algo - The public key algorithm
|
||||
@ -434,6 +589,30 @@ export async function validateParams(algo, publicParams, privateParams) {
|
||||
const { k } = privateParams;
|
||||
return elliptic.ecdhX.validateParams(algo, A, k);
|
||||
}
|
||||
case enums.publicKey.hmac: {
|
||||
const { cipher: algo, digest } = publicParams;
|
||||
const { hashSeed, keyMaterial } = privateParams;
|
||||
const keySize = getHashByteLength(algo.getValue());
|
||||
return keySize === keyMaterial.length &&
|
||||
util.equalsUint8Array(digest, await computeDigest(enums.hash.sha256, hashSeed));
|
||||
}
|
||||
case enums.publicKey.aead: {
|
||||
const { cipher: algo, digest } = publicParams;
|
||||
const { hashSeed, keyMaterial } = privateParams;
|
||||
const { keySize } = getCipherParams(algo.getValue());
|
||||
return keySize === keyMaterial.length &&
|
||||
util.equalsUint8Array(digest, await computeDigest(enums.hash.sha256, hashSeed));
|
||||
}
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { eccSecretKey, mlkemSeed } = privateParams;
|
||||
const { eccPublicKey, mlkemPublicKey } = publicParams;
|
||||
return postQuantum.kem.validateParams(algo, eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSeed);
|
||||
}
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { eccSecretKey, mldsaSeed } = privateParams;
|
||||
const { eccPublicKey, mldsaPublicKey } = publicParams;
|
||||
return postQuantum.signature.validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unknown public key algorithm.');
|
||||
}
|
||||
|
@ -50,9 +50,9 @@ function buildEcdhParam(public_algo, oid, kdfParams, fingerprint) {
|
||||
return util.concatUint8Array([
|
||||
oid.write(),
|
||||
new Uint8Array([public_algo]),
|
||||
kdfParams.write(),
|
||||
kdfParams.write(true),
|
||||
util.stringToUint8Array('Anonymous Sender '),
|
||||
fingerprint
|
||||
kdfParams.replacementFingerprint || fingerprint
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import enums from '../../../enums';
|
||||
import util from '../../../util';
|
||||
import computeHKDF from '../../hkdf';
|
||||
import { getCipherParams } from '../../cipher';
|
||||
import { b64ToUint8Array, uint8ArrayToB64 } from '../../../encoding/base64';
|
||||
|
||||
const HKDF_INFO = {
|
||||
x25519: util.encodeUTF8('OpenPGP X25519'),
|
||||
@ -25,27 +24,12 @@ const HKDF_INFO = {
|
||||
*/
|
||||
export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.x25519:
|
||||
try {
|
||||
const webCrypto = util.getWebCrypto();
|
||||
const webCryptoKey = await webCrypto.generateKey('X25519', true, ['deriveKey', 'deriveBits']);
|
||||
|
||||
const privateKey = await webCrypto.exportKey('jwk', webCryptoKey.privateKey);
|
||||
const publicKey = await webCrypto.exportKey('jwk', webCryptoKey.publicKey);
|
||||
|
||||
return {
|
||||
A: new Uint8Array(b64ToUint8Array(publicKey.x)),
|
||||
k: b64ToUint8Array(privateKey.d)
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.name !== 'NotSupportedError') {
|
||||
throw err;
|
||||
}
|
||||
// k stays in little-endian, unlike legacy ECDH over curve25519
|
||||
const k = getRandomBytes(32);
|
||||
const { publicKey: A } = x25519.box.keyPair.fromSecretKey(k);
|
||||
return { A, k };
|
||||
}
|
||||
case enums.publicKey.x25519: {
|
||||
// k stays in little-endian, unlike legacy ECDH over curve25519
|
||||
const k = getRandomBytes(32);
|
||||
const { publicKey: A } = x25519.box.keyPair.fromSecretKey(k);
|
||||
return { A, k };
|
||||
}
|
||||
|
||||
case enums.publicKey.x448: {
|
||||
const x448 = await util.getNobleCurve(enums.publicKey.x448);
|
||||
@ -187,32 +171,13 @@ export function getPayloadSize(algo) {
|
||||
*/
|
||||
export async function generateEphemeralEncryptionMaterial(algo, recipientA) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.x25519:
|
||||
try {
|
||||
const webCrypto = util.getWebCrypto();
|
||||
const jwk = publicKeyToJWK(algo, recipientA);
|
||||
const ephemeralKeyPair = await webCrypto.generateKey('X25519', true, ['deriveKey', 'deriveBits']);
|
||||
const recipientPublicKey = await webCrypto.importKey('jwk', jwk, 'X25519', false, []);
|
||||
const sharedSecretBuffer = await webCrypto.deriveBits(
|
||||
{ name: 'X25519', public: recipientPublicKey },
|
||||
ephemeralKeyPair.privateKey,
|
||||
getPayloadSize(algo) * 8 // in bits
|
||||
);
|
||||
const ephemeralPublicKeyJwt = await webCrypto.exportKey('jwk', ephemeralKeyPair.publicKey);
|
||||
return {
|
||||
sharedSecret: new Uint8Array(sharedSecretBuffer),
|
||||
ephemeralPublicKey: new Uint8Array(b64ToUint8Array(ephemeralPublicKeyJwt.x))
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.name !== 'NotSupportedError') {
|
||||
throw err;
|
||||
}
|
||||
const ephemeralSecretKey = getRandomBytes(getPayloadSize(algo));
|
||||
const sharedSecret = x25519.scalarMult(ephemeralSecretKey, recipientA);
|
||||
assertNonZeroArray(sharedSecret);
|
||||
const { publicKey: ephemeralPublicKey } = x25519.box.keyPair.fromSecretKey(ephemeralSecretKey);
|
||||
return { ephemeralPublicKey, sharedSecret };
|
||||
}
|
||||
case enums.publicKey.x25519: {
|
||||
const ephemeralSecretKey = getRandomBytes(getPayloadSize(algo));
|
||||
const sharedSecret = x25519.scalarMult(ephemeralSecretKey, recipientA);
|
||||
assertNonZeroArray(sharedSecret);
|
||||
const { publicKey: ephemeralPublicKey } = x25519.box.keyPair.fromSecretKey(ephemeralSecretKey);
|
||||
return { ephemeralPublicKey, sharedSecret };
|
||||
}
|
||||
case enums.publicKey.x448: {
|
||||
const x448 = await util.getNobleCurve(enums.publicKey.x448);
|
||||
const ephemeralSecretKey = x448.utils.randomPrivateKey();
|
||||
@ -228,27 +193,11 @@ export async function generateEphemeralEncryptionMaterial(algo, recipientA) {
|
||||
|
||||
export async function recomputeSharedSecret(algo, ephemeralPublicKey, A, k) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.x25519:
|
||||
try {
|
||||
const webCrypto = util.getWebCrypto();
|
||||
const privateKeyJWK = privateKeyToJWK(algo, A, k);
|
||||
const ephemeralPublicKeyJWK = publicKeyToJWK(algo, ephemeralPublicKey);
|
||||
const privateKey = await webCrypto.importKey('jwk', privateKeyJWK, 'X25519', false, ['deriveKey', 'deriveBits']);
|
||||
const ephemeralPublicKeyReference = await webCrypto.importKey('jwk', ephemeralPublicKeyJWK, 'X25519', false, []);
|
||||
const sharedSecretBuffer = await webCrypto.deriveBits(
|
||||
{ name: 'X25519', public: ephemeralPublicKeyReference },
|
||||
privateKey,
|
||||
getPayloadSize(algo) * 8 // in bits
|
||||
);
|
||||
return new Uint8Array(sharedSecretBuffer);
|
||||
} catch (err) {
|
||||
if (err.name !== 'NotSupportedError') {
|
||||
throw err;
|
||||
}
|
||||
const sharedSecret = x25519.scalarMult(k, ephemeralPublicKey);
|
||||
assertNonZeroArray(sharedSecret);
|
||||
return sharedSecret;
|
||||
}
|
||||
case enums.publicKey.x25519: {
|
||||
const sharedSecret = x25519.scalarMult(k, ephemeralPublicKey);
|
||||
assertNonZeroArray(sharedSecret);
|
||||
return sharedSecret;
|
||||
}
|
||||
case enums.publicKey.x448: {
|
||||
const x448 = await util.getNobleCurve(enums.publicKey.x448);
|
||||
const sharedSecret = x448.getSharedSecret(k, ephemeralPublicKey);
|
||||
@ -275,32 +224,3 @@ function assertNonZeroArray(sharedSecret) {
|
||||
throw new Error('Unexpected low order point');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function publicKeyToJWK(algo, publicKey) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.x25519: {
|
||||
const jwk = {
|
||||
kty: 'OKP',
|
||||
crv: 'X25519',
|
||||
x: uint8ArrayToB64(publicKey, true),
|
||||
ext: true
|
||||
};
|
||||
return jwk;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported ECDH algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
function privateKeyToJWK(algo, publicKey, privateKey) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.x25519: {
|
||||
const jwk = publicKeyToJWK(algo, publicKey);
|
||||
jwk.d = uint8ArrayToB64(privateKey, true);
|
||||
return jwk;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported ECDH algorithm');
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,9 @@
|
||||
* @module crypto/public_key/elliptic/eddsa
|
||||
*/
|
||||
|
||||
import ed25519 from '@openpgp/tweetnacl';
|
||||
import naclEd25519 from '@openpgp/tweetnacl'; // better constant-timeness as it uses Uint8Arrays over BigInts
|
||||
import { verify as nobleEd25519Verify } from '@noble/ed25519';
|
||||
|
||||
import util from '../../../util';
|
||||
import enums from '../../../enums';
|
||||
import { getHashByteLength } from '../../hash';
|
||||
@ -48,11 +50,15 @@ export async function generate(algo) {
|
||||
seed: b64ToUint8Array(privateKey.d, true)
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.name !== 'NotSupportedError' && err.name !== 'OperationError') { // Temporary (hopefully) fix for WebKit on Linux
|
||||
if (
|
||||
err.name !== 'NotSupportedError' &&
|
||||
err.name !== 'OperationError' && // Temporary (hopefully) fix for WebKit on Linux
|
||||
err.name !== 'SyntaxError' // Temporary fix for Palemoon throwing 'SyntaxError'
|
||||
) {
|
||||
throw err;
|
||||
}
|
||||
const seed = getRandomBytes(getPayloadSize(algo));
|
||||
const { publicKey: A } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
const { publicKey: A } = naclEd25519.sign.keyPair.fromSeed(seed);
|
||||
return { A, seed };
|
||||
}
|
||||
|
||||
@ -100,11 +106,11 @@ export async function sign(algo, hashAlgo, message, publicKey, privateKey, hashe
|
||||
|
||||
return { RS: signature };
|
||||
} catch (err) {
|
||||
if (err.name !== 'NotSupportedError') {
|
||||
if (err.name !== 'NotSupportedError' && err.name !== 'SyntaxError') { // Temporary fix for Palemoon throwing 'SyntaxError'
|
||||
throw err;
|
||||
}
|
||||
const secretKey = util.concatUint8Array([privateKey, publicKey]);
|
||||
const signature = ed25519.sign.detached(hashed, secretKey);
|
||||
const signature = naclEd25519.sign.detached(hashed, secretKey);
|
||||
return { RS: signature };
|
||||
}
|
||||
|
||||
@ -146,10 +152,10 @@ export async function verify(algo, hashAlgo, { RS }, m, publicKey, hashed) {
|
||||
const verified = await webCrypto.verify('Ed25519', key, RS, hashed);
|
||||
return verified;
|
||||
} catch (err) {
|
||||
if (err.name !== 'NotSupportedError') {
|
||||
if (err.name !== 'NotSupportedError' && err.name !== 'SyntaxError') { // Temporary fix for Palemoon throwing 'SyntaxError'
|
||||
throw err;
|
||||
}
|
||||
return ed25519.sign.detached.verify(hashed, RS, publicKey);
|
||||
return nobleEd25519Verify(RS, hashed, publicKey);
|
||||
}
|
||||
|
||||
case enums.publicKey.ed448: {
|
||||
@ -177,7 +183,7 @@ export async function validateParams(algo, A, seed) {
|
||||
* and expect A == A'
|
||||
* TODO: move to sign-verify using WebCrypto (same as ECDSA) when curve is more widely implemented
|
||||
*/
|
||||
const { publicKey } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
const { publicKey } = naclEd25519.sign.keyPair.fromSeed(seed);
|
||||
return util.equalsUint8Array(A, publicKey);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
* @module crypto/public_key/elliptic/eddsa_legacy
|
||||
*/
|
||||
|
||||
import nacl from '@openpgp/tweetnacl';
|
||||
import naclEd25519 from '@openpgp/tweetnacl'; // better constant-timeness as it uses Uint8Arrays over BigInts
|
||||
import util from '../../../util';
|
||||
import enums from '../../../enums';
|
||||
import { getHashByteLength } from '../../hash';
|
||||
@ -101,7 +101,7 @@ export async function validateParams(oid, Q, k) {
|
||||
* Derive public point Q' = dG from private key
|
||||
* and expect Q == Q'
|
||||
*/
|
||||
const { publicKey } = nacl.sign.keyPair.fromSeed(k);
|
||||
const { publicKey } = naclEd25519.sign.keyPair.fromSeed(k);
|
||||
const dG = new Uint8Array([0x40, ...publicKey]); // Add public key prefix
|
||||
return util.equalsUint8Array(Q, dG);
|
||||
|
||||
|
67
src/crypto/public_key/hmac.js
Normal file
67
src/crypto/public_key/hmac.js
Normal file
@ -0,0 +1,67 @@
|
||||
import enums from '../../enums';
|
||||
import util from '../../util';
|
||||
|
||||
const supportedHashAlgos = new Set([enums.hash.sha1, enums.hash.sha256, enums.hash.sha512]);
|
||||
|
||||
const webCrypto = util.getWebCrypto();
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
|
||||
export async function generate(hashAlgo) {
|
||||
if (!supportedHashAlgos.has(hashAlgo)) {
|
||||
throw new Error('Unsupported hash algorithm.');
|
||||
}
|
||||
const hashName = enums.read(enums.webHash, hashAlgo);
|
||||
|
||||
const crypto = webCrypto || nodeCrypto.webcrypto.subtle;
|
||||
const key = await crypto.generateKey(
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: { name: hashName }
|
||||
},
|
||||
true,
|
||||
['sign', 'verify']
|
||||
);
|
||||
const exportedKey = await crypto.exportKey('raw', key);
|
||||
return new Uint8Array(exportedKey);
|
||||
}
|
||||
|
||||
export async function sign(hashAlgo, key, data) {
|
||||
if (!supportedHashAlgos.has(hashAlgo)) {
|
||||
throw new Error('Unsupported hash algorithm.');
|
||||
}
|
||||
const hashName = enums.read(enums.webHash, hashAlgo);
|
||||
|
||||
const crypto = webCrypto || nodeCrypto.webcrypto.subtle;
|
||||
const importedKey = await crypto.importKey(
|
||||
'raw',
|
||||
key,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: { name: hashName }
|
||||
},
|
||||
false,
|
||||
['sign']
|
||||
);
|
||||
const mac = await crypto.sign('HMAC', importedKey, data);
|
||||
return new Uint8Array(mac);
|
||||
}
|
||||
|
||||
export async function verify(hashAlgo, key, mac, data) {
|
||||
if (!supportedHashAlgos.has(hashAlgo)) {
|
||||
throw new Error('Unsupported hash algorithm.');
|
||||
}
|
||||
const hashName = enums.read(enums.webHash, hashAlgo);
|
||||
|
||||
const crypto = webCrypto || nodeCrypto.webcrypto.subtle;
|
||||
const importedKey = await crypto.importKey(
|
||||
'raw',
|
||||
key,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: { name: hashName }
|
||||
},
|
||||
false,
|
||||
['verify']
|
||||
);
|
||||
return crypto.verify('HMAC', importedKey, mac, data);
|
||||
}
|
@ -7,3 +7,5 @@ export * as rsa from './rsa';
|
||||
export * as elgamal from './elgamal';
|
||||
export * as elliptic from './elliptic';
|
||||
export * as dsa from './dsa';
|
||||
export * as hmac from './hmac';
|
||||
export * as postQuantum from './post_quantum';
|
||||
|
7
src/crypto/public_key/post_quantum/index.js
Normal file
7
src/crypto/public_key/post_quantum/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
import * as kem from './kem/index';
|
||||
import * as signature from './signature';
|
||||
|
||||
export {
|
||||
kem,
|
||||
signature
|
||||
};
|
51
src/crypto/public_key/post_quantum/kem/ecc_kem.js
Normal file
51
src/crypto/public_key/post_quantum/kem/ecc_kem.js
Normal file
@ -0,0 +1,51 @@
|
||||
import * as ecdhX from '../../elliptic/ecdh_x';
|
||||
import enums from '../../../../enums';
|
||||
|
||||
export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { A, k } = await ecdhX.generate(enums.publicKey.x25519);
|
||||
return {
|
||||
eccPublicKey: A,
|
||||
eccSecretKey: k
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function encaps(eccAlgo, eccRecipientPublicKey) {
|
||||
switch (eccAlgo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { ephemeralPublicKey: eccCipherText, sharedSecret: eccKeyShare } = await ecdhX.generateEphemeralEncryptionMaterial(enums.publicKey.x25519, eccRecipientPublicKey);
|
||||
|
||||
return {
|
||||
eccCipherText,
|
||||
eccKeyShare
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function decaps(eccAlgo, eccCipherText, eccSecretKey, eccPublicKey) {
|
||||
switch (eccAlgo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const eccKeyShare = await ecdhX.recomputeSharedSecret(enums.publicKey.x25519, eccCipherText, eccPublicKey, eccSecretKey);
|
||||
return eccKeyShare;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateParams(algo, eccPublicKey, eccSecretKey) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519:
|
||||
return ecdhX.validateParams(enums.publicKey.x25519, eccPublicKey, eccSecretKey);
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
2
src/crypto/public_key/post_quantum/kem/index.js
Normal file
2
src/crypto/public_key/post_quantum/kem/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
export { generate, encrypt, decrypt, validateParams } from './kem';
|
||||
export { expandSecretSeed as mlkemExpandSecretSeed } from './ml_kem';
|
56
src/crypto/public_key/post_quantum/kem/kem.js
Normal file
56
src/crypto/public_key/post_quantum/kem/kem.js
Normal file
@ -0,0 +1,56 @@
|
||||
import * as eccKem from './ecc_kem';
|
||||
import * as mlKem from './ml_kem';
|
||||
import * as aesKW from '../../../aes_kw';
|
||||
import util from '../../../../util';
|
||||
import enums from '../../../../enums';
|
||||
import { computeDigest } from '../../../hash';
|
||||
|
||||
export async function generate(algo) {
|
||||
const { eccPublicKey, eccSecretKey } = await eccKem.generate(algo);
|
||||
const { mlkemPublicKey, mlkemSeed, mlkemSecretKey } = await mlKem.generate(algo);
|
||||
|
||||
return { eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSeed, mlkemSecretKey };
|
||||
}
|
||||
|
||||
export async function encrypt(algo, eccPublicKey, mlkemPublicKey, sessioneKeyData) {
|
||||
const { eccKeyShare, eccCipherText } = await eccKem.encaps(algo, eccPublicKey);
|
||||
const { mlkemKeyShare, mlkemCipherText } = await mlKem.encaps(algo, mlkemPublicKey);
|
||||
const kek = await multiKeyCombine(algo, eccKeyShare, eccCipherText, eccPublicKey, mlkemKeyShare, mlkemCipherText, mlkemPublicKey);
|
||||
const wrappedKey = await aesKW.wrap(enums.symmetric.aes256, kek, sessioneKeyData); // C
|
||||
return { eccCipherText, mlkemCipherText, wrappedKey };
|
||||
}
|
||||
|
||||
export async function decrypt(algo, eccCipherText, mlkemCipherText, eccSecretKey, eccPublicKey, mlkemSecretKey, mlkemPublicKey, encryptedSessionKeyData) {
|
||||
const eccKeyShare = await eccKem.decaps(algo, eccCipherText, eccSecretKey, eccPublicKey);
|
||||
const mlkemKeyShare = await mlKem.decaps(algo, mlkemCipherText, mlkemSecretKey);
|
||||
const kek = await multiKeyCombine(algo, eccKeyShare, eccCipherText, eccPublicKey, mlkemKeyShare, mlkemCipherText, mlkemPublicKey);
|
||||
const sessionKey = await aesKW.unwrap(enums.symmetric.aes256, kek, encryptedSessionKeyData);
|
||||
return sessionKey;
|
||||
}
|
||||
|
||||
async function multiKeyCombine(algo, ecdhKeyShare, ecdhCipherText, ecdhPublicKey, mlkemKeyShare, mlkemCipherText, mlkemPublicKey) {
|
||||
// LAMPS-aligned and NIST compatible combiner, proposed in: https://mailarchive.ietf.org/arch/msg/openpgp/NMTCy707LICtxIhP3Xt1U5C8MF0/
|
||||
// 2a. KDF(mlkemSS || tradSS || tradCT || tradPK || Domain)
|
||||
// where Domain is "Domain" for LAMPS, and "mlkemCT || mlkemPK || algId || const" for OpenPGP
|
||||
const encData = util.concatUint8Array([
|
||||
mlkemKeyShare,
|
||||
ecdhKeyShare,
|
||||
ecdhCipherText,
|
||||
ecdhPublicKey,
|
||||
// domSep
|
||||
mlkemCipherText,
|
||||
mlkemPublicKey,
|
||||
new Uint8Array([algo]),
|
||||
util.encodeUTF8('OpenPGPCompositeKDFv1')
|
||||
]);
|
||||
|
||||
const kek = await computeDigest(enums.hash.sha3_256, encData);
|
||||
return kek;
|
||||
}
|
||||
|
||||
export async function validateParams(algo, eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSeed) {
|
||||
const eccValidationPromise = eccKem.validateParams(algo, eccPublicKey, eccSecretKey);
|
||||
const mlkemValidationPromise = mlKem.validateParams(algo, mlkemPublicKey, mlkemSeed);
|
||||
const valid = await eccValidationPromise && await mlkemValidationPromise;
|
||||
return valid;
|
||||
}
|
72
src/crypto/public_key/post_quantum/kem/ml_kem.js
Normal file
72
src/crypto/public_key/post_quantum/kem/ml_kem.js
Normal file
@ -0,0 +1,72 @@
|
||||
import enums from '../../../../enums';
|
||||
import util from '../../../../util';
|
||||
import { getRandomBytes } from '../../../random';
|
||||
|
||||
export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const mlkemSeed = getRandomBytes(64);
|
||||
const { mlkemSecretKey, mlkemPublicKey } = await expandSecretSeed(algo, mlkemSeed);
|
||||
|
||||
return { mlkemSeed, mlkemSecretKey, mlkemPublicKey };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand ML-KEM secret seed and retrieve the secret and public key material
|
||||
* @param {module:enums.publicKey} algo - Public key algorithm
|
||||
* @param {Uint8Array} seed - secret seed to expand
|
||||
* @returns {Promise<{ mlkemPublicKey: Uint8Array, mlkemSecretKey: Uint8Array }>}
|
||||
*/
|
||||
export async function expandSecretSeed(algo, seed) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { ml_kem768 } = await import('../noble_post_quantum');
|
||||
const { publicKey: encapsulationKey, secretKey: decapsulationKey } = ml_kem768.keygen(seed);
|
||||
|
||||
return { mlkemPublicKey: encapsulationKey, mlkemSecretKey: decapsulationKey };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function encaps(algo, mlkemRecipientPublicKey) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { ml_kem768 } = await import('../noble_post_quantum');
|
||||
const { cipherText: mlkemCipherText, sharedSecret: mlkemKeyShare } = ml_kem768.encapsulate(mlkemRecipientPublicKey);
|
||||
|
||||
return { mlkemCipherText, mlkemKeyShare };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function decaps(algo, mlkemCipherText, mlkemSecretKey) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { ml_kem768 } = await import('../noble_post_quantum');
|
||||
const mlkemKeyShare = ml_kem768.decapsulate(mlkemCipherText, mlkemSecretKey);
|
||||
|
||||
return mlkemKeyShare;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateParams(algo, mlkemPublicKey, mlkemSeed) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mlkem_x25519: {
|
||||
const { mlkemPublicKey: expectedPublicKey } = await expandSecretSeed(algo, mlkemSeed);
|
||||
return util.equalsUint8Array(mlkemPublicKey, expectedPublicKey);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported KEM algorithm');
|
||||
}
|
||||
}
|
10
src/crypto/public_key/post_quantum/noble_post_quantum.ts
Normal file
10
src/crypto/public_key/post_quantum/noble_post_quantum.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* This file is needed to dynamic import noble-post-quantum libs.
|
||||
* Separate dynamic imports are not convenient as they result in multiple chunks,
|
||||
* which ultimately share a lot of code and need to be imported together
|
||||
* when it comes to Proton's ML-DSA + ML-KEM keys.
|
||||
*/
|
||||
|
||||
export { ml_kem768 } from '@noble/post-quantum/ml-kem';
|
||||
export { ml_dsa65 } from '@noble/post-quantum/ml-dsa';
|
||||
|
46
src/crypto/public_key/post_quantum/signature/ecc_dsa.js
Normal file
46
src/crypto/public_key/post_quantum/signature/ecc_dsa.js
Normal file
@ -0,0 +1,46 @@
|
||||
import * as eddsa from '../../elliptic/eddsa';
|
||||
import enums from '../../../../enums';
|
||||
|
||||
export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { A, seed } = await eddsa.generate(enums.publicKey.ed25519);
|
||||
return {
|
||||
eccPublicKey: A,
|
||||
eccSecretKey: seed
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest) {
|
||||
switch (signatureAlgo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { RS: eccSignature } = await eddsa.sign(enums.publicKey.ed25519, hashAlgo, null, eccPublicKey, eccSecretKey, dataDigest);
|
||||
|
||||
return { eccSignature };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature) {
|
||||
switch (signatureAlgo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519:
|
||||
return eddsa.verify(enums.publicKey.ed25519, hashAlgo, { RS: eccSignature }, null, eccPublicKey, dataDigest);
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateParams(algo, eccPublicKey, eccSecretKey) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519:
|
||||
return eddsa.validateParams(enums.publicKey.ed25519, eccPublicKey, eccSecretKey);
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
2
src/crypto/public_key/post_quantum/signature/index.js
Normal file
2
src/crypto/public_key/post_quantum/signature/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
export { generate, sign, verify, validateParams, getRequiredHashAlgo } from './signature';
|
||||
export { expandSecretSeed as mldsaExpandSecretSeed } from './ml_dsa';
|
69
src/crypto/public_key/post_quantum/signature/ml_dsa.js
Normal file
69
src/crypto/public_key/post_quantum/signature/ml_dsa.js
Normal file
@ -0,0 +1,69 @@
|
||||
import enums from '../../../../enums';
|
||||
import util from '../../../../util';
|
||||
import { getRandomBytes } from '../../../random';
|
||||
|
||||
export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const mldsaSeed = getRandomBytes(32);
|
||||
const { mldsaSecretKey, mldsaPublicKey } = await expandSecretSeed(algo, mldsaSeed);
|
||||
|
||||
return { mldsaSeed, mldsaSecretKey, mldsaPublicKey };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand ML-DSA secret seed and retrieve the secret and public key material
|
||||
* @param {module:enums.publicKey} algo - Public key algorithm
|
||||
* @param {Uint8Array} seed - secret seed to expand
|
||||
* @returns {Promise<{ mldsaPublicKey: Uint8Array, mldsaSecretKey: Uint8Array }>}
|
||||
*/
|
||||
export async function expandSecretSeed(algo, seed) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { ml_dsa65 } = await import('../noble_post_quantum');
|
||||
const { secretKey: mldsaSecretKey, publicKey: mldsaPublicKey } = ml_dsa65.keygen(seed);
|
||||
|
||||
return { mldsaSecretKey, mldsaPublicKey };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function sign(algo, mldsaSecretKey, dataDigest) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { ml_dsa65 } = await import('../noble_post_quantum');
|
||||
const mldsaSignature = ml_dsa65.sign(mldsaSecretKey, dataDigest);
|
||||
return { mldsaSignature };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function verify(algo, mldsaPublicKey, dataDigest, mldsaSignature) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { ml_dsa65 } = await import('../noble_post_quantum');
|
||||
return ml_dsa65.verify(mldsaPublicKey, dataDigest, mldsaSignature);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateParams(algo, mldsaPublicKey, mldsaSeed) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { mldsaPublicKey: expectedPublicKey } = await expandSecretSeed(algo, mldsaSeed);
|
||||
return util.equalsUint8Array(mldsaPublicKey, expectedPublicKey);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
70
src/crypto/public_key/post_quantum/signature/signature.js
Normal file
70
src/crypto/public_key/post_quantum/signature/signature.js
Normal file
@ -0,0 +1,70 @@
|
||||
import enums from '../../../../enums';
|
||||
import * as mldsa from './ml_dsa';
|
||||
import * as eccdsa from './ecc_dsa';
|
||||
|
||||
export async function generate(algo) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { eccSecretKey, eccPublicKey } = await eccdsa.generate(algo);
|
||||
const { mldsaSeed, mldsaSecretKey, mldsaPublicKey } = await mldsa.generate(algo);
|
||||
return { eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, dataDigest) {
|
||||
if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) {
|
||||
// The signature hash algo MUST be set to the specified algorithm, see
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
|
||||
throw new Error('Unexpected hash algorithm for PQC signature');
|
||||
}
|
||||
|
||||
switch (signatureAlgo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { eccSignature } = await eccdsa.sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest);
|
||||
const { mldsaSignature } = await mldsa.sign(signatureAlgo, mldsaSecretKey, dataDigest);
|
||||
|
||||
return { eccSignature, mldsaSignature };
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function verify(signatureAlgo, hashAlgo, eccPublicKey, mldsaPublicKey, dataDigest, { eccSignature, mldsaSignature }) {
|
||||
if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) {
|
||||
// The signature hash algo MUST be set to the specified algorithm, see
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
|
||||
throw new Error('Unexpected hash algorithm for PQC signature');
|
||||
}
|
||||
|
||||
switch (signatureAlgo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const eccVerifiedPromise = eccdsa.verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature);
|
||||
const mldsaVerifiedPromise = mldsa.verify(signatureAlgo, mldsaPublicKey, dataDigest, mldsaSignature);
|
||||
const verified = await eccVerifiedPromise && await mldsaVerifiedPromise;
|
||||
return verified;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export function getRequiredHashAlgo(signatureAlgo) {
|
||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
|
||||
switch (signatureAlgo) {
|
||||
case enums.publicKey.pqc_mldsa_ed25519:
|
||||
return enums.hash.sha3_256;
|
||||
default:
|
||||
throw new Error('Unsupported signature algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed) {
|
||||
const eccValidationPromise = eccdsa.validateParams(algo, eccPublicKey, eccSecretKey);
|
||||
const mldsaValidationPromise = mldsa.validateParams(algo, mldsaPublicKey, mldsaSeed);
|
||||
const valid = await eccValidationPromise && await mldsaValidationPromise;
|
||||
return valid;
|
||||
}
|
@ -3,9 +3,10 @@
|
||||
* @module crypto/signature
|
||||
*/
|
||||
|
||||
import { elliptic, rsa, dsa } from './public_key';
|
||||
import { elliptic, rsa, dsa, hmac, postQuantum } from './public_key';
|
||||
import enums from '../enums';
|
||||
import util from '../util';
|
||||
import ShortByteString from '../type/short_byte_string';
|
||||
import { UnsupportedError } from '../packet/packet';
|
||||
|
||||
/**
|
||||
@ -65,7 +66,16 @@ export function parseSignatureParams(algo, signature) {
|
||||
const RS = util.readExactSubarray(signature, read, read + rsSize); read += RS.length;
|
||||
return { read, signatureParams: { RS } };
|
||||
}
|
||||
|
||||
case enums.publicKey.hmac: {
|
||||
const mac = new ShortByteString(); read += mac.read(signature.subarray(read));
|
||||
return { read, signatureParams: { mac } };
|
||||
}
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const eccSignatureSize = 2 * elliptic.eddsa.getPayloadSize(enums.publicKey.ed25519);
|
||||
const eccSignature = util.readExactSubarray(signature, read, read + eccSignatureSize); read += eccSignature.length;
|
||||
const mldsaSignature = util.readExactSubarray(signature, read, read + 3309); read += mldsaSignature.length;
|
||||
return { read, signatureParams: { eccSignature, mldsaSignature } };
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedError('Unknown signature algorithm.');
|
||||
}
|
||||
@ -80,12 +90,13 @@ export function parseSignatureParams(algo, signature) {
|
||||
* @param {module:enums.hash} hashAlgo - Hash algorithm
|
||||
* @param {Object} signature - Named algorithm-specific signature parameters
|
||||
* @param {Object} publicParams - Algorithm-specific public key parameters
|
||||
* @param {Object} privateParams - Algorithm-specific private key parameters
|
||||
* @param {Uint8Array} data - Data for which the signature was created
|
||||
* @param {Uint8Array} hashed - The hashed data
|
||||
* @returns {Promise<Boolean>} True if signature is valid.
|
||||
* @async
|
||||
*/
|
||||
export async function verify(algo, hashAlgo, signature, publicParams, data, hashed) {
|
||||
export async function verify(algo, hashAlgo, signature, publicParams, privateParams, data, hashed) {
|
||||
switch (algo) {
|
||||
case enums.publicKey.rsaEncryptSign:
|
||||
case enums.publicKey.rsaEncrypt:
|
||||
@ -121,6 +132,18 @@ export async function verify(algo, hashAlgo, signature, publicParams, data, hash
|
||||
const { A } = publicParams;
|
||||
return elliptic.eddsa.verify(algo, hashAlgo, signature, data, A, hashed);
|
||||
}
|
||||
case enums.publicKey.hmac: {
|
||||
if (!privateParams) {
|
||||
throw new Error('Cannot verify HMAC signature with symmetric key missing private parameters');
|
||||
}
|
||||
const { cipher: algo } = publicParams;
|
||||
const { keyMaterial } = privateParams;
|
||||
return hmac.verify(algo.getValue(), keyMaterial, signature.mac.data, hashed);
|
||||
}
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { eccPublicKey, mldsaPublicKey } = publicParams;
|
||||
return postQuantum.signature.verify(algo, hashAlgo, eccPublicKey, mldsaPublicKey, hashed, signature);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unknown signature algorithm.');
|
||||
}
|
||||
@ -176,6 +199,17 @@ export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, da
|
||||
const { seed } = privateKeyParams;
|
||||
return elliptic.eddsa.sign(algo, hashAlgo, data, A, seed, hashed);
|
||||
}
|
||||
case enums.publicKey.hmac: {
|
||||
const { cipher: algo } = publicKeyParams;
|
||||
const { keyMaterial } = privateKeyParams;
|
||||
const mac = await hmac.sign(algo.getValue(), keyMaterial, hashed);
|
||||
return { mac: new ShortByteString(mac) };
|
||||
}
|
||||
case enums.publicKey.pqc_mldsa_ed25519: {
|
||||
const { eccPublicKey } = publicKeyParams;
|
||||
const { eccSecretKey, mldsaSecretKey } = privateKeyParams;
|
||||
return postQuantum.signature.sign(algo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, hashed);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unknown signature algorithm.');
|
||||
}
|
||||
|
25
src/enums.js
25
src/enums.js
@ -50,6 +50,18 @@ export default {
|
||||
'brainpoolP512r1': 'brainpoolP512r1'
|
||||
},
|
||||
|
||||
/** KDF parameters flags
|
||||
* Non-standard extensions (for now) to allow email forwarding
|
||||
* @enum {Integer}
|
||||
* @readonly
|
||||
*/
|
||||
kdfFlags: {
|
||||
/** Specify fingerprint to use instead of the recipient's */
|
||||
replace_fingerprint: 0x01,
|
||||
/** Specify custom parameters to use in the KDF digest computation */
|
||||
replace_kdf_params: 0x02
|
||||
},
|
||||
|
||||
/** A string to key specifier type
|
||||
* @enum {Integer}
|
||||
* @readonly
|
||||
@ -95,7 +107,16 @@ export default {
|
||||
/** Ed25519 (Sign only) */
|
||||
ed25519: 27,
|
||||
/** Ed448 (Sign only) */
|
||||
ed448: 28
|
||||
ed448: 28,
|
||||
/** Post-quantum ML-KEM-768 + X25519 (Encrypt only) */
|
||||
pqc_mlkem_x25519: 105,
|
||||
/** Post-quantum ML-DSA-64 + Ed25519 (Sign only) */
|
||||
pqc_mldsa_ed25519: 107,
|
||||
|
||||
/** Persistent symmetric keys: encryption algorithm */
|
||||
aead: 100,
|
||||
/** Persistent symmetric keys: authentication algorithm */
|
||||
hmac: 101
|
||||
},
|
||||
|
||||
/** {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC4880, section 9.2}
|
||||
@ -382,6 +403,8 @@ export default {
|
||||
splitPrivateKey: 16,
|
||||
/** 0x20 - This key may be used for authentication. */
|
||||
authentication: 32,
|
||||
/** This key may be used for forwarded communications */
|
||||
forwardedCommunication: 64,
|
||||
/** 0x80 - The private component of this key may be in the
|
||||
* possession of more than one person. */
|
||||
sharedPrivateKey: 128
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user