Compare commits

...

619 Commits

Author SHA1 Message Date
dependabot[bot]
88310fe69d
Bump playwright from 1.51.0 to 1.51.1 (#1834)
Bumps [playwright](https://github.com/microsoft/playwright) from 1.51.0 to 1.51.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.51.0...v1.51.1)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 13:56:54 +01:00
dependabot[bot]
c2526c8a88
Tests: bump playwright from 1.50.1 to 1.51.0 (#1831)
Bumps [playwright](https://github.com/microsoft/playwright) from 1.50.1 to 1.51.0.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.50.1...v1.51.0)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 15:53:39 +01:00
larabr
1848f51a4c
Merge pull request #1829
Re-enable using WebCrypto for X25519 when available.
2025-03-05 11:51:40 +01:00
larabr
4762d2c762 CI: do not test Webkit on Linux
The tests work correctly in Epiphany, but not in the WebKit build,
where the native X25519 implementation throws non-standard errors on
importKey (DataError) and generateKey (OperationError).
Patching this would be simply a matter of catching such errors and falling back
to the JS implementation, but since only the CI WebKit build seems to be
affected, we prefer not to relax fallback checks in the context of crypto
operations without issues reported in the wild.
2025-02-26 13:00:14 +01:00
larabr
d5689894f6 Re-enable using WebCrypto for X25519 when available
Reverting commit ccb040ae96acd127a29161ffaf3b82b5b18c062f .
Firefox has fixed support in v132 (https://bugzilla.mozilla.org/show_bug.cgi?id=1918354)
usage of v130 and 131, which have a broken implementation, is now below 1%.

Also, Chrome has released support in v133.
2025-02-26 12:15:17 +01:00
Carlos Alexandro Becker
6d4a86295e
Make Issuer Key ID signature subpacket non-critical (#1828)
RPM <=4.16 does not support it.

See also:
- https://github.com/ProtonMail/go-crypto/pull/175
- https://github.com/ProtonMail/go-crypto/issues/263
2025-02-26 10:19:25 +01:00
dependabot[bot]
8a2062d342
Bump the noble group with 3 updates (#1825)
Bumps the noble group with 3 updates: [@noble/ciphers](https://github.com/paulmillr/noble-ciphers), [@noble/curves](https://github.com/paulmillr/noble-curves) and [@noble/hashes](https://github.com/paulmillr/noble-hashes).

Also:
* Internal: OCB: do not reuse AES-CBC instance (Noble is now preventing instance reuse).
* Tests: update error message following noble-curve change


Updates `@noble/ciphers` from 1.0.0 to 1.2.1
- [Release notes](https://github.com/paulmillr/noble-ciphers/releases)
- [Commits](https://github.com/paulmillr/noble-ciphers/compare/1.0.0...1.2.1)

Updates `@noble/curves` from 1.6.0 to 1.8.1
- [Release notes](https://github.com/paulmillr/noble-curves/releases)
- [Commits](https://github.com/paulmillr/noble-curves/compare/1.6.0...1.8.1)

Updates `@noble/hashes` from 1.5.0 to 1.7.1
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/1.5.0...1.7.1)

---

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: larabr <7375870+larabr@users.noreply.github.com>
2025-02-12 13:20:20 +01:00
dependabot[bot]
e9fe979649
Bump fflate from 0.7.4 to 0.8.2 (#1826)
Bumps [fflate](https://github.com/101arrowz/fflate) from 0.7.4 to 0.8.2.
- [Release notes](https://github.com/101arrowz/fflate/releases)
- [Changelog](https://github.com/101arrowz/fflate/blob/master/CHANGELOG.md)
- [Commits](https://github.com/101arrowz/fflate/compare/v0.7.4...v0.8.2)

---
updated-dependencies:
- dependency-name: fflate
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-11 13:59:09 +01:00
dependabot[bot]
1ab6f27fc9
Bump playwright from 1.48.2 to 1.50.1 (#1824)
Bumps [playwright](https://github.com/microsoft/playwright) from 1.48.2 to 1.50.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.48.2...v1.50.1)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-11 13:27:41 +01:00
larabr
a7660cc43b CI: fix (again) Dependabot setup: add workaround to set different schedules for npm updates 2025-02-11 11:38:06 +01:00
larabr
b583bcad23
CI: fix Dependabot setup (#1823)
Typo in filename resulting in bot not actually working.
2025-02-10 19:20:03 +01:00
larabr
a3a9e06802
CI: add reconnection mechanism for Browserstack on testsStartTimeout (#1822)
iOS tests sometimes fail to start due to some "server disconnect" issue on BS side.
This seems more prominent on certain devices (e.g. iPhone 16 with iOS 18).
So, we also change the 'iOS latest' target to a more stable one.
2025-02-10 19:15:43 +01:00
Daniel Huigens
965e63b672
Only push new tags when running npm version (#1821) 2025-02-03 14:27:39 +01:00
Daniel Huigens
96b13a468b
6.1.0 2025-01-30 14:15:35 +01:00
Daniel Huigens
432856ff0e
Fix signing using keys without preferred hash algorithms (#1820) 2025-01-29 16:45:32 +01:00
larabr
b2bd8a0fdd
Merge pull request #1812
Improve internal tree-shaking and lazy load md5
2024-11-25 11:13:15 +01:00
larabr
6db98f1e47 Internal: improve tree-shaking in armor module 2024-11-22 14:34:18 +01:00
larabr
8e5da78971 Internal: improve tree-shaking of web-stream-tools
Import single functions instead of entire lib.
2024-11-22 14:34:18 +01:00
larabr
a5d894f514 Internal: avoid importing enums in legacy_cipher chunk
To avoid issues with the lightweight build:
for now it works fine, but it could mess up chunking in the future,
and it already results in a circular import.
2024-11-22 14:34:18 +01:00
larabr
a16160fc66 Use noble-hashes for md5
The existing md5 module brought in the util module,
which messed up the chunking structure in the lightweight build;
inlining those functions is an option, but the noble-hashes code
is also more modern and readable.
2024-11-22 14:32:42 +01:00
larabr
abe750cf7c Lightweight build: lazy load md5 hashing module
Used by old, legacy messages only
2024-11-22 14:32:42 +01:00
larabr
2a8969b437 Internal: improve tree-shaking for crypto modules
Every submodule under the 'crypto' directory was exported-imported
even if a handful of functions where actually needed.
We now only export entire modules behind default exports if it makes
sense for readability and if the different submodules would be
imported together anyway (e.g. `cipherMode` exports are all needed
by the SEIPD class).

We've also dropped exports that are not used outside of the crypto modules,
e.g. pkcs5 helpers.
2024-11-22 14:32:39 +01:00
larabr
bf85deedb8
Merge pull request #1811 2024-11-22 14:30:41 +01:00
larabr
6c3b02872d Throw on encryption using non-standard experimentalGCM AEAD algo
The `enums.aead.gcm` ID standardized by RFC9580 should be used instead.
2024-11-22 14:29:14 +01:00
larabr
4d2d8740dc Fix decryption support for non-standard, legacy AEAD messages and keys that used experimentalGCM
This adds back support for decrypting password-protected messages which
were encrypted in OpenPGP.js v5 with custom config settings
`config.aeadProtect = true` together with
`config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM`.

Public-key-encrypted messages are affected if they were encrypted using the same config, while also providing `encryptionKeys` that declared `experimentalGCM` in their AEAD prefs.
Such keys could be generated in OpenPGP.js v5 by setting the aforementioned config values.
2024-11-22 10:15:20 +01:00
larabr
bbdaad0cba TS: add gcm to enums.aead, mark non-standard experimentalGCM as deprecated
`experimentalGCM` should not be used anymore,
as a different a different algorithm ID was standardized
for GCM, and using the experimental value could give
interoperability issues with e.g. SEIPDv2 and AEAD-encrypted keys.
2024-11-22 10:15:20 +01:00
larabr
daeaf6b1da CI: disable Browserstack concurrency to improve reliability 2024-11-21 18:11:10 +01:00
larabr
67faffafff 6.0.1 2024-11-21 17:16:29 +01:00
larabr
f75447afaa Fix ES imports for webpack: declare exports.browser entrypoint as higher priority than import
We could also drop the browser's directive `"./dist/node/openpgp.min.cjs": "./dist/openpgp.min.js"`,
since that build cannot be used with `require()`, and it's instead meant
to be the target of <script> tags.
But we keep it around for now to avoid potentially breaking changes, in case it's
used in some setups.
2024-11-21 16:43:15 +01:00
larabr
121b478312 Tests: drop unused, unnecessary error assertion
The `expect().to.not.throw` check as written is a no-op.
In fact, `throw` should have been called as a function.

We drop the relevant check altogether since if the wrapped
operation throws, the test will naturally fail due to the
unexpected error.
2024-11-13 19:44:06 +01:00
larabr
088d5f3638
Merge pull request #1807 2024-11-11 20:46:51 +01:00
Daniel Huigens
ac1bfc0d60
Fix openpgp.verify/decrypt with expectSigned: true and format: 'binary' (#1805) 2024-11-11 15:42:33 +01:00
larabr
287104aafb TS: fix PrivateKey.getDecryptionKeys() return type 2024-11-11 14:20:18 +01:00
larabr
2d65d1d553 TS: generateKey: fix options.type definitions to accept 'curve25519' and 'curve448' 2024-11-11 13:28:05 +01:00
Daniel Huigens
3f060660c2
Update hash algorithm preferences order (#1804)
Prefer SHA3_512 over SHA3_256 for consistency.
2024-11-07 15:19:20 +01:00
larabr
01b62399af Revert "CI: temporarily enable for PRs to v6 branch" [skip ci] 2024-11-05 12:56:39 +01:00
larabr
dd01ee00cb 6.0.0 2024-11-04 17:35:18 +01:00
Daniel Huigens
a5645e1d6c Spaces after "RFC" in README 2024-11-04 17:03:36 +01:00
Daniel Huigens
09800741f0 Document required Web Crypto support in README 2024-11-04 17:02:04 +01:00
Daniel Huigens
31a7e2616b
Merge pull request #1629 from openpgpjs/v6
V6
2024-11-04 12:11:19 +01:00
larabr
42d504a69a
Switch to SHA512 as default preferred hash algo (config.preferredHashAlgorithm) (#1801)
This affects the preferences of newly generated keys, which by default will
have SHA512 as first hash algo preference.
SHA512 will also be used when signing, as long as the recipient keys declare
support for the algorithm.
2024-10-31 00:24:19 +01:00
larabr
fb72ea449a
Merge pull request #1802
Determine signature hash prefs based on recipient keys instead of signing key
2024-10-31 00:16:40 +01:00
larabr
f9a3e54364 openpgp.sign: add recipientKeys option to get the signing prefs from
If given, the signature will be generated using the preferred hash algo from the recipient keys.
Otherwise, the signing key preferences are used (this was also the existing behavior).

Note: when signing through `openpgp.encrypt`, the `encryptionKeys` are automatically used as recipient keys.
2024-10-30 19:06:44 +01:00
larabr
d3e75de23d openpgp.encrypt: use encryptionKeys to determine preferred hash algo when signing
In `openpgp.sign`, the signing key preferences are considered instead,
since no "recipient keys" are available.

The hash algo selection logic has been reworked as follows:
if `config.preferredHashAlgo` appears in the prefs of all recipients, we pick it;
otherwise, we use the strongest supported algo (note: SHA256 is always implicitly supported by all keys),
as long as it is compatible with the signing key (e.g. ECC keys require minimum digest sizes).

Previously, only the preferences of the signing key were used to determine the hash algo to use,
but this is in contrast to the RFC: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.16-2 .
Also, an algo stronger than `config.preferredHashAlgo` would be used, if the signing key
declared it as first preference.

With this change, `config.preferredHashAlgo` is picked even if it's weaker than the
preferences of the recipient keys.
2024-10-30 19:06:44 +01:00
larabr
12274a1543 Update README [skip ci] 2024-10-28 18:01:07 +01:00
larabr
0138b69356 CI: update Browserstack project id to include target branch 2024-10-28 13:38:59 +01:00
larabr
821f260ba9 Lightweight build: lazy load bzip decompression lib 2024-10-28 13:38:59 +01:00
larabr
09095ced4f Run npm update
as well as npm audit
2024-10-28 13:38:59 +01:00
larabr
d7f5736d67
Merge pull request #1794 2024-10-25 12:16:02 +02:00
larabr
693adb417e CI: run browser tests also on Linux
To test platform potential specific code of e.g. the WebCrypto API

Testing on Windows would be nice too, but all browsers fail to fetch resources
from the web-test-runner server.
2024-10-25 11:38:52 +02:00
larabr
013dffce70 CI: test latest Webkit on macOS, as a replacement for testing Safari on Browserstack
We were previously testing the webkit engine on Linux, which however relies on a
different WebCrypto API implementation compared to the macOS version (behind Safari).

Also, increase mocha timeouts, as the argon2 memory-heavy test takes longer in Firefox.
2024-10-24 20:12:11 +02:00
larabr
59c809c943 CI: Browserstack: test only iOS latest and min supported version (iOS 14)
Dropping Safari since Web Secure Sockets do not seem to work with
the 'networkLogs' capability, which is in turn required for the HTTPS
connection to work without insecure certs warnings.
2024-10-24 15:39:20 +02:00
larabr
4ddadd4f53 CI: setup HTTPS in web-test-runner for BrowserStack tests
To have tests work Browserstack Safari (also below iOS 15), as the tests are run in an iframe,
rewriting localhost as hostname, making WebCrypto not available.

We keep HTTP for the non-browserstack tests so that in local testing,
generating self-signed certs is not required.
2024-10-24 15:39:14 +02:00
larabr
ae5698c621 CI: fix playwright version parsing
Only look at direct dependency
2024-10-23 18:03:54 +02:00
larabr
4b017f6c67 Tests: drop karma (deprecated) in favor of web-test-runner 2024-10-23 18:03:51 +02:00
larabr
e924a50c31
Merge pull request #1799 2024-10-22 14:32:31 +02:00
larabr
88f20974dd Tests: add support for RNG mocking in browser tests
The affected tests were previously only run in Node.
2024-10-22 12:40:15 +02:00
larabr
05fbc63732 Use WebCrypto.getRandomValues in Node
To move towards uniform code with across platforms.
2024-10-22 12:40:15 +02:00
larabr
3cdaab7894 Check session key size on v3 SKESK and PKESK packet decryption
For v3 SKESK and PKESK packets, the session key algorithm is part of the payload,
so we can check the session key size on packet decryption.
This is helpful to catch errors early, when using e.g. `decryptSessionKeys`.

In v6 packets, the session key size check can only be done on SEIPDv2 decryption.
2024-10-22 12:40:15 +02:00
larabr
e58c02d5ee Check session key size on SEIPD decryption
This is especially important for SEIPDv2 session keys,
as a key derivation step is run where the resulting key
will always match the expected cipher size,
but we want to ensure that the input key isn't e.g. too short.
2024-10-22 12:40:15 +02:00
larabr
a57bffc84a
Fix key and signature parsing of EdDSALegacy entities with unsupported curves (e.g. Curve448Legacy) (#1798)
Signature parsing would fail in case of unexpected payload sizes, causing key parsing to always throw
when processing e.g. an (unsupported) Curve448Legacy subkey instead of ignoring it.

To address this, we now throw on signature verification instead of parsing (as done for ECDSA).

NB: the bug and this fix are not relevant for the new Ed25519/Ed448 entities as standardized by the crypto-refresh.
2024-10-14 12:15:33 +02:00
larabr
5ee854140a CI: update SOP test suite docker image to v1.1.12
Includes rsop with crypto-refresh support
2024-10-03 16:44:55 +02:00
larabr
ada794cab6 Throw on (unexpected) low order points in ECDH over Curve25519/448
These points do not pose a security threat in the context of OpenPGP ECDH,
and would simply result in an all-zero shared secret being generated.
However, they represent unexpected inputs, so we prefer to warn the user.
2024-09-12 13:32:14 +02:00
larabr
e80d71bdfc CI: setup Dependabot to update non-dev dependencies
We unfortunately need to manually list them as they are still
declared as dev dependencies in the package.json, due to the fact
that we bundle them.
2024-09-11 19:41:57 +02:00
larabr
e454faab0c CI: setup Dependabot to update playwright and test latest browser versions 2024-09-11 19:35:47 +02:00
larabr
6ac17dc71c 6.0.0-beta.3.patch.1 2024-09-11 10:57:20 +02:00
larabr
148fff91e8 Docs: fix type tag warnings 2024-09-11 10:56:08 +02:00
larabr
ccb040ae96 Revert to not using the WebCrypto for X25519 (ECDH only)
Due to missing support in WebKit and Chrome (without experimental flags),
and broken support in Firefox, for now we go back to using a JS implementation.

This change only affects encryption and decryption using X25519.
For signing and verification using Ed25519 we keep relying on
WebCrypto when available (namely in WebKit, Firefox, and Node).
2024-09-11 10:56:08 +02:00
larabr
2b9a07e840 Run npm audit 2024-09-11 10:42:37 +02:00
larabr
0255fcba86 CI: update playwright to test latest browser versions 2024-09-11 10:39:51 +02:00
larabr
f2818429db 6.0.0-beta.3.patch.0 2024-09-09 11:47:41 +02:00
larabr
8d8033383b Fix regression in x25519 (legacy) key generation: store clamped secret scalar
Fixes regression from changes in #1782, as the spec mandates that
legacy x25519 store the secret scalar already clamped.
Keys generated using v6.0.0-beta.3 are still expected to be functional,
since the scalar is to be clamped before computing the ECDH shared secret.
2024-09-09 11:20:59 +02:00
larabr
a3839f6db5 6.0.0-beta.3 2024-09-05 13:24:51 +02:00
larabr
1bcce67c68 CI: test also on Node 22 2024-09-05 13:20:56 +02:00
larabr
e7b7f6c6b1 Run npm update 2024-09-05 13:20:56 +02:00
larabr
ab8445116c CI: update SOP test suite docker image to v1.1.10
Add rsop to tested libraries.
2024-09-05 13:20:56 +02:00
larabr
f36be640cc Fallback to js implementation on WebCrypto EdDSA key generation failure
Workaround random failures in WebKit (Linux).
2024-09-04 17:47:55 +02:00
larabr
2f185481a7
PrivateKey.getDecryptionKeys: throw if no decryption key is found (#1789)
To avoid returning dummy key packets, and improving error reporting.
This new behavior is also better aligned with that of `Key.getSigningKey()`.

This is a breaking change for apps that call `getDecryptionKeys()` directly.
The related error messages returned by `openpgp.decrypt` have also changed,
becoming more specific.

This change is also made in preparation of supporting private keys with
public key packets.
2024-09-03 14:40:06 +02:00
larabr
5fd7ef370f
Drop asmcrypto.js for AES fallbacks in favor of noble-ciphers (#1785)
Asm.js has now been deprecated for many years, and no performance gain is
recorded for AES compared to vanilla JS.
The relevant AES fallback code is primarily used if the WebCrypto (resp.
NodeCrypto) implementation is not available.
2024-08-21 12:59:23 +02:00
larabr
79014f00f0
Merge pull request #1782 2024-08-21 12:53:13 +02:00
larabr
5c583341d7 Update README 2024-08-14 16:28:56 +02:00
larabr
db82968b48 Tests: do not test RFC8032 test vectors on Safari
As it implements a different RFC for non-deterministic signature generation
2024-08-14 16:22:01 +02:00
larabr
7698790d1c Use WebCrypto for x25519 when available 2024-08-14 16:22:01 +02:00
larabr
bcaaa7e2d2 Use WebCrypto for ed25519 when available 2024-08-14 16:22:00 +02:00
Daniel Huigens
fca699373a
Try more AEAD ciphersuites for SEIPDv2 (#1781)
Stick more closely to the algorithm preferences when creating an SEIPDv2
message, by trying additional combinations of the preferred symmetric algorithm
and the preferred AEAD algorithm. If one of them is supported but not the
other, we still use it (with the mandatory-to-implement algorithm for the other
one).
2024-08-12 11:52:52 +02:00
larabr
efb0324330 TS: add definition for config.enableParsingV5Entities [skip ci] 2024-07-15 15:14:27 +02:00
larabr
c0b35306cb 6.0.0-beta.2 2024-07-05 15:12:14 +02:00
larabr
35a1e1f23b Run npm audit 2024-07-05 15:10:29 +02:00
larabr
b9c5c8df59
Allow parsing legacy AEAD messages regardless of config.enableParsingV5Entities (#1779)
As legacy AEAD messages have been in circulation for longer.
2024-07-05 14:38:16 +02:00
Daniel Huigens
857b794e13
Disallow using forbidden S2K modes (#1777)
RFC9580 says that:

    Argon2 is only used with AEAD (S2K usage octet 253).  An
    implementation MUST NOT create and MUST reject as malformed any
    secret key packet where the S2K usage octet is not AEAD (253) and
    the S2K specifier type is Argon2.

Therefore, we disallow reading and writing Argon2 keys without AEAD.

And:

    [The Simple and Salted S2K methods] are used only for reading in
    backwards compatibility mode.
    
Since v6 keys don't need backwards compatibility, we also disallow
reading Simple S2K there. We still allow reading Salted S2K since the
spec says it may be used "when [the password] is high entropy".
2024-07-05 13:52:45 +02:00
Daniel Huigens
00e147f5c1
Use preferred AEAD mode for secret key encryption (#1776)
When config.aeadProtect is enabled, use config.preferredAEADAlgorithm
to decide the AEAD mode when encrypting secret keys.
2024-07-05 13:50:11 +02:00
Daniel Huigens
42938c871a
Fix legacy AEAD secret key encryption of v5 keys (#1775) 2024-07-04 19:41:39 +02:00
larabr
40b6427658 Tests: fix stream polyfilling in legacy browsers
web-streams-polyfill v4 has a different entrypoint for the polyfills.
2024-07-04 14:51:59 +02:00
larabr
f729d2bfa7
Fix ECDH fingerprint size of v6 keys (#1771)
Fingerprint should not be truncated, unlike for v5 keys.
2024-07-04 14:28:43 +02:00
larabr
5268c484e9
Disable support for parsing v5 entities by default (add config.enableParsingV5Entities) (#1774)
Parsing of v5 keys, v5 signatures and AEAD-encrypted data packets now requires turning on
the corresponding config flag.
The affected entities are non-standard, and in the crypto-refresh RFC they have been superseded by
v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively.
However, generation of v5 entities was supported behind config flag in OpenPGP.js v5, and some other libraries,
hence parsing them might be necessary in some cases.
2024-07-04 13:59:40 +02:00
Daniel Huigens
9efdaf14b1 Let hard revocations apply at any time (#1773)
"Hard" revocations (i.e. key compromise, and unknown reasons) apply
at any time, even before the revocation was created.

Co-authored-by: larabr <larabr+github@protonmail.com>
2024-07-04 13:51:35 +02:00
larabr
8d11c5fd0f Drop support for Node 16 and 17 2024-06-26 12:01:10 +02:00
larabr
7af16be62b
Use positive cert for self-signatures (#1769)
To uniform behaviour with other openpgp libs.
2024-06-25 12:50:26 +02:00
larabr
4026e24585 Merge branch 'main' into v6 2024-06-18 19:21:16 +02:00
larabr
a0337780b7 5.11.2 2024-06-18 17:53:56 +02:00
larabr
3eba29dba8
Merge pull request #1762
`openpgp.verify`: fix bug preventing verification of detached signatures over streamed data
2024-06-18 17:39:21 +02:00
larabr
12fb916360 Pass curve object instead of oid to checkPublicPointEnconding 2024-06-18 17:09:23 +02:00
larabr
cf94380e26 Read wireFormatLeadingByte value from curve object 2024-06-18 17:09:23 +02:00
larabr
52611e7f26 Detect unexpected eddsaLegacy OID on parsing 2024-06-18 17:09:23 +02:00
larabr
f8d0e6052f Detect invalid ECDSA, EdDSA and ECDH public key point encodings on usage
We now throw on unexpected leading byte.
This change is primarily intended to help with debugging, in case of malformed params.
In fact, in case of wrong point size, the operations would already fail anyway,
just in lower-level functions.
2024-06-18 17:09:23 +02:00
larabr
08b71487c5 Detect invalid PKESK public point encoding on decryption
We got a report of a message including a PKESK packet where
the ECDH x25519Legacy point was missing the leading byte (0x40).
While decryption naturally would naturally fail afterwards, this
change ensures we fail at a higher level, and do not blindly pass
down invalid data to the low-level crypto functions.
2024-06-18 17:09:23 +02:00
larabr
75f10955e6 Tests: move away from global streamed data
To improve readability
2024-06-18 17:07:41 +02:00
larabr
1ce2df1119 Avoid using stream.clone over polyfilled steam in test
Gives issues in Node and Safari < 14.1
2024-06-18 16:36:31 +02:00
larabr
6ace4a00f5 Update web-stream-tools to fix passiveClone cancellation race condition in tests
Affecting tests over streamed detached verification
2024-06-18 10:16:33 +02:00
Daniel Huigens
9f5ff66c3d
Store unhashed subpackets in a more structured format (#1767)
To match the new `unknownSubpackets` property.
2024-06-17 16:52:28 +02:00
Daniel Huigens
b1e27a1430
Delay checking unknown critical signature subpackets (#1766)
Throw when verifying signatures with unknown critical subpackets,
instead of when parsing them.
2024-06-17 12:31:31 +02:00
larabr
a315c46583 openpgp.verify: fix bug preventing verification of detached signature over streamed data
When given a streamed `message` and a detached `signature` in input,
the function would return an empty array as `data` instead of
the input stream, meaning it was not possible to pull it, causing
the `verified` promise to hang indefinitely.

The above issue was introduced v5.0.0-2, and thus affects all v5 releases
up to v5.11.1.
2024-05-31 15:58:42 +02:00
larabr
d138b5290b 6.0.0-beta.1 2024-05-17 14:13:46 +02:00
larabr
1d732c34ff Run npm update 2024-05-17 13:04:47 +02:00
larabr
6a306a1797 Lint: add support for dep imports that use exports declarations 2024-05-17 13:00:37 +02:00
larabr
676c31b748 CI: update SOP actions to Node 20 2024-05-16 17:21:36 +02:00
larabr
727c7cad37 read[Private]Key: support parsing key blocks (return first parsable key)
Previously, `readKey` and `readPrivateKey` would throw when given a block
of keys as input.
With this change, the first parsable key is returned by both functions:
the behaviour is equivalent to calling `readKeys` (resp. `readPrivateKeys`)
and taking the first array entry.
2024-05-16 14:07:39 +02:00
larabr
ad7165dfd0 readPrivateKeys: support parsing key block with mix of private and public keys
Previously, parsing a key block where a public key followed a private one would fail.
2024-05-16 14:07:39 +02:00
larabr
cf0285add5 Drop BigInteger class, use standalone helpers 2024-05-16 13:59:11 +02:00
larabr
90495522f7 CI: update Browserstack legacy targets (drop Safari 13) 2024-05-16 13:59:11 +02:00
larabr
2985b0f470 Lint: add support for TS files, fix errors 2024-05-16 13:59:11 +02:00
larabr
5bfff907b4 Move Brainpool curves implementation from noble-curves fork
The main repo doesn't implement them
2024-05-16 13:59:11 +02:00
larabr
ec52bdea83 Point to official noble-hashes and noble-curve libs 2024-05-16 13:59:11 +02:00
larabr
d1a24d1758 Drop support for platforms without native BigInt (e.g. Safari <14)
Remove BN.js fallback, and only keep native BigInteger interface
(for algorithmic constant-time functions).
Also, add support for TS modules, to move some over from the forked
noble repos.
2024-05-16 13:59:11 +02:00
larabr
7e2ea3f871 CI: update cache actions to Node 20 2024-05-02 21:45:58 +02:00
larabr
f3f1ab931b Tests: update SEIPD version check to no longer depend on config.aeadProtect
The logic was updated in github.com/openpgpjs/openpgpjs/pull/1678 .
The tests worked anyway thanks to the config option matching the (monkey patched)
keys' feature flags, which are the deciding factor for whether to use AEAD.
2024-05-02 21:45:58 +02:00
larabr
2bf7c92469 6.0.0-beta.0 2024-04-12 14:28:06 +02:00
larabr
5464caa6f7
Fix email address validity check to still allow unicode values, and further relax constraints (#1739)
We relaxed constraints in a previous commit, but excluded unicode chars, which are however allowed in v5.

We now drop almost all email address constraints, by primarily rejecting
control and spaces char classes.
Library users are strongly encouraged to implement additional checks as needed,
based on their supported email address format.

NB: the validity checks in question affect the userID inputs accepted by e.g.
`generateKey` and `reformatKey`, not the values parsed from existing entities,
e.g. using `readKey` (where almost no validation is performed).
2024-04-12 13:47:52 +02:00
larabr
231fbbe8ca Run npm update 2024-04-09 19:07:58 +02:00
larabr
9a53ac15df Tests: bump Sinon to v17 2024-04-09 18:57:53 +02:00
larabr
a05c23b507 Key.getRevocationCertificate(): apply config settings when armoring
The `config` input was not passed down to the armor function due to an oversight.
2024-04-09 18:40:51 +02:00
larabr
90c8fbbf00
Add back armor checksum for non-v6 artifacts (#1741)
We need to include the checksum to work around a GnuPG bug where data fails to
be decoded if the base64 ends with no padding chars (=) (see https://dev.gnupg.org/T7071).
Pure v6 artifacts are unaffected and won't include the checksum, as mandated by
the spec.

Breaking change:
`openpgp.armor` takes an additional `emitChecksum` argument (defaults to
false).
NB: some types of data must not include the checksum, but compliance is left as
responsibility of the caller: this function does not carry out any checks.
Refer to the crypto-refresh RFC for more details.

---------

Co-authored-by: Daniel Huigens <d.huigens@protonmail.com>
2024-04-09 17:12:44 +02:00
larabr
e9e843280b CI: update to sop-openpgp-v2 to test different v6 profiles
The implemented profiles do not work on v5, hence for now they need to be manually
disabled in the config of 'sop-openpgpjs-main'.
2024-04-05 17:25:54 +02:00
larabr
c68bd960ce
Randomise v4 and v5 signatures via custom notation, add config.nonDeterministicSignaturesViaNotation to disable feature (#1737)
EdDSA is known to be vulnerable to fault attacks which can lead to secret key
extraction if two signatures over the same data can be collected. Randomly
occurring bitflips in specific parts of the computation might in principle
result in vulnerable faulty signatures being generated.
To protect signatures generated using v4 and v5 keys from this possibility, we
randomise each signature by adding a custom notation with a random value,
functioning as a salt. 
For simplicity, we add the salt to all algos, not just EdDSA, as it may also
serve as protection in case of weaknesses in the hash algo, potentially
hindering e.g. some chosen-prefix attacks.
v6 signatures do not need to rely on this, as they are non-deterministic by
design.

While this notation solution is interoperable, it will reveal that the
signature has been generated using OpenPGP.js, which may not be desirable in
some cases.
For this reason, the option `config.nonDeterministicSignaturesViaNotation`
(defaulting to true) has been added to turn off the feature.
2024-04-02 17:37:57 +02:00
larabr
aa222fecb2
Drop config.revocationsExpire, always honour revocation expiration instead (#1736)
Unclear motivation for adding the original config option; if an expiration is there, it should
be honoured.

Breaking change:
the option used to default to `false`, and ignore revocation expirations. We now honour
those expirations, namely match the behaviour resulting from setting the option to `true`.
2024-03-28 14:24:23 +01:00
larabr
6ebd179ed5 Fix encrypting to a key with no declared features 2024-03-22 17:12:45 +01:00
larabr
2574795d37
Fix wrong serialization of PKESK v6 for x25519/x448 (#1734)
The cleartext session key symmetric algorithm was accidentally included in the packet.
As a result, the generated messages may fail to parse and/or decrypt in other implementations.
The messages would still decrypt successfully in OpenPGP.js, due to an overly permissive parsing procedure,
which simply discarded the unused additional byte.

We know also throw on unexpected cleartext symmetric algo in PKESK v6.
2024-03-22 17:10:27 +01:00
larabr
b41298a3f6 Add back armor checksum to detached signatures for GPG compatibility
GPG v2 fails to parse detached signatures without the checksum
2024-03-22 16:21:55 +01:00
larabr
cb97c8fcb9 CI: fix sop test result comparison 2024-03-22 16:14:18 +01:00
larabr
aba61efa70 CI: update interop test suite: fix sop-openpgpjs, include crypto-refresh tests, and compare with gopenpgp v3
sop-openpgpjs did not correctly apply the `OPENPGPJS_PATH` env variable; as a result,
it did not actually test the code from either the PR and base branch, but always from
the hardcoded version bundled with it.
2024-03-22 16:14:18 +01:00
larabr
147d043a32 6.0.0-alpha.1 2024-02-28 13:22:22 +01:00
larabr
df59dec319 Update README 2024-02-28 13:22:22 +01:00
larabr
f5cebfe6fd CI: update Playwright browser installation 2024-02-28 13:06:22 +01:00
larabr
15adf84a7d Run npm update 2024-02-28 12:44:05 +01:00
larabr
d4fd9c8d43 Merge branch 'main' into v6 2024-02-28 12:00:01 +01:00
larabr
151f15e282
Node: drop asn1.js dependency (#1722)
asn1.js is a fairly large lib and was simply needed to handle DER encodings in
some NodeCrypto operations.
This change replaces the dependency by moving to:

- JWT encoding for RSA (support added in Node v15)
- a much lighter dependency (eckey-utils) for ECDSA, where JWT cannot be used
for now, as Node has yet to add decoding support for Brainpool curves.

The change also allows us to drop BN.js as a direct dependency, optimising the
BigInteger-related chunking in the lightweight build.
2024-02-27 14:56:07 +01:00
larabr
a6283e64cc Drop internal cipher/aes module
The module was barely used, and its presence confusing, since
WebCrypto or asmcrypto are often directly used and usable instead.
Also, use AES_CBC instead of AES_ECB for single-block encryption,
so that we can drop support for the latter in the asmcrypto lib.
2024-02-27 14:43:24 +01:00
larabr
9c75845944 Use WebCrypto for AES-KW
Fallback needed for AES192, due to missing Chromium support.
2024-02-27 14:43:24 +01:00
larabr
db15f6d6a1
Import legacy ciphers (CAST5, TwoFish, BlowFish, DES) only on demand (#1723)
This primarily affects the lightweight build, which will not include these
(fairly large) modules in the main bundle file.
2024-02-26 15:37:50 +01:00
larabr
026b348cf8 5.11.1 2024-02-19 17:23:54 +01:00
larabr
711c41826a Run npm audit 2024-02-19 17:22:15 +01:00
larabr
a4e2c56c49
Use JS fallback code for RSA message decryption in Node if PKCS#1 is not supported (#1728)
Necessary as Node v18.19.1, 20.11.1 and 21.6.2 have disabled support for PKCS#1 decryption.
2024-02-19 17:14:55 +01:00
Mingye Wang
7a6b41fbd4
README: replace "IETF proposal" with "RFC4880bis proposal" (#1726) 2024-02-19 15:17:40 +01:00
larabr
17bbab44c9 README: clarify web-stream-tools version to install for TypeScript projects [skip ci] 2024-02-19 13:52:30 +01:00
larabr
b413a113f9 CI: update actions to Node 20 2024-02-12 13:53:46 +01:00
larabr
280828dae6 Throw if WebCrypto API is not available
It was already required, this simply makes errors more clear.
2024-02-06 16:00:35 +01:00
larabr
3320eaccb2
Relax constraints for UserID email address validity (#1641)
New checks align with the HTML5 W3C spec and should be more lax than the
existing ones (meaning, addresses which passed validation before should
continue to be valid).
Addresses such as `@localhost` are now allowed too, since presence of "." is no
longer enforced.

These checks should not be considered exhaustive: library users are encouraged
to implement separate checks for email validity if needed.

Co-authored-by: Daniel Huigens <d.huigens@protonmail.com>
2024-02-02 15:04:34 +01:00
larabr
22c2682574
Ensure primary key meets strength and algo requirements when encrypting/verifying/signing using subkeys (#1719)
Breaking change: the requirements of `config.minRSABits`, `rejectPublicKeyAlgorithms` and `rejectCurves`
are now applied to the primary key, aside from the selected subkey.

The motivation is that the subkeys are certified by the primary key, but if the latter is
weak, arbitrary subkeys could potentially be added.

Note that the change does not affect decryption, to allow decrypting older messages.
2024-02-02 14:50:32 +01:00
larabr
f64dc3f35f
enums.curve: rename NIST curves (p256,p384,p521`) and clean up unused internal values (#1721)
This is a breaking change, as NIST curves identifiers and values in
`enums.curves` have been renamed:
- the identifiers `enums.curve.p256`, `.p384`, `.p521` are now marked as
`@deprecated`
- the new identifiers are, respectively: `enums.curve.nistP256`, `.nistP384`,
`.nistP521`.
- the corresponding values have been changed from `'p256'`,`'p384'`,`'p521'` to
`'nistP256'`, `'nistP384'`, `'nistP521'`.

Affected high-level API functions:
- in `generateKey`, the `options.curve` argument will expect the updated string
values
- `Key.getAlgorithmInfo()` will return the updated `curve` values
2024-02-02 12:54:24 +01:00
larabr
6370e0b2d3 CI: fix typescript test runner issues by switching to tsx from ts-node
ts-node is still needed for mocha to work with the different versions of Node
(passing --import in NODE_OPTIONS is not supported in older versions).
2024-02-01 10:38:01 +01:00
larabr
6bfb557ca6 Update Rollup to v4 2024-02-01 10:23:50 +01:00
larabr
959956cfc9
Use Compression Stream API when available, drop config.deflateLevel (#1717)
Breaking change: the `config.deflateLevel` is removed as the API does not accept a deflate level
in input, and the setting is of limited importance. Plus, using compression
is discouraged on security grounds.
2024-02-01 09:42:16 +01:00
larabr
99899d1d5c
Drop support for native Node Readable stream: require passing Node Web Streams (#1716)
Breaking change: all functions taking streams as inputs will now require passing Web Streams in Node.js . If given a native `stream.Readable` input, they will throw. The browser build is unaffected by this change.

Utils to convert from and to Web Streams in Node are available from v17,
see https://nodejs.org/api/stream.html#streamreadabletowebstreamreadable-options .
Previously, we automatically converted between Node native streams and custom, Web-like Readable streams.
This led to occasional issues.
2024-01-26 17:52:29 +01:00
larabr
591b9399a8
Skip key validation for keys encrypted with non-legacy AEAD mechanism (#1713)
The public key material integrity is guaranteed by the new encryption mechanism,
hence `.validate()` does not need to run further checks.
2024-01-15 15:07:09 +01:00
larabr
f77da9cdb0
Add config.parseAEADEncryptedV4KeysAsLegacy to support AEAD-encrypted v4 keys from OpenPGP.js v5 or older (#1672)
The config option must be set when reading v4 private keys (e.g. those
generated in OpenPGP.js by default, without setting `config.v5Keys = true`)
which were encrypted by OpenPGP.js v5 (or older) using `config.aeadProtect = true`.
Otherwise, key parsing and/or key decryption will fail.

Additional context: OpenPGP.js up to v5 used to support encrypting v4 keys
using AEAD as specified by draft RFC4880bis
(https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-5.5.3-3.5).
Said AEAD mechanism was not standardized as-is, and it's been replaced in the
crypto-refresh with a new version that guarantees full key integrity on decryption.
The legacy AEAD format is incompatible, but fundamentally indistinguishable,
from that of the crypto-refresh for v4 keys. Thus, we rely on the caller to
instruct us to process the key as legacy, via the new config flag.

Co-authored-by: Daniel Huigens <d.huigens@protonmail.com>
2024-01-12 16:29:56 +01:00
larabr
19cb6ee521 Lint: make 'space-before-function-paren' rule stricter to reflect enforced style 2023-12-18 15:52:19 +01:00
larabr
e92b44bc84 CI (temp): fix typescript test runner failure due to ts-node bug
This fix triggers some warnings about experimental features,
and it's meant to be temporary until ts-node shares a long-term solutio .

See https://github.com/TypeStrong/ts-node/issues/2094.
2023-12-08 15:10:27 +01:00
larabr
c754fac10f CI: replace nyc with c8 as coverage tool
Unclear if nyc is still actively maintained, and it does not seem
to work with ESM out of the box.
2023-12-08 14:53:19 +01:00
larabr
90a2af9fe2 Tests: fix flaky elliptic curve test in Node
`genKeyPair()` does not pad the returned values. This caused random test failures in Node
as some secret keys are 1 byte short.
2023-12-08 14:46:41 +01:00
larabr
ff4181ad5a Add back zlib and zip to preferred compression algos on key generation
To signal support, despite "no compression" being preferred by default,
for security reasons.
2023-12-08 14:00:22 +01:00
larabr
e93702bb8d Fix types path for lightweight build [skip ci] 2023-11-21 17:34:59 +01:00
Ryan
54fc2c8fbd
Add SHA3-256 and SHA3-512 to preferred hash algos on key generation (#1696)
This is to signal support to senders who wish to use these algos.
Note  that SHA256 remains as first default preference, followed by SHA512,
as in the context of OpenPGP signatures they provide
better performance/security ratio than their SHA3 counterparts.
2023-11-02 14:16:40 +01:00
larabr
7881b850ec 6.0.0-alpha.0 2023-10-25 12:55:43 +02:00
larabr
0da131cd9a Update README 2023-10-25 12:53:15 +02:00
larabr
30635c72e8 Lint: error on unnecessary switch-case braces
Also fix some indent issues with armoring code detected after required ESLint update.

s
2023-10-25 12:53:15 +02:00
larabr
917faa56f5 Rename internal functions, filter key algos on decryption 2023-10-25 12:53:14 +02:00
larabr
690346a854 Refuse to use keys without key flags, add config.allowMissingKeyFlags
Key flags are needed to restrict key usage to specific purposes:
https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-5.2.3.29 .
Some older keys (e.g. from OpenPGP.js v1) do not declare any key flags.
In previous OpenPGP.js versions, we've allowed such keys to be used for any operation for which they were compatible.
This behaviour has now changed, and these keys are not allowed to be used for any operation.

The setting  `config.allowMissingKeyFlags` has been added to selectively revert to the past behaviour.
2023-10-25 12:53:14 +02:00
larabr
9a547b4553 Update rollup to v3 2023-10-25 12:53:14 +02:00
larabr
86f5a8b71b Rollup: use preserveEntrySignatures = 'exports-only' setting in lightweight build
This is the default setting and it ensures that the main chunk does not include
additional exports, which is is important when importing the module as `import *`
as shown in the readme.
In practice, this change does not affect the chunking with the current code.
2023-10-25 12:53:14 +02:00
larabr
4ee9deae62 Switch back to using standard BigInteger class instead of wrapper
Using a wrapper requires adding some handling code to fix race conditions,
but it does not provide advantages until we switch to TS.
2023-10-25 12:53:14 +02:00
larabr
9e1962f006 Import noble-hashes, noble-curves and BN.js only on demand
This primarily affects the lightweight build, which will not include these
(fairly large) libs in the main bundle file. This allows fetching their code only if required:
- Noble-curves is only needed for curves other than curve25519.
- Noble-hashes is needed for streamed hashing and e.g. SHA3 on web.
- BN.js is used by the above libs, and it's also separately needed for platforms
without native BigInt support.
2023-10-25 12:53:14 +02:00
larabr
5456211266 Simplify userID parsing based on conventions, drop third-party parsing lib
Follow conventions as per https://datatracker.ietf.org/doc/draft-dkg-openpgp-userid-conventions
2023-10-25 12:53:14 +02:00
larabr
a56a4a16e8 Use internal tweetnacl SHA-512 implementation
Instead of relying on externally provided one (no async loading supported)
2023-10-25 12:53:14 +02:00
larabr
7295a2e7b3 Rename config.useIndutnyElliptic to .useEllipticFallback
To reflect change of underlying library
2023-10-25 12:53:14 +02:00
larabr
909d44f436 Add back support for verification of some invalid ECDSA sigs affected by old lib bug
At some point we used to generate invalid ECDSA sigs with the js (non-native) elliptic lib,
if the signature digest had leading zeros: https://github.com/openpgpjs/openpgpjs/pull/948 .

Brainpool curves are the most likely to have been affected by the bug, since they do not
have WebCrypto support (unlike NIST curves).
This commit reintroduces support on web to verify such invalid signatures
(support for this was previously built-in in the indutny-elliptic library).
It also expands the fix to work in Node.
2023-10-25 12:53:14 +02:00
larabr
a9fae5ff12 Replace indutny-elliptic lib with noble-curves
Unlike elliptic, noble-curves targets algorithmic constant time, and
it relies on the native BigInts when available, resulting in a smaller bundle
and improved performance.

Also, expand testing of fallback elliptic implementation.
2023-10-25 12:53:14 +02:00
larabr
01df8ca889 Rename values of enums.curve.{curve, ed}25519Legacy from '{curve. ed}25519' to '{curve. ed}25519Legacy'
To reflect the crypto-refresh naming, after the standardisation of the new EdDSA
key types.
2023-10-25 12:53:14 +02:00
larabr
d6d8576700 Prevent generating v6 keys using legacy curve25519 2023-10-25 12:53:14 +02:00
larabr
c7efef60ac Throw when parsing v6 keys using legacy curve25519 2023-10-25 12:53:14 +02:00
larabr
7c2248151d Default to generating new curve25519 format for v6 keys
As per the spec, v6 keys must not use the legacy curve25519 format.
The new format is not used by default with v4 keys as it's not compatible with OpenPGP.js older than v5.10.0 .
However, v6 keys already break compatibility, so if the user requests them via config flag, we can safely use the new curve format as well.
2023-10-25 12:53:14 +02:00
larabr
360a44f57b addSubkey: match primary key version
As required by the spec.
2023-10-25 12:53:14 +02:00
larabr
0b7a5f69fa Drop enums.publicKey.eddsa in favour of enums.publicKey.eddsaLegacy
The crypto-refresh has standardised a new key format for EdDSA, whose algorithm
identifier are `enums.publicKey.ed25519` and `.ed448`
2023-10-25 12:53:14 +02:00
larabr
24c644207d Support generating Curve448 and Curve25519 keys (new format)
Neither type is set as default for now, since they are not widely supported.
2023-10-25 12:53:14 +02:00
larabr
1509364a49 Throw on unexpected param sizes in secret keys, session keys and signatures
Detect extra bytes in secret key material, as well as missing bytes in other parameters.
2023-10-25 12:53:14 +02:00
larabr
2afa19db01 Run npm audit 2023-10-25 12:53:13 +02:00
larabr
d291ce6d0f Update Curve448 tests using inputs from gopenpgp 2023-10-25 12:53:13 +02:00
larabr
089a14f9e0 Internal: refactor uint8ArrayToHex for performance and to avoid branching 2023-10-25 12:53:13 +02:00
larabr
56cd448a32 crypto-refresh: add support for X448 2023-10-25 12:53:13 +02:00
larabr
1ebf7034f5 crypto-refresh: add support for Ed448 2023-10-25 12:53:13 +02:00
larabr
105b3cdde4 Disregard config.aeadProtect when encrypting to public keys (#1678)
Determine whether AEAD should be used for encryption solely based the encryption key preferences.
Previously, the config flag was also used to control the behaviour, since AEAD messages were not standardised nor widely supported.

To generate keys that declare AEAD in their preferences, use `generateKey` with `config.aeadProtect = true`.
2023-10-25 12:53:13 +02:00
larabr
97ebd14829 Fix parsing of v6 signatures with unknown hash algorithm (#1683)
Fail on verification rather than parsing, also for unexpected salt size.
2023-10-25 12:53:13 +02:00
Ryan
53e1ec023f Add SHA-3 signature support (#1680)
To support parsing, signing and verifying SHA3 signatures over messages and
keys.
2023-10-25 12:53:12 +02:00
larabr
8fe04c99c6 Remove unused enums.symmetric.plaintext
This special cipher value can be relevant for unencrypted private keys:
https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-12.2.1 .
However, it is no longer used internally, and on the contrary it could cause
confusion on SKESK decryption, where "random" cipher algos are returned in case
of wrong password.

This change also fixes a flaky test on password-based decryption, caused by the
PKESK v6 changes which add support for `null` cipher algos. The code did not
distinguish between a `null` and a `0` (plaintext) algo identifier, and would
break when the latter was returned on SKESK decryption.
2023-10-25 12:53:12 +02:00
larabr
278a61adab Add SEIP.fromObject
To avoid defaulting to v1
2023-10-25 12:53:12 +02:00
larabr
1423bdd564 Add PKESK.fromObject 2023-10-25 12:53:12 +02:00
Lukas Burkhalter
79b3687424 Only emit Hash header below V6 for cleartext messages
The latest version of the crypto refresh (i.e., !313, !314) specifies that
the "Hash" header is depricated. This commit changes that the Hash header
is only generated if a cleartext message contains a non-V6 signature.
2023-10-25 12:53:12 +02:00
Lukas Burkhalter
1ddf4e151c Accept cleartext messages without hash header
The latest version of the crypto refresh (i.e., !313, !314) specifies that
the  "Hash" header is deprecated, and that an implementation that is verifying
a cleartext signed message MUST ignore this header.
However, we go against this directive, and keep the checks in place to avoid
arbitrary injection of text as part of the "Hash" header payload.
We also mandate that if the hash header is present, the declared
algorithm matches the signature algorithm. This is again to avoid
a spoofing attack where e.g. a SHA1 signature is presented as
using SHA512.
Related CVEs: CVE-2019-11841, CVE-2023-41037.

This commit does not change the writing part of cleartext messages.

# Conflicts:
#	src/cleartext.js
2023-10-25 12:53:12 +02:00
Lukas Burkhalter
af96628855 Add support for v6 one-pass signature packets
Introduces v6 one-pass signature packets required for v6 signatures.
Includes the changes from !305 of the crypto refresh:
https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/305

Also, introduce `OnePassSignaturePacket.fromSignaturePacket` to simplify
OPS generation.
2023-10-25 12:53:12 +02:00
larabr
0b8501427b Implement packet criticality check
The Packet Tag space is now partitioned into critical packets and non-critical packets.
If an implementation encounters a critical packet where the packet type is unknown in a packet sequence,
it MUST reject the whole packet sequence. On the other hand, an unknown non-critical packet MUST be ignored.

See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-4.3.1 .
2023-10-25 12:53:12 +02:00
larabr
95fd04db8e Support AEAD encryption for v4 and v6 private keys 2023-10-25 12:53:12 +02:00
Daniel Huigens
21343f2bb8 Appease linter 2023-10-25 12:53:12 +02:00
larabr
33af3debc4 Throw intelligible error on GCM authentication failure, fix/refactor test for modification detection on decryption
Also, address race condition in error handling as part of AEAD message decryption,
which would cause non-uniform errors during testing.
2023-10-25 12:53:12 +02:00
Daniel Huigens
0e08abb3e2 When decrypting a v6 PKESK in constant-time, use the v2 SEIPD algorithm
Rather than using the config to determine which algorithms to try
to decrypt session keys for, try the algorithm we know the message
was encrypted with.
2023-10-25 12:53:12 +02:00
Daniel Huigens
7e382e6e43 Add support for PKESK v6
Also, set version in PKESK constructor to null,
requiring to explicitly set all fields.

Co-authored-by: Lukas Burkhalter <lukas.burkhalter@proton.ch>
2023-10-25 12:53:12 +02:00
Daniel Huigens
f77ed0c0ed Look up preferred ciphersuite in one go
Instead of calling getPreferredAlgo('symmetric') and
getPreferredAlgo('aead'), we define and call getPreferredCipherSuite()
to determine the preferred symmetric and AEAD algorithm.

Additionally, we remove isAEADSupported(), instead we return
aeadAlgorithm: undefined from getPreferredCipherSuite() if AEAD is not
supported (CFB is used instead).

And finally, we define getPreferredCompressionAlgo() to replace
getPreferredAlgo('compression').
2023-10-25 12:53:12 +02:00
Daniel Huigens
e5fe84dc2e Support SKESK v6 as per the latest crypto refresh
The latest crypto refresh specifies an HKDF step to be used for
deriving the key to encrypt the session key with.

It also specifies two additional length fields.
2023-10-25 12:53:12 +02:00
Daniel Huigens
6ae87b9208 Implement Padding Packet 2023-10-25 12:53:12 +02:00
Daniel Huigens
9d85938ed7 Implement SEIPD v2 2023-10-25 12:53:12 +02:00
Daniel Huigens
939622e827 Remove armor checksum check
The crypto refresh says that we MUST NOT reject messages where the
CRC24 checksum is incorrect. So, we remove the check for it.

Also, remove the checksumRequired config.
2023-10-25 12:53:12 +02:00
Daniel Huigens
6f1eb06119 For v6 keys, check direct-key signature for key properties
Key flags, expiration time, algorithm preferences, et cetera, are now
read from the direct-key signature instead of the primary User ID
binding signature for v6 keys.

This also requires a direct-key signature to be present for v6 keys.
2023-10-25 12:53:12 +02:00
Daniel Huigens
5391bcc1bc Update fallback (mandatory) AEAD algorithm to OCB
This has been changed in the crypto refresh.
2023-10-25 12:53:12 +02:00
Daniel Huigens
f21e327e69 Tests: update expected algorithm preferences 2023-10-25 12:53:12 +02:00
Daniel Huigens
2419e6b4c5 Remove compression algorithms from preferences 2023-10-25 12:53:12 +02:00
Daniel Huigens
762775bc03 Don't generate armor checksum lines 2023-10-25 12:53:12 +02:00
Daniel Huigens
b077504b3c Remove AES-192 from preferred symmetric algorithms
Chrome's Web Crypto implementation doesn't support it, and it
seems unnecessary to list it when AES-256 is available.
2023-10-25 12:53:12 +02:00
Daniel Huigens
5008f07808 Add preferred ciphersuites subpacket
This subpacket replaces both symmetric algorithm preferences and
AEAD algorithm preferences when AEAD is supported, by providing
sets of preferred symmetric and AEAD algorithm pairs.

We still keep the symmetric algorithm preferences in case AEAD is
not supported.
2023-10-25 12:53:11 +02:00
Daniel Huigens
b6dc112eb3 Add (non-experimental) GCM
Also, set it as the preferred AEAD algorithm.
2023-10-25 12:53:11 +02:00
Daniel Huigens
5078b8a66d Generate SEIPD v2 flag instead of AEAD flag
The AEAD Encrypted Data packet has been removed from the draft
in favor of version 2 of the Sym. Encrypted Integrity Protected
Data packet. It also has a new feature flag to match.
2023-10-25 12:53:11 +02:00
Daniel Huigens
bafdab20cf Don't require User IDs for v6 keys 2023-10-25 12:53:11 +02:00
Daniel Huigens
3ea21f6c6a For v6 keys, create direct-key signature for key properties
Store key flags, features and preferences in a direct-key signature
instead of user ID signatures, for V6 keys.
2023-10-25 12:53:11 +02:00
larabr
091be036f4 Rename enums.signatureSubpacket.issuer to .issuerKeyID
To reflect the subpacket rename in the crypto-refresh.
2023-10-25 12:53:11 +02:00
larabr
71ac6aff2f Only parse Issuer Key ID subpacket in v4 signatures
This packet must not be included in newer signature versions, but if it is
present it can cause internal inconsistencies, so we avoid parsing it.
2023-10-25 12:53:11 +02:00
Daniel Huigens
a5f1ab8a1c Add support for v6 signatures
Compared to v5 signatures, v6 signatures include a salt, and the
subpacket lengths are increased from 2 to 4 bytes.
2023-10-25 12:53:11 +02:00
Daniel Huigens
8816bd7541 Replace config.v5Keys with config.v6Keys flag
Also, don't generate v5 keys flag, which has been removed from the draft specification.
2023-10-25 12:53:11 +02:00
Daniel Huigens
31c2a2575d Add support for v6 key packets
Compared to v5 keys, v6 keys contain additional length fields to aid in
parsing the key, but omit the secret key material length field.

Additionally, unencrypted v6 secret key packets don't include the count
of the optional fields, as per the updated crypto refresh. Since they
are always absent, the count is not needed.

Finally, unencrypted v6 secret keys do not include the two-byte checksum.
2023-10-25 12:53:11 +02:00
larabr
4521de2bea HKDF: remove fallback for Node 14
v6 drops support for Node 14, which does not include SubtleCrypto
2023-10-25 12:53:11 +02:00
larabr
538b5b6304 Set Node 16 as minimum supported version in package.json 2023-10-25 12:53:11 +02:00
larabr
97b73489d1 Replace internal BigInteger code with that from noble-hashes
The noble-hashes fork uses the same fallback implementation,
except BN.js is always imported (due to lib contraints), so a dynamic import is now superfluous
2023-10-25 12:53:11 +02:00
larabr
6ef4392fb1 Lint: update config to support ESM imports 2023-10-25 12:53:11 +02:00
larabr
e07a0c432a Replace hash.js with noble-hashes 2023-10-25 12:53:11 +02:00
larabr
7c9549ce88 Drop config.minBytesForWebCrypto
WebCrypto performance is now on-par or better than non-native libs even for small messages
2023-10-25 12:53:11 +02:00
larabr
b3ef95e60e Tests: update sinon 2023-10-25 12:53:11 +02:00
larabr
b3574d6b3e CI: test all Node.js version even if some fail 2023-10-25 12:53:10 +02:00
larabr
6d477ea509 Add time benchmark test for streamed sign (testing hashing performance) 2023-10-25 12:53:10 +02:00
larabr
2377b2958d Use WebCrypto for streamed CFB encryption; for CFB/GCM/EAX, fallback to asmcrypto only if key size is not supported
CFB decryption is too slow using WebCrypto (CBC mode), since every block needs to be decrypted separately
2023-10-25 12:53:10 +02:00
larabr
21a6d83ec8 Update asmcrypto.js, use for AES only (move to noble-hashes for sha1, sha256) 2023-10-25 12:53:10 +02:00
larabr
0b2767fe4c Replace pako with fflate as compression lib
fflate already supports ESM and is actively maintained
2023-10-25 12:53:10 +02:00
larabr
1aefed9602 Fix streaming tests for browser, drop NodeReadableStream tests in Node.js
Unclear why the Node tests fails, but we're planning to drop support
2023-10-25 12:53:10 +02:00
larabr
b094274d98 Remove @private JSDoc directives interfering with TS 2023-10-25 12:53:10 +02:00
larabr
ae4ed1fbf3 Tests: explicitly share openpgp instance used in tests
Also, init config before any code is run in tests
2023-10-25 12:53:10 +02:00
larabr
d49d92e5cb Update to Mocha v10 in tests, declare lib as module and add exports to package.json
Mocha v10 requires the lib to be esm compliant.
ESM mandates the use of file extensions in imports, so to minimize the
changes (for now), we rely on the flag `experimental-specifier-resolution=node`
and on `ts-node` (needed only for Node 20).

Breaking changes:
downstream bundlers might be affected by the package.json changes depending on
how they load the library.
NB: legacy package.json entrypoints are still available.
2023-10-25 12:53:10 +02:00
larabr
3520a357f5 CI: drop Node 14 2023-10-25 12:53:10 +02:00
larabr
ebf22f2ee7 crypto-refresh: add support for Argon2 S2K (#1597)
In terms of API, this feature is backwards compatible, no breaking changes.
However, since a Wasm module is loaded for the Argon2 computation, browser apps
might need to make changes to their CSP policy in order to use the feature.

Newly introduced config fields:
- `config.s2kType` (defaulting to `enums.s2k.iterated`): s2k to use on
password-based encryption as well as private key encryption;
- `config.s2kArgon2Params` (defaulting to "uniformly safe settings" from Argon
RFC): parameters to use on encryption when `config.s2kType` is set to
`enums.s2k.argon2`;
2023-10-25 12:53:10 +02:00
larabr
204f32791d CI: temporarily enable for PRs to v6 branch 2023-10-25 12:53:10 +02:00
Daniel Huigens
e1ba0b2373 Use globalThis for setting test helper functions globals 2023-10-25 12:53:10 +02:00
Daniel Huigens
95c73738fa Update ESLint globals syntax 2023-10-25 12:53:10 +02:00
Daniel Huigens
de5549ff69 Remove embedded Web Streams ponyfill
Require the application to load a polyfill instead.
2023-10-25 12:53:10 +02:00
Daniel Huigens
cec4e029f0 Update web-stream-tools 2023-10-25 12:53:10 +02:00
larabr
7003d19c71 5.11.0 2023-10-25 12:04:48 +02:00
oofdog
111132238d
TS: Allow nullable date in VerifyOptions (#1644) 2023-10-23 13:39:33 +02:00
larabr
fe420d0bf9 Rename enums.curve.x25519Legacy to .curve25519Legacy
To keep name aligned with the spec.
2023-10-19 15:41:02 +02:00
larabr
410dbcf1d5
Fix Node 20 tests: always use NodeCrypto over WebCrypto (#1692)
This is also to uniform behaviour across Node versions for now.
2023-10-12 10:10:28 +02:00
larabr
96d6e76c05
Fix stream closure when using Node's stream.pipeline (#1691) 2023-10-11 17:30:36 +02:00
larabr
ed482a17c5
Merge pull request #1687
`crypto-refresh`: minor fixes and updates for X25519/Ed25519 (new format)
2023-10-10 13:06:09 +02:00
larabr
99ba76c695 Add enums.curve.ed25519Legacy and .x25519Legacy
Set to replace `enums.curve.ed25519` (resp. `.curve25519`), which can still be used everywhere,
but it will be dropped in v6.
Deprecation notices have been added to ease transition.
2023-10-10 11:36:47 +02:00
larabr
a12ca976a0 Reject signatures with hash digest shorter than 256-bit for ed25519
As mandated by the new crypto-refresh spec.
This applies to both the new and legacy EdDSA format.
For the legacy signatures, it is not expected to be a breaking change, since the spec
already mandated the use SHA-256 (or stronger).
2023-10-10 11:36:47 +02:00
larabr
c0f57dffb2 Do not clamp generated private key in X25519 (new format)
This was required by legacy ECDH over curve25519, but not for the new format.
Relevant spec: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-curve25519legacy-ecdh-secre
2023-10-10 11:36:47 +02:00
larabr
b6fbab0443 Internally use createSignaturePacket helper whenever possible 2023-10-10 11:36:46 +02:00
larabr
1fd9d2f0c5 Fix binding signature generation using shorter hash than expected for some ECDSA subkeys
The required hash size was determined based on the subkey algo rather than the primary key.
As a result, if the subkey being certified required a shorter hash size than the ECDSA primary key,
the issued signature would include a shorter digest than expected.

This issue is not expected to have practical security impact, and
it only affected keys with ECDSA subkeys with smaller key sizes than their ECDSA primary key
(e.g. NIST p521 primary key and NIST p256 subkey).
2023-10-03 18:50:40 +02:00
larabr
01b02d6092 Always select SHA-256 or longer hash for Ed25519 signatures (new format)
Due to a bug, a shorter hash could be selected, and signing would throw as a result.
This change fixes the issue by automatically picking SHA-256, if needed.
The same was already done for legacy EdDSA signatures.
2023-10-03 18:50:40 +02:00
larabr
5b283550b7 Add enums.publicKey.eddsaLegacy
Set to replace `enums.publicKey.eddsa`, which can still be used everywhere,
but it will be dropped in v6.
Deprecation notices have been added to ease transition.
2023-10-03 18:50:36 +02:00
larabr
d6145ac73e 5.10.2 2023-09-18 14:47:25 +02:00
larabr
f90c53ae65 Minor: fix packet validity check for new curve25519 keys without key flags
The code used to wrongly consider e.g. x25519 keys without key flags as valid signing keys.
Keys without key flags are very rare nowadays, so this fix has low impact.
2023-09-18 14:25:45 +02:00
larabr
2ba8229d23
Fix CFB decryption performance in JS fallback for ciphers other than AES (#1679)
This issue affected non-AES ciphers (legacy), such as Cast5, in Node 18+ and in browser.
2023-09-18 14:14:49 +02:00
larabr
5d02e3a03e 5.10.1 2023-08-29 16:52:34 +02:00
larabr
6b43e02a25
Merge pull request from GHSA-ch3c-v47x-4pgp
Reject cleartext messages with extraneous data preceeding hash header
2023-08-29 16:49:28 +02:00
larabr
11b59994cf Reject cleartext messages with extraneous data preceeding hash header
Parsing of such messages will fail, as the data in the header is not verified,
and allowing it opens up the possibility of signature spoofing.
2023-08-29 16:30:35 +02:00
larabr
4df86e53a7 5.10.0 2023-08-29 14:59:17 +02:00
larabr
8d4dd349ae
Merge pull request #1620
Add support for new Ed25519/X25519 keys, signatures and messages,
as per crypto-refresh document.
2023-07-26 10:08:41 +02:00
larabr
5ae2846d97 CI: test on iOS Safari 14 instead of 15 to have access to SubtleCrypto
SubtleCrypto not available in the latter due to stricter secure context checks
2023-07-25 10:18:05 +02:00
larabr
b164190f6a Internal: rename Curves to CurvesWithOID
Following the addition of the new format for Montgomery curves,
which do not rely on OIDs.
2023-07-25 10:18:05 +02:00
larabr
ef953ce81e Add HKDF fallback for Node 14, where SubtleCrypto is not available 2023-07-25 10:18:00 +02:00
larabr
ee4ad89451 Enforce AES with PKESK v3 using x25519 (new format)
Fail on PKESK parsing as well as session key generation and encryption
2023-07-25 10:17:17 +02:00
larabr
1c07d268b8 crypto-refresh: add support for new X25519 key and PKESK format
As specified in openpgp-crypto-refresh-09.

Instead of encoding the symmetric key algorithm in the PKESK ciphertext (requiring padding),
the symmetric key algorithm is left unencrypted.

Co-authored-by: Lukas Burkhalter <lukas.burkhalter@proton.ch>
2023-07-25 10:17:09 +02:00
larabr
3f44082457 crypto-refresh: add support for new Ed25519 key and signature format
This addition is backwards compatible. We offer no way to generate v4 keys in the new format.
2023-07-13 11:58:40 +02:00
larabr
b6170aa40d
Merge pull request #1656
Fix forward compatibility of keys, SKESKs, and detached/cleartext signatures and ECDH.

Relevant for forward compatibility when:
- verifying **detached** or cleartext signatures that include e.g. v4 and v6 packets.
  Non-detached signatures are not affected.
- parsing messages with sym. encrypted session keys (SKESK) that rely on unsupported S2K types (e.g. argon2)
- parsing keys that include ECDH subkeys with unknown KDF params version
  (e.g. end-to-end encrypted forwarding use-case)
2023-07-10 19:38:39 +02:00
larabr
32caf41929 Fix parsing of ECDH with unknown KDFParam version
Keys with such subkeys should still be usable, as long as they have
a supported primary key.
2023-07-10 15:26:39 +02:00
larabr
f5b5b73f07 Fix parsing of messages with unsupported SKESK s2k type
These messages should still be decrypt-able if they include at least one
supported ESK packet.
2023-07-10 15:26:39 +02:00
larabr
9ed1135d74 Fix verification of cleartext signatures that include unknown signature packet versions 2023-07-10 15:26:39 +02:00
larabr
de2ffaf8e5 Fix verification of detached signatures that include unknown signature packet versions
Relevant for forward compatibility when verifying detached signatures
that include e.g. v4 and v6 packets
2023-07-10 15:26:39 +02:00
larabr
d72cece54a
Support parsing encrypted key with unknown s2k types or cipher algos (#1658)
Such keys are still capable of encryption and signature verification.
This change is relevant for forward compatibility of v4 keys encrypted using e.g. argon2.
2023-07-10 15:23:47 +02:00
larabr
400b163f84 5.9.0 2023-05-15 16:47:20 +02:00
larabr
33c19542af
Allow email addresses with trailing numbers in domain (#1642)
Domains such as .com09 are valid (see RFC1123)
2023-05-15 16:21:51 +02:00
larabr
1eb0b42387
TS: add declaration for verify with CleartextMessage input (#1640)
Also, make `VerifyMessageResult` generic. This change should be backwards
compatible since a default type is set.
2023-05-15 16:21:05 +02:00
Mart G
29d2b701c9
Add support for verifying User Attributes in verifyAllUsers (#1637)
Previously, `verifyAllUsers` would fail on keys with User Attributes.
Now, it returns a list of objects that have a either a non-null `userID`
property (in the case of User IDs) or a non-null `userAttribute`
property that contains the User Attribute packet.

Co-authored-by: Daniel Huigens <d.huigens@protonmail.com>
2023-05-15 15:40:53 +02:00
haryu703
785d24d0d2
Add revoke to Subkey in type definition (#1639) 2023-05-02 16:59:14 +02:00
Daniel Huigens
726ee55de4 5.8.0 2023-04-18 19:21:24 +02:00
Thomas Oberndörfer
ac223bb8a6
Fix shorthand check on user revoked status in getPrimaryUser method (#1623) 2023-04-04 14:57:34 +02:00
marinthiercelin
e63ab3db4f
CI: update SOP test suite docker image (#1628)
This new release uses Node v18 instead of v12.
2023-04-03 13:44:41 +02:00
Thomas Oberndörfer
0d025d8c3d
Add additionalAllowedPackets config option (#1618)
This config option allows parsing additional packet types when parsing
a packet list or armored object, in contexts where they are normally
not expected to appear, by passing a list of packet classes
(e.g. `additionalAllowedPackets: [PublicKeyPacket]`).
2023-03-30 15:52:11 +02:00
marinthiercelin
f72e34fefa
CI: add OpenPGP interoperability test suite (#1603) 2023-03-15 11:52:51 +01:00
Daniel Huigens
c60f2e3490 5.7.0 2023-02-21 19:14:36 +01:00
larabr
bb0c1f8a08
Merge pull request #1602 from larabr/update-deps-feb23 2023-02-21 19:00:03 +01:00
larabr
8ffd7aa1d4 Remove import cycles 2023-02-21 18:27:59 +01:00
larabr
94868e606a ESLint: drop unnecessary rules
Most rules are derived from the `airbnb` template.
Some "bad" rule exceptions remain, but they require too many changes to fix, so
we leave it to a future refactoring.
2023-02-21 18:27:59 +01:00
larabr
705f238e1e Update ESlint 2023-02-21 18:27:56 +01:00
larabr
1b17132631 Update deps 2023-02-21 18:25:28 +01:00
larabr
080b49a4ce
Merge pull request #1549 from larabr/test-update-karma-browsers 2023-02-21 16:16:55 +01:00
Daniel Huigens
0ffcc4970f
Remove default known notations (#1600)
Since we don't interpret these notations, it is up to the caller
to handle them, and thus also to decide whether they are "known".
If they are marked as critical, and aren't handled by the caller,
we should consider the signature unverified.
2023-02-20 19:05:30 +01:00
larabr
66844826c6 Skip native Crypto tests if native lib is not available 2023-02-20 16:08:19 +01:00
larabr
dcd28fadc6 CI: test latest Safari 2023-02-20 16:08:19 +01:00
larabr
18333999a2 CI: test latest browsers without Browserstack, cache build step across jobs 2023-02-20 16:08:10 +01:00
larabr
b083e1d067 Update Karma 2023-02-20 15:34:39 +01:00
Roman
5b92b80f79
Add selfCertification property to PrimaryUser interface definition (#1594)
Also, mark the `publicKeys` parameter of `Key.verifyAllUsers` as optional.
2023-02-17 17:03:32 +01:00
LucienLeMagicien
3e6e8d03a4
Docs: mark global generateSessionKeys's encryptionKeys as optional (#1596) 2023-02-17 13:05:25 +01:00
Daniel Huigens
71fef439ed
Add support for creating critical signature subpackets (#1599)
Assign most signature subpacket types a criticality based on whether
failing to interpret their meaning would negatively impact security.

For Notation Data subpackets, let the user indicate their criticality
using the `signatureNotations[*].critical` property.
2023-02-17 12:21:03 +01:00
Daniel Huigens
0307111993 5.6.0 2023-02-16 14:32:01 +01:00
Daniel Huigens
64ca5af879
Merge pull request #1598 from twiss/sig-notation-creation
Add support for creating Notation Data subpackets when signing or encrypting messages
2023-02-16 13:48:20 +01:00
Daniel Huigens
70778bc4c4 Test non-ASCII notation name 2023-02-16 11:47:38 +01:00
Daniel Huigens
911e0f5330 Use UTF-8 encoding for strings in signature subpackets 2023-02-16 11:46:37 +01:00
Daniel Huigens
fbd71f8dfe Update type definitions 2023-02-16 11:24:11 +01:00
Daniel Huigens
809deee3a6 Add signatureNotations option to sign and encrypt
This allows adding Notation Data signature subpackets when signing or
encrypting a message.
2023-02-15 19:42:45 +01:00
Daniel Huigens
375b03dcd4 Make signaturePacket.rawNotations[*].critical a boolean 2023-02-15 19:42:07 +01:00
Daniel Huigens
3a6e2d1661 Fix Notation Data signature subpacket creation 2023-02-15 19:42:07 +01:00
Fabien FORESTIER
2e4e05369c
TypeScript: add missing function definitions to Subkey class (#1588)
Add types for `Subkey.getExpirationTime()`, `.isRevoked()`, `.update()`
2023-02-09 23:15:18 +01:00
larabr
126ab53840
Remove internal, unused RandomBuffer (#1593)
The changes do not affect the public API:
`RandomBuffer` was used internally for secure randomness generation before
`crypto.getRandomValues` was made available to WebWorkers, requiring
generating randomness in the main thread.
As a result of the change, the internal `getRandomBytes()` and some functions
that use it are no longer async.
2023-02-09 23:11:53 +01:00
larabr
9175b76887
Docs: clarify Key.clone() behaviour (#1589) 2023-02-09 23:07:27 +01:00
Markus Wolf
50ea1ac889
README: add TypeScript setup notice (#1586)
Mention that the library needs types from `@openpgp/web-stream-tools`.
2023-01-30 14:35:47 +01:00
Thomas Oberndörfer
4dbfcc5043
Add revoke method to User (#1584) 2023-01-24 16:34:58 +01:00
Roman
7a1a67c718
TypeScript: fix signature of armor function: add customComment (#1585) 2023-01-19 16:45:18 +01:00
Roman
2bc07996fa
TypeScript: fix SymEncryptedSessionKeyPacket type name (#1583)
Co-authored-by: DESKTOP-KRJIM7J\Roman <rrrooommmaaa@outlook.com>
2023-01-04 17:41:58 +01:00
Leo Kotschenreuther
4379bfb7ec
TypeScript: fix signature of armor function (#1576)
The `partIndex` and `partTotal` params of the `armor` function are
optional. This commit updates the openpgp.d.ts file to reflect this.
2022-11-16 14:18:06 +01:00
Leo Kotschenreuther
2f8a8c1c9a
TypeScript: add SignaturePacket.rawNotations (#1571) 2022-10-24 14:23:37 +02:00
larabr
04488af790 Bump package lock version 2022-10-24 14:15:04 +02:00
larabr
9a935ed559 CI: move away from Node.js v12
Github is deprecating it in Actions, and it's already past EOL
2022-10-24 14:15:04 +02:00
Daniel Huigens
5957bab2e2
Allow use of Brainpool curves by default (#1563)
These curves have been merged back into the editor's draft of the
crypto refresh.
2022-10-12 13:15:56 +02:00
Daniel Huigens
d0be98feb9 5.5.0 2022-08-31 13:56:51 +02:00
Daniel Huigens
9f3985d398
Hash all signature subpackets (#1562)
Move the Issuer, Issuer Fingerprint, and Embedded Signature subpackets
to the hashed subpackets for new signatures. While we allow these to be
unhashed, it's safer to hash them, and this simplifies the code as well.
2022-08-30 16:36:17 +02:00
wussler
000e1335a2
Leave unhashed subpackets as-is when re-serializing signatures (#1561)
When re-serializing a signature packet, don't add Issuer, Issuer
Fingerprint, and Embedded Signature subpackets to the unhashed
subpackets if they weren't already there.

Also, store all unhashed subpackets in `signature.unhashedSubpackets`,
not just the "disallowed" ones.
2022-08-30 13:46:05 +02:00
Daniel Huigens
5e6dd8b1ed
Remove leading newline from clearsigned messages armoring (#1560) 2022-08-30 13:40:57 +02:00
Celine Moredo
4d2cf85a51
Ignore improperly formatted armor headers (#1557)
Show a debug warning instead of throwing an error on malformed headers.
2022-08-22 15:30:33 +02:00
larabr
93644b7c58
printDebug: add label to identify source of the log (#1555) 2022-08-17 18:54:53 +02:00
larabr
ca60884c05 5.4.0 2022-08-08 13:49:52 +02:00
larabr
50fa974dcc
CI: run worker tests first to give enough time to download the required scripts (#1550)
This should fix issues with Safari 13 not managing to load the worker in BrowserStack Automate.
2022-08-08 13:28:40 +02:00
larabr
08eef424a0
TypeScript: add missing allowInsecureVerificationWithReformattedKeys field to Config (#1551) 2022-08-04 18:55:51 +02:00
larabr
dc85a5088f
Fix CleartextMessage signature generation over text with trailing whitespace and \r\n line endings
Signing a `CleartextMessage` containing trailing whitespace and \r\n line
endings (as opposed to \n) would result in an unverifiable signature. The issue
seems to have been present since v3.0.9 . These broken signatures were
unverifiable even in the OpenPGP.js version(s) that generated them.
2022-08-02 17:50:45 +02:00
larabr
e862d5f20b
Throw in encryptSessionKey if no keys or passwords are provided (#1547)
Previously, the operation would return an empty message.
2022-07-27 17:47:47 +02:00
Daniel Huigens
bd1a7db46f Use npm ci instead of npm install in release script
In order not to update the package-lock.json file during releases.
2022-06-29 21:15:18 +02:00
Daniel Huigens
dd2aa7c5ec Revert package lock version bump 2022-06-29 21:07:10 +02:00
Daniel Huigens
5c02953b1c 5.3.1 2022-06-29 21:02:15 +02:00
Daniel Huigens
04e806e0b4
Support Node.js 18 (#1542)
Recent Node.js seems to have dropped support for ripemd160.
Thus, properly check the availability of hashes before using them.

Also, add Node.js 18 to CI.
2022-06-29 20:59:38 +02:00
Daniel Huigens
e69d8b24fc
Fix armor error handling (#1541)
Fix unhandled promise rejections when parsing armor with malformed footers.
2022-06-29 20:09:30 +02:00
Daniel Huigens
449ec3a367 Fix CNAME and make docs script portable 2022-06-09 12:54:22 +02:00
larabr
b677ab5949 5.3.0 2022-06-08 16:10:17 +02:00
larabr
6c32b62ef3
Throw on decryption of messages that don't contain any encrypted data packet (#1529)
Calling `openpgp.decrypt` with a message that contains encrypted session keys
followed by a non-encrypted packet (e.g. Literal or Compressed Data packet)
used to succeed, even if a wrong passphrase/key was provided.
With this change, the operation will always fail, and the user is warned that
the data was not encrypted.

NB: a message that did not contain any encrypted session key packet would fail
to decrypt even prior to this change.
2022-06-07 14:29:31 +02:00
larabr
ef066183dd
Throw UnsupportedError on unknown algorithm in keys, signatures and encrypted session keys (#1523)
The relevant packets will be considered unsupported instead of malformed.
Hence, parsing them will succeed by default (based on
`config.ignoreUnsupportedPackets`).
2022-06-07 13:51:58 +02:00
Justin Lovell
a822dd817b
Add memory benchmark tests for streamed decryption of large files (#1462)
Also, provide more details about `config.allowUnauthenticatedStream`.
2022-06-02 17:29:27 +02:00
larabr
775dade80f
Add UnparseablePacket to properly deal with key blocks that include malformed/unsupported packets (#1522)
When parsing errors are being ignored, packets that fail to parse are now
included in the resulting packet list as `UnparseablePacket`s . This way, when
parsing keys that contain unparsable (sub)key, we avoid associating the
following non-key packets to the wrong key entity.

On serialization, `UnparseablePacket`s are also included by writing their raw
packet body as it was read.
2022-05-24 20:12:57 +02:00
larabr
cb8901c16d
Fix loading browser built in JSDom environment (#1518) 2022-05-12 17:29:52 +02:00
larabr
4713282bb1
Throw on empty passphrase in encryptKey and SecretKeyPacket.encrypt (#1508)
Breaking change: `openpgp.encryptKey` now throws if an empty string is given as
passphrase. The operation used to succeed, but the resulting key was left in an
inconsistent state, and e.g. serialization would not be possible.

Non-breaking changes:
- `options.passphrase` in `generateKey` and `reformatKey` now defaults to
`undefined` instead of empty string. Passing an empty string does not throw for
now, but this might change in the future to align with `encryptKey`'s
behaviour.
- In TS, add `GenerateKeyOptions` as alias of `KeyOptions`, to clarify its
scope.
2022-03-22 15:11:51 +01:00
Daniel Huigens
d677c30359 5.2.1 2022-03-15 14:59:45 +01:00
larabr
36985c92dc
Lint: error if imported value not found in module (#1507) 2022-03-14 21:40:16 +01:00
larabr
2e867956eb
Fix AES encryption error in browsers for messages larger than 3MB (#1506)
In browsers, encryption of messages larger than 3MB (or a custom value
based on `config.minBytesForWebCrypto`) would throw the error `Error encrypting
message: 'crypto.getCipher' is not a function`.

The issue was introduced in v5.1 .
2022-03-14 19:39:15 +01:00
larabr
d89cc48bf3
TypeScript: rely on new web-stream-tools types, fix SignOptions (#1502)
The updated stream types improve type inference and checks, in particular when
using ReadableStreams.

Also:
- add `EncryptSessionKeyOptions` to make it easier to declare wrapper functions
of `encryptSessionKey`;
- tighter output type inference in `Message.getText()` and `.getLiteralData()`.
2022-03-09 17:00:12 +01:00
Daniel Huigens
a1ef5f509f 5.2.0 2022-03-02 21:35:43 +01:00
larabr
7aaa34ddfc
CI: update mocha (#1503)
Update to mocha@8 instead of 9 because the latter dropped support for `--require
esm`, hence using it would require more extensive changes.
2022-03-01 16:34:52 +01:00
Ivan Pizhenko
e5c7c77362
TypeScript: fix data argument type in SignaturePacket.verify() (#1494) 2022-02-18 20:20:50 +01:00
Daniel Huigens
f93f59e2e5
Check existence of navigator before using it (#1475) 2022-02-11 13:33:43 +01:00
Daniel Huigens
f54b133085
Drop MS Edge Legacy support (#1474) 2022-02-10 21:31:32 +01:00
Ivan Pizhenko
255926ab19
TypeScript: mark signature arg as optional in Key.isRevoked() and remove SignaturePacket.verified (#1486) 2022-02-10 21:13:34 +01:00
Daniel Huigens
717f6bffe4 Update web-stream-tools 2022-02-01 16:24:52 +01:00
Daniel Huigens
917b5e51c2 Persist docs/CNAME after release 2022-01-25 18:53:32 +01:00
Daniel Huigens
d5d8de36f5
Create CNAME 2022-01-25 12:17:49 +01:00
Daniel Huigens
bd13edfc88 5.1.0 2022-01-24 18:38:46 +01:00
larabr
22a68878e4
Add support for constant-time decryption of PKCS#1 v1.5-encoded session keys (#1445)
Implement optional constant-time decryption flow to hinder Bleichenbacher-like
attacks against RSA- and ElGamal public-key encrypted session keys.

Changes:
- Add `config.constantTimePKCS1Decryption` to enable the constant-time
processing (defaults to `false`). The constant-time option is off by default
since it has measurable performance impact on message decryption, and it is
only helpful in specific application scenarios (more info below).
- Add `config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms`
(defaults to the AES algorithms). The set of supported ciphers is restricted by
default since the number of algorithms negatively affects performance.

Bleichenbacher-like attacks are of concern for applications where both of the
following conditions are met:
1. new/incoming messages are automatically decrypted (without user
interaction);
2. an attacker can determine how long it takes to decrypt each message (e.g.
due to decryption errors being logged remotely).
2022-01-19 19:05:43 +01:00
Austin Schmidli
a6c849166d
Update documentation link (#1455) 2021-12-21 11:32:31 +01:00
Hexagon
ce5174dd21
Initial Deno support (#1448) 2021-12-07 14:07:46 +01:00
larabr
d6139daa79
CI: use Node v16 instead of v15 2021-12-01 17:40:33 +01:00
larabr
6fc005f19c
Check key requirements in PrivateKey.addSubkey() (#1423)
Breaking change:
when generating new subkeys through `key.addSubkey()`, we now check
`config.rejectCurves` and prevent adding subkeys using the corresponding
curves.
By default, `config.rejectCurves` includes the brainpool curves
(`brainpoolP256r1`, `brainpoolP384r1`, `brainpoolP512r1`) and the Bitcoin curve
(`secp256k1`).

This is a follow up to #1395 , which introduced the same check to
`openpgp.generateKey`.
2021-12-01 17:04:02 +01:00
Bart Butler
2894b35d66 Create CNAME 2021-11-29 13:10:57 +01:00
Daniel Huigens
9e547bf6e4 Rename master branch to main 2021-11-23 12:10:57 +01:00
larabr
6da1c53de7
Replace strings with integer algorithm identifiers in packet classes (#1410)
In several packet classes, we used to store string identifiers for public-key,
aead, cipher or hash algorithms. To make the code consistent and to avoid
having to convert to/from string values, we now always store integer values
instead, e.g. `enums.symmetric.aes128` is used instead of `'aes128'`.

This is not expected to be a breaking change for most library users. Note that
the type of `Key.getAlgorithmInfo()` and of the session key objects returned
and accepted by top-level functions remain unchanged.

Affected classes (type changes for some properties and method's arguments):
- `PublicKeyPacket`, `PublicSubkeyPacket`, `SecretKeyPacket`,
`SecretSubkeyPacket`
- `SymEncryptedIntegrityProtectedDataPacket`, `AEADEncryptedDataPacket`,
`SymmetricallyEncryptedDataPacket`
- `LiteralDataPacket`, `CompressedDataPacket`
- `PublicKeyEncryptedSessionKey`, `SymEncryptedSessionKeyPacket`
- `SignaturePacket`

Other potentially breaking changes:
- Removed property `AEADEncryptedDataPacket.aeadAlgo`, since it was redudant
given `.aeadAlgorithm`.
- Renamed `AEADEncryptedDataPacket.cipherAlgo` -> `.cipherAlgorithm`
2021-11-22 11:51:27 +01:00
larabr
03fa68dbb6
CI: create annotations on performance regression warnings/errors (#1441) 2021-11-18 14:24:16 +01:00
Daniel Huigens
05e435aae7 5.0.1 2021-11-17 21:46:14 +01:00
Daniel Huigens
1d2093ab0a
Update web stream tools and improve performance (#1439)
Optimize reading literal data packet from ArrayStreams, and update
web-stream-tools (with various performance improvements).
2021-11-17 21:34:04 +01:00
Daniel Huigens
a17a7200b8
Remove line terminators from randomly generated test messages (#1440)
Remove line separators (U+2028) and paragraph separators (U+2029)
from randomly generated test messages. These messages cause the
test to fail due to the difference in handling them between
multiline regexes and OpenPGP.js-internal functions.
2021-11-17 12:11:54 +01:00
larabr
cfeef41d61
Do not include checksum values in error messages when armor integrity check fails (#1428) 2021-10-21 16:14:46 +02:00
larabr
88b1380a54
Add config.allowInsecureVerificationWithReformattedKeys (#1422)
Using `openpgp.reformatKey` with the default `date` option would render
messages signed with the original key unverifiable by OpenPGP.js v5 (not v4),
since the signing key would not be considered valid at the time of signing (due
to its self-certification signature being in the future, compared to the
message signature creation time).

This commit adds `config.allowInsecureVerificationWithReformattedKeys` (false
by default) to make it possible to still verify such messages with the
reformatted key provided the key is valid at the `date` specified for
verification (which defaults to the current time).
2021-10-18 18:10:04 +02:00
larabr
b7527f7966
CI: Add memory usage regression monitoring for pull requests (#1415) 2021-10-15 16:16:34 +02:00
larabr
421733e21b
CI: Add performance regression monitoring for pull requests (#1411) 2021-10-14 18:59:14 +02:00
lee-orr
df7e690469
Try to use process.env.NODE_ENV directly (#1402)
Support build processes that replace `process.env.NODE_ENV` with a
constant string (such as webpack and Vite) by using
`process.env.NODE_ENV` directly, instead of `globalThis.process &&
globalThis.process.env.NODE_ENV`, but do so inside a try/catch in case
`process` is not defined.

Co-authored-by: Daniel Huigens <d.huigens@protonmail.com>
2021-10-07 18:02:49 +02:00
Kevin Moutet
fc42c38706
Remove stream from type definitions (#1413) 2021-09-06 11:22:32 +02:00
Daniel Huigens
acafb28661 5.0.0 2021-09-02 17:09:02 +02:00
Daniel Huigens
4f1c474433 5.0.0-6 2021-08-20 15:34:03 +02:00
larabr
a599638ce2
Docs: clarify content of returned signatures value in openpgp.verify and decrypt 2021-08-19 17:58:52 +02:00
larabr
3fa778abe2
Add config.rejectCurves and prevent generating keys using blacklisted algorithms (#1395)
Breaking changes:
- throw error on key generation if the requested public key algorithm is
included in `config.rejectPublicKeyAlgorithms`;
- add `config.rejectCurves` to blacklist a set of ECC curves, to prevent keys
using those curves from being generated, or being used to
encrypt/decrypt/sign/verify messages.
By default, `config.rejectCurves` includes the brainpool curves
(`brainpoolP256r1`, `brainpoolP384r1`, `brainpoolP512r1`) and the Bitcoin curve
(`secp256k1`). This is because it's unclear whether these curves will be
standardised[1], and we prefer to blacklist them already, rather than introduce
a breaking change after release.

[1] https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/47#note_634199141
2021-08-19 17:58:16 +02:00
larabr
f57d3527d3
Set default config.minRSABits to 2047 (#1392)
Lower the default allowed RSA key size to ensure that (most) keys generated in
v4 without WebCrypto are supported (see #1336).
2021-08-19 17:53:06 +02:00
Daniel Huigens
f59b0dec60 5.0.0-5 2021-07-23 19:00:19 +02:00
larabr
da60fa0047
Add security policy (#1388) 2021-07-23 14:06:34 +02:00
larabr
d9829fce06
Throw on unrecognised configuration in top-level functions (#1387)
Breaking change: passing non-existing configuration options to top-level
functions now results in an error, to make users aware that the given
configuration cannot be applied.
2021-07-23 14:00:08 +02:00
larabr
4b6189b91b
Rename config.tolerant to config.ignoreUnsupportedPackets, add config.ignoreMalformedPackets (#1386)
Configuration options related to parsing have been changed to make it possible
to try to read messages containing malformed packets. Changes:
- rename `config.tolerant` to `config.ignoreUnsupportedPackets`. This still
defaults to `true`.
- Add `config.ignoreMalformedPackets` to ignore packets that fail to parse
(when possible). This option was not available before and it defaults to `false`.
2021-07-23 13:22:18 +02:00
Lucas Longarini
3cd61ff1b4
TypeScript: add missing config options to the type definitions (#1385) 2021-07-23 13:07:07 +02:00
larabr
7ebdd6a2a6
Update dependencies (#1383) 2021-07-23 12:59:39 +02:00
Daniel Huigens
1837077012 5.0.0-4 2021-07-20 19:41:10 +02:00
Daniel Huigens
5e997605b3 Update web-stream-tools 2021-07-20 19:06:31 +02:00
Ali Cherry
85d129af77
Export Subkey class (#1381) 2021-07-20 10:54:29 +02:00
larabr
1ac71a94a5
Github: add ISSUE_TEMPLATES (#1369) 2021-07-19 19:16:01 +02:00
larabr
b604458ba8
Rename format: 'armor' option to format: 'armored' in top-level functions (#1377)
The `format` option in `openpgp.generateKey, reformatKey, revokeKey, encrypt,
sign, encryptSessionKey` now expects the value `'armored'` instead of `'armor'`
to output armored data. The other format options (i.e. `'binary'` and
`'object'`) remain unchanged.
2021-07-19 19:08:49 +02:00
larabr
ce70484738
Replace armor option with format in openpgp.encrypt, sign and encryptSessionKey (#1354)
Breaking changes:
- a new `format` option has been added to `openpgp.encrypt`, `sign` and
`encryptSessionKey` to select the format of the output message. `format`
replaces the existing `armor` option, and accepts three values:
   * if `format: 'armor'` (default), an armored signed/encrypted message is
returned (same as `armor: true`).
   * if `format: 'binary'`,  a binary signed/encrypted message is returned (same
as `armor: false`).
   * if `format: 'object'`, a Message or Signature object is returned (this was
not supported before).
This change is to uniform the output format selection across all top-level
functions (following up to #1345).

- All top-level functions now throw if unrecognised options are passed, to make
library users aware that those options are not being applied.
2021-07-19 18:12:42 +02:00
Nick Darvey
53f54e1e19
Extend BaseStream<> from AsyncIterable<> (#1373)
Both Web ReadableStreams and Node.js streams are async iterable objects.
2021-07-15 13:09:29 +02:00
Akihito Mikazuki
e450582888
Update README to use openpgp.readPrivateKey() where applicable (#1362) 2021-07-09 18:05:09 +02:00
larabr
3886358592
Remove valid and error from the verification result of openpgp.verify and decrypt (#1348)
This change is to make the code more consistent between the streaming and
non-streaming cases.
The validity of a signature (or the corresponding verification error) can be
determined through the existing `verified` property.
2021-07-09 17:44:34 +02:00
larabr
ed8db3d31e
CI: Ignore unhandled rejections in tests in Safari 14.1 (#1371)
The tests fail in Safari 14.1 due to unhandled rejections that have no clear
cause. The problem is likely related to the native TransformStream
implementation added in Safari 14.1 (in fact, using a polyfilled
TransformStream solves all issues).
2021-07-09 16:35:40 +02:00
larabr
ab22fe86da
Lint: enforce single quotes and do not error on class methods without this (#1341) 2021-06-24 22:58:15 +02:00
larabr
d238a023c1
Support using Key.isPrivate() for type inference, remove Key.isPublic() (#1347)
API changes:
- `Key.isPublic()` has been removed, since it was redundant and it would
introduce TypeScript issues. Call `!Key.isPrivate()` instead.

TypeScript changes:
- the `openpgp.readKey(s)` functions are now declared as returning a `Key`
instead of a `PublicKey`. This is just a readability improvement to make it
clearer that the result could also be a `PrivateKey`.
- All `Key` methods that return a key object now have the narrowest possible
return type.
- The `Key.isPrivate()` method can now be used for type inference, allowing the
compiler to distinguish between `PrivateKey` and `PublicKey`. 

Calling `key.isPrivate()` is the recommended way of distinguishing between a
`PrivateKey` and `PublicKey` at runtime, over using `key instanceof ...`, since
the latter depends on the specifics of the `Key` class hierarchy.
2021-06-24 19:53:10 +02:00
larabr
f50abd81a1
Support passing a non-array value to encryption/signingKeyIDs in top-level functions (#1342)
- Support passing a single Key ID directly to the `encryption/signingKeyIDs`
options of `openpgp.encrypt`, `sign`, `generateSessionKey` and
`encryptSessionKey`.
- Add type definitions for `openpgp.encryptSessionKey` and `decryptSessionKeys`.
2021-06-24 17:51:18 +02:00
larabr
40542fd08a
Simplify return value of generateKey, reformatKey and revokeKey and add support for binary output (#1345)
- `openpgp.generateKey`, `reformatKey` and `revokeKey` take a new `format`
option, whose possible values are: `'armor', 'binary', 'object'` (default is 
`'armor'`).
- `generateKey` and `reformatKey` now return an object of the form `{
publicKey, privateKey, revocationCertificate }`, where the type of `publicKey`
and `privateKey` depends on `options.format`:
    * if `format: 'armor'` then `privateKey, publicKey` are armored strings;
    * if `format: 'binary'` then `privateKey, publicKey` are `Uint8Array`;
    * if `format: 'object'` then `privateKey, publicKey` are `PrivateKey` and
`PublicKey` objects respectively;
- `revokeKey` now returns `{ publicKey, privateKey }`, where:
    * if a `PrivateKey` is passed as `key` input,  `privateKey, publicKey` are of the
requested format;
    * if a `PublicKey` is passed as `key` input, `publicKey` is of the requested format,
while `privateKey` is `null` (previously, in this case the `privateKey` field
was not defined).

Breaking changes:
- In `revokeKey`, if no `format` option is specified, the returned `publicKey,
privateKey` are armored strings (they used to be objects).
- In `generateKey` and `reformatKey`, the `key` value is no longer returned.
- For all three functions, the `publicKeyArmored` and `privateKeyArmored`
values are no longer returned.
2021-06-24 17:14:39 +02:00
Ali Cherry
b862e139fc
TypeScript: make packets, keyPacket and mainKey readonly properties (#1337)
The following fields are now `readonly` instead of `private`:
- `Key.keyPacket`
- `Subkey.keyPacket` and `Subkey.mainKey`
- `Signature.packets`
- `Message.packets`
2021-06-23 12:36:37 +02:00
larabr
b76236755a
Ignore Trust and Marker packets on parsing and always throw on unexpected packets (#1340)
- When parsing, throw on unexpected packets even if `config.tolerant = true`
(e.g. if a Public Key packet is found when reading a signature).
- Always ignore Trust and Marker packets on parsing.
- Fix #1145: correctly verify signatures that include Marker packets when
`config.tolerant = false`.
2021-06-23 12:17:29 +02:00
Dan Habot
a9252c6649
Add Signature#getSigningKeyIDs method to get Issuer Key IDs from a Signature (#1331) 2021-06-16 11:46:49 +02:00
larabr
619d02d78c
Drop capabilities, keyID args in Key.getExpirationTime() and consider direct-key sigs (#1319)
- Fix #1159: `Key.verifyPrimaryKey` considers expiration time subpackets in
direct-key signatures to determine whether the key is expired.
- `Key.getExpirationTime()` does not take the `capabilities` and `keyID` arguments
anymore, and simply returns the expiration date of the primary key. Also, like
for `verifyPrimaryKey`, direct-key signatures are now taken into account.
- Keys and signatures are considered expired at the time of expiry, instead of
one second later.

Breaking change:
`Key.getExpirationTime(capabilities, keyID, userID, config)` ->
`.getExpirationTime(userID, config)`
2021-06-15 19:16:52 +02:00
larabr
bccdabbc45
Always generate RSA keys of exact bit length (#1336)
Fix RSA key generation code used when no native crypto library is available
(i.e. no NodeCrypto or WebCrypto). Now generated keys are always of exact bit
length. This was not guaranteed before, and it was common for keys to be one
bit shorter than expected.

Also, remove leftover code related to legacy WebCrypto interfaces (for IE11 and
Safari 10).
2021-06-15 18:07:36 +02:00
larabr
1166de205c
Remove primaryKey argument from User methods, rename User.sign to User.certify (#1329)
- Add `User.mainKey` field to store a reference to the corresponding `Key`,
allowing to simplify calling some `User` methods.
- Rename `User.sign` to `User.certify`, since it's used for third-party
certifications and not as a counterpart of `User.verify`, which deals with
self-signatures.
- Change `Key.update` behaviour to store a copy of newly added users and
subkeys. Pointing to the same instance could give issues as the lists of
certifications and signatures could be altered by both the source key and the
updated one.

Breaking changes in `User` methods:
- `User.constructor(userPacket)` -> `constructor(userPacket, mainKey)`
- `User.sign(primaryKey, signingKeys, date, config)` -> `.certify(signingKeys,
date, config)`
- `User.verify(primaryKey, date = new Date(), config)` -> `.verify(date = new
Date(), config)`
- `User.verifyCertificate(primaryKey, certificate, verificationKeys, date = new
Date(), config)` -> `.verifyCertificate(certificate, verificationKeys, date =
new Date(), config)`
- `User.verifyAllCertifications(primaryKey, verificationKeys, date = new
Date(), config)` -> `.verifyAllCertifications(verificationKeys, date = new
Date(), config)`
- `User.isRevoked(primaryKey, certificate, keyPacket, date = new Date(),
config)` -> `.isRevoked(certificate, keyPacket, date = new Date(), config)`
- `User.update(sourceUser, primaryKey, date, config)` -> `.update(sourceUser,
date, config)`
2021-06-15 17:42:00 +02:00
larabr
e785df4c8f
Require keys in openpgp.sign and make all top-level functions fully async (#1318)
- `openpgp.sign` throws if no signing keys are given, instead of returning a
non-signed literal packet.
- Any top-level function error will cause Promise rejection, and can thus be
handled with `.catch()`.
2021-06-15 17:21:18 +02:00
larabr
b4e53b3ff7
CI: Detect unhandled rejections in browser tests (#1333)
Also, target the Safari release for macOS Big Sur in Browserstack.
2021-06-15 16:39:56 +02:00
Daniel Huigens
df2240ba08
CI: Check that JSDoc comments are valid (#1328)
Also, fix a JSDoc comment.
2021-06-14 11:15:37 +02:00
larabr
1484df9b8f
Uniform casing of subkey(s): rename Key.subKeys to Key.subkeys (#1310)
Also, rename `SubKey` class to `Subkey`
2021-06-10 11:25:43 +02:00
Ali Cherry
ead266507e Throw if privateKeys/publicKeys are passed to top-level functions (#1327) 2021-06-09 13:23:13 +02:00
larabr
0e088aec28
Fix various signature verification issues (#1302)
- Throw on signature parsing (e.g. in `openpgp.readSignature`) if the
  creation time subpacket is missing
- `SignaturePacket.verify` now directly checks for signature creation
  and expiration times. This makes it easier to thoroughly check the
  validity of signatures. Also:
  - `openpgp.revokeKey` now takes a `date` to check the provided
    revocation certificate
  - `openpgp.decryptSessionKeys` now takes a `date` to check the
    validity of the provided private keys
  - whenever a `date` is used internally, the function accepts a
    `date` param to allow passing the correct date
- Add tests for all of the above
- Like `openpgp.generateKey`, `openpgp.reformatKey` now also requires
  `options.userIDs`
- Simplify calling `SubKey.isRevoked/update/getExpirationTime` by
  adding the `SubKey.mainKey` field to hold the reference of the
  corresponding `Key`

Breaking changes in low-level functions:
- Added/removed `date` params:
  - `Key.update(key, config)` -> `update(key, date, config)`
  - `Key.applyRevocationCertificate(revocationCertificate, config)` ->
    `applyRevocationCertificate(revocationCertificate, date, config)`
  - `Key.signAllUsers(privateKeys, config)` ->
    `signAllUsers(privateKeys, date, config)`
  - `Key.verifyAllUsers(keys, config)` ->
    `verifyAllUsers(keys, date, config)`
  - `new SignaturePacket(date)` -> `new SignaturePacket()`
  - `SignaturePacket.sign(key, data, detached)` ->
    `sign(key, data, date, detached)`
  - `Message.sign(primaryKey, privateKeys, config)` ->
    `sign(primaryKey, privateKeys, date, config)`
  - `Message.decrypt(privateKeys, passwords, sessionKeys, config)` ->
    `decrypt(privateKeys, passwords, sessionKeys, date, config)`
  - `Message.decryptSessionKeys(privateKeys, passwords, config)` ->
    `decryptSessionKeys(privateKeys, passwords, date, config)`
- Removed `primaryKey` params:
  - `SubKey.isRevoked(primaryKey, signature, key, date, config)` ->
    `isRevoked(signature, key, date, config)`
  - `SubKey.update(subKey, primaryKey, date, config)` ->
    `update(subKey, date, config)`
  - `SubKey.getExpirationTime(primaryKey, date, config)` ->
    `getExpirationTime(date, config)`
2021-06-08 18:12:48 +02:00
Ali Cherry
ab7dedf0a5
Update README to reflect parameter name changes (#1323)
Also, update the detached sign/verify example to use a Message rather
than a CleartextMessage.
2021-06-08 13:08:53 +02:00
Daniel Huigens
12e5c96607
Update BrowserStack status badge key 2021-06-01 17:07:11 +02:00
Daniel Huigens
1bff8aad50 5.0.0-3 2021-05-28 17:36:43 +02:00
Daniel Huigens
1836c40468 Fix JSDoc type 2021-05-28 17:34:59 +02:00
Daniel Huigens
0ca83cf121 Switch from Uint8Array.from to new Uint8Array 2021-05-28 17:08:13 +02:00
Daniel Huigens
5ae7fc4444 Update pako 2021-05-26 10:51:25 +02:00
larabr
f028026217
Replace Key with PrivateKey and PublicKey classes (#1300)
- Add `PrivateKey` and `PublicKey` classes. A `PrivateKey` can always
  be passed where a `PublicKey` key is expected, but not vice versa.
- Unexport `Key`, and export `PrivateKey` and `PublicKey`. 
- Rename `Key.packetlist2structure` to `Key.packetListToStructure`.
- Change `Key.update` to return a new updated key, rather than
  modifying the destination one in place.
- Add `openpgp.readPrivateKey` and `openpgp.readPrivateKeys` to avoid
  having to downcast the result of `readKey(s)` in TypeScript.
2021-05-25 19:18:47 +02:00
Yash Murty
3349fab89e
Fix link in README's table of contents (#1307) 2021-05-21 18:07:52 +02:00
Ali Cherry
6299c6dd77
Rename public/privateKeys to encryption/decryption/signing/verificationKeys (#1299)
- Rename `publicKeys` to `encryptionKeys` or `verificationKeys` depending on their use
- Rename `privateKeys` to `decryptionKeys` or `signingKeys` depending on their use
- Similarly, rename `toUserIDs` to `encryptionUserIDs` and `fromUserIDs` to `signingUserIDs`
2021-05-17 18:56:28 +02:00
Daniel Huigens
93b77669bc
Unexport openpgp.stream (#1291)
This change allows us to only load the `ReadableStream` polyfill when
needed without behaving inconsistently in the external API.

Users of the library should use the global `ReadableStream` or Node.js
`stream.Readable` instead, or import a polyfill if needed. This patch
loosens the detection criteria such that polyfilled streams are better
detected.
2021-05-05 20:20:20 +02:00
larabr
31fe960261
Only ignore unsupported packets when config.tolerant is set (#1298)
Don't ignore parse errors if `config.tolerant` is enabled. This leads to
more useful error messages in most cases, as ignoring these errors will
most likely still lead to an error down the line (e.g. if a key binding
signature is missing). Unsupported and unknown packets and packets with
an unsupported or unknown version are still ignored, for forward
compatibility.

Also, make `PKESK.encrypt`/`decrypt` void.
2021-05-05 19:51:33 +02:00
larabr
02a1ed2d78
Make key fingerprint computation async (#1297)
- Make fingerprint and key ID computation async, and rely on Web Crypto
  for hashing if available
- Always set fingerprint and keyID on key parsing / generation
- Introduce `*KeyPacket.computeFingerprint()` and
  `*KeyPacket.computeFingerprintAndKeyID()` 
- Change `getKeyID` and `getFingerprint*` functions to return the
  pre-computed key ID and fingerprint, respectively
- Make `PublicKeyPacket.read` async
2021-05-05 17:39:19 +02:00
larabr
247ad58344
Add PacketList.fromBinary and add missing config param in some functions (#1294)
- Add `PacketList.fromBinary` which parses binary data and returns a
  `PacketList`. Using it instead of `PacketList.read` avoids being left
  with partially read data in case of errors.
- Rename `toPacketlist` to `toPacketList` in `Key`, `Subkey` and `User`
  classes
- In `readMessage`, pass down `config` to `PacketList.read`
- Add `config` param to `CompressedDataPacket.decompress`,
  `AEADEncryptedDataPacket.decrypt` and `Message.appendSignature`
2021-05-05 16:56:11 +02:00
larabr
aeddac438e
Make PacketList a valid subtype of Array and update Packet.tag types (#1289)
Changes:
- Implementation:
  - Remove `PacketList.prototype.concat` and `push`
    (we solely rely on `Array.push` instead)
  - Fix https://github.com/openpgpjs/openpgpjs/issues/907 by
    correctly handling result of `filterByTag`
  - Implement `write()` method for `Trust` and `Marker` packets,
    to make them compatible with the `BasePacket` interface
- Types:
  - Simplify and updated `PacketList` type definitions
  - Fix types for `Packet.tag`, which is `static` since
    https://github.com/openpgpjs/openpgpjs/pull/1268
  - Prevent passing SubkeyPackets where KeyPackets are expected,
    and vice versa
2021-04-29 17:18:39 +02:00
Daniel Huigens
2d07c43030 5.0.0-2 2021-04-27 14:00:54 +02:00
Daniel Huigens
28c5902419 Fix JSDoc types 2021-04-27 13:58:39 +02:00
larabr
0654bbe505
Remove Key.prototype.encrypt() and Key.prototype.decrypt() (#1285)
To encrypt/decrypt a key, the top-level functions `openpgp.encryptKey` and
`openpgp.decryptKey` should be used instead: these don't mutate the key;
instead, they either return a new encrypted/decrypted key object or throw an
error.

With `Key.prototype.encrypt` and `decrypt`, which mutated the key, it was
possible to end up in an inconsistent state if some (sub)keys could be
decrypted but others couldn't, they would both mutate the key and throw an
error, which is unexpected.

Note that the `keyID` parameter is not supported by `encryptKey`/`decryptKey`,
since partial key decryption is not recommended. If you still need to decrypt
a single subkey or primary key `k`, you can call `k.keyPacket.decrypt(...)`,
followed by `k.keyPacket.validate(...)`. Similarly, for encryption, call
`k.keyPacket.encrypt(...)`.

Additionally, `openpgp.generateKey` now requires `options.userIDs` again,
since otherwise the key is basically unusable. This was a regression from v4,
since we now allow parsing keys without user IDs (but still not using them).
2021-04-23 15:43:38 +02:00
Kostis Andrikopoulos
39aa742c7a
Fix encoded length in unencrypted v5 secret key packets (#1278)
When unencrypted secret key packets are serialized, a 2-byte checksum is
appended after the key material. According to rfc4880bis, these 2 bytes are
not included in the length of the key material (this encoded length is a new
addition of rfc4880bis, specific to v5 keys). We erroneously included them,
causing other implementations to fail to parse unencrypted v5 private keys
generated by OpenPGP.js.
2021-04-06 15:00:45 +02:00
larabr
2e19f1401c
Add expectSigned option to openpgp.decrypt and openpgp.verify (#1275)
If `expectSigned` is set:
- `openpgp.decrypt` throws immediately if public keys or signatures are
  missing, or if the signatures are invalid and streaming is not used.
- `openpgp.verify` throws immediately if signatures are missing, or if the
  signatures are invalid and streaming is not used.
- If the signatures are invalid and streaming is used, reading the returned
  data stream will eventually throw.
2021-03-31 14:24:29 +02:00
will Farrell
5016cd5677
Fix streaming verification example in README (#1269) 2021-03-29 15:46:02 +02:00
Daniel Huigens
5299561aa3 Clean up async function JSDocs 2021-03-28 16:07:56 +02:00
Daniel Huigens
e3cfa4f9dd Revert "Don't mark async function as returning a Promise explicitly"
This reverts commit 9e85f75519dbb65c391bee08ee20b9e5a8284733.

It made VS Code / TypeScript complain about unnecessary `await`s.
2021-03-28 15:39:19 +02:00
Kevin Moutet
b8c07d6343
Fix createMessage return type in type definitions (#1276) 2021-03-27 22:22:33 +01:00
Daniel Huigens
eb496d2018 CI: Test type definitions
Also, fix a typo in the typings.
2021-03-27 11:35:02 +01:00
Daniel Huigens
e1fc91958c Disallow passing streams to readKey[s], readSignature and readCleartextMessage 2021-03-26 10:56:02 +01:00
Daniel Huigens
e7594f7d6a Remove unused util functions 2021-03-26 10:56:02 +01:00
Daniel Huigens
e599cee6c8 Remove top-level streaming options
Only return a stream if a stream was passed.
2021-03-26 10:56:02 +01:00
Daniel Huigens
91bd9e2c15 Replace Message.fromText and Message.fromBinary with createMessage
Also, replace CleartextMessage.fromText with createCleartextMessage.
2021-03-26 10:56:02 +01:00
Daniel Huigens
18ec54bf4b Fetch Streams ponyfill on demand in lightweight build 2021-03-26 10:56:02 +01:00
Daniel Huigens
940ebba54f Speed up Node.js tests 2021-03-25 19:23:58 +01:00
Daniel Huigens
97e9cdefe9 Remove unnecessary Buffer.from calls 2021-03-25 19:23:58 +01:00
Daniel Huigens
06aef92752 Remove internal streaming parameters 2021-03-25 19:23:58 +01:00
Daniel Huigens
ff8d274b4d Use ArrayStreams 2021-03-25 18:57:29 +01:00
larabr
6cff19c44a
Use consistent name casing (#1268)
- Use PascalCase for classes, with uppercase acronyms.
- Use camelCase for function and variables. First word/acronym is always
  lowercase, otherwise acronyms are uppercase.

Also, make the packet classes' `tag` properties `static`.
2021-03-25 19:56:59 +01:00
larabr
8a57246ec4
Add config.rejectPublicKeyAlgorithms (#1264)
- Add `config.rejectPublicKeyAlgorithms` to disallow using the given algorithms
  to verify, sign or encrypt new messages or third-party certifications.

- Consider `config.minRsaBits` when signing, verifying and encrypting messages
  and third-party certifications, not just on key generation.

- When verifying a message, if the verification key is not found (i.e. not
  provided or too weak), the corresponding `signature` will have
  `signature.valid=false` (used to be `signature.valid=null`).
  `signature.error` will detail whether the key is missing/too weak/etc.

Generating and verifying key certification signatures is still permitted in all cases.
2021-03-25 15:08:49 +01:00
larabr
3e808c1578
Drop support for verification of detached cleartext signatures (#1265)
(Also, use turnstyle to avoid CI browserstack tasks running in parallel.)
2021-03-18 17:17:39 +01:00
Kevin Moutet
eba791e11e
Add key.write() and update type definitions (#1267)
Also, mark key.keyPacket, message.packets and signature.packets private.
2021-03-16 13:45:17 +01:00
larabr
43fb58404d
Simplify algorithm preference selection and normalize config names (#1262)
- Rename `config.compression` to `config.preferredCompressionAlgorithm`
- Rename `config.encryptionCipher` to `config.preferredSymmetricAlgorithm`
- Rename `config.preferHashAlgorithm` to `config.preferredHashAlgorithm`
- Rename `config.aeadMode` to `config.preferredAeadAlgorithm`
- When encrypting to public keys, the compression/aead/symmetric algorithm is selected by:
  - taking the preferred algorithm specified in config, if it is supported by all recipients
  - otherwise, taking the "MUST implement" algorithm specified by rfc4880bis
- When encrypting to passphrases only (no public keys), the preferred algorithms from `config` are always used
- EdDSA signing with a hash algorithm weaker than sha256 is explicitly disallowed (https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2)
2021-03-10 18:06:03 +01:00
Daniel Huigens
4379d1856e 5.0.0-1 2021-03-03 20:28:16 +01:00
Daniel Huigens
b9134ed161
Fix unhandled promise rejection when stream-decrypting non-MDC messages (#1260)
Also, add some tests.
2021-03-03 19:38:58 +01:00
larabr
6e2a787ff8
Rename config.ignoreMdcError, drop config.integrityProtect and allow V4 keys to be AEAD-encrypted (#1261)
* Rename `config.ignoreMdcError` to `config.allowUnauthenticatedMessages`

* Do not support creating sym. enc. messages without integrity protection

* Use `config.aeadProtect` to determine SKESK encryption mode
2021-03-03 18:05:40 +01:00
larabr
f41412a5a2
Check critical notations during signature verification instead of parsing (#1259) 2021-03-03 18:03:45 +01:00
Daniel Huigens
30ddc3b90a Remove util from TypeScript definitions 2021-03-01 18:27:30 +01:00
Daniel Huigens
3f494ca797 Remove config.nodeStore 2021-03-01 12:02:39 +01:00
Daniel Huigens
4a8fffdfdf Remove KeyRing class
Keyring handling and storage should be handled in the application, as
localStorage may not meet the durability requirements of the
application, for example.
2021-03-01 11:58:10 +01:00
Daniel Huigens
8e5fe1da4f Remove config.keyserver 2021-03-01 11:43:13 +01:00
Daniel Huigens
7203e6afb6 Move WKD client to openpgpjs/wkd-client 2021-03-01 01:02:16 +01:00
Daniel Huigens
43f0724aeb Move HKP client to openpgpjs/hkp-client 2021-02-28 22:59:16 +01:00
Daniel Huigens
fa3c36fc87 Remove unused devDependencies 2021-02-28 21:58:30 +01:00
Daniel Huigens
e959602a94 Switch packages installed from git to @openpgp scope 2021-02-28 21:45:21 +01:00
Daniel Huigens
9bb65bd1c3 Update web-stream-tools 2021-02-28 21:25:58 +01:00
Daniel Huigens
9e85f75519 Don't mark async function as returning a Promise explicitly
It seems redundant.
2021-02-28 01:47:48 +01:00
Daniel Huigens
2ba04d9f0a Document parameters of Message.fromText/fromBinary 2021-02-28 01:47:48 +01:00
Daniel Huigens
174086a011 Default to empty filename 2021-02-28 01:47:48 +01:00
Daniel Huigens
21e3ba4653 Clean up JSDocs 2021-02-28 00:32:02 +01:00
Daniel Huigens
e2eadd09e4 Fix documentation of top-level function parameters 2021-02-27 23:37:41 +01:00
Daniel Huigens
a50cb9c6b7 Don't include date in documentation
To reduce diffs for each release.
2021-02-27 22:29:08 +01:00
Daniel Huigens
365a5efb63 5.0.0-0 2021-02-27 01:25:52 +01:00
Daniel Huigens
ab419179bc Remove TextEncoder/TextDecoder polyfills
Also, drop support for Node.js 10.
2021-02-27 01:22:13 +01:00
Daniel Huigens
3a42b45ab7 Remove unused config/localStorage module 2021-02-27 01:22:13 +01:00
Daniel Huigens
636c7cf529 Update documentation 2021-02-27 01:22:13 +01:00
larabr
7f37a8aaca
Add config parameter to top-level functions (#1241)
Refactor functions to take the configuration as a parameter.

This allows setting a config option for a single function call, whereas
setting `openpgp.config` could lead to concurrency-related issues when
multiple async function calls are made at the same time.

`openpgp.config` is used as default for unset config values in top-level
functions.
`openpgp.config` is used as default config object in low-level functions
(i.e., when calling a low-level function, it may be required to pass
`{ ...openpgp.config, modifiedConfig: modifiedValue }`).

Also,

- remove `config.rsaBlinding`: blinding is now always applied to RSA decryption
- remove `config.debug`: debugging mode can be enabled by setting
  `process.env.NODE_ENV = 'development'`
- remove `config.useNative`: native crypto is always used when available
2021-02-26 20:04:54 +01:00
larabr
15ee659c9c
Exit with error on unhandled rejections in Node tests (#1251) 2021-02-26 12:46:41 +01:00
Ali Cherry
2000388a80
Return subkey binding signature in SubKey#verify (#1250)
Also, update TypeScript definitions.
2021-02-25 12:58:54 +01:00
Daniel Huigens
ca248ba1a8 CI: Bump browser test timeout 2021-02-24 23:00:25 +01:00
larabr
95dd81381f
CI: Update browser targets (#1249) 2021-02-24 18:15:57 +01:00
Daniel Huigens
e1307b88d0
Consolidate read* functions (#1236)
Make all `read*` functions accept an options object, so that we can add config
options to them later (for #1166). This is necessary so that we can remove the
global `openpgp.config`, which doesn't work that well when importing
individual functions.

Furthermore, merge `readMessage` and `readArmoredMessage` into one function,
et cetera.
2021-02-17 20:36:33 +01:00
Ali Cherry
9ae0aae7a2
Add options to select encryption/signing key IDs (#1238) 2021-02-17 20:06:31 +01:00
Daniel Huigens
b6edfe646b Lint all tests (#1235) 2021-02-12 23:00:22 +01:00
Daniel Huigens
8f8517702e Remove Travis badge 2021-02-12 21:29:24 +01:00
Daniel Huigens
4bff80bc9c Switch to karma-mocha-reporter 2021-02-12 21:13:39 +01:00
Daniel Huigens
ce983e5a2d Switch from Travis to GitHub Workflows (#1234) 2021-02-12 21:13:19 +01:00
Daniel Huigens
01be7b7ec1
CI: Switch to karma for browser tests (#1233)
This should fix the false positives (failures to detect errors).
2021-02-12 13:29:04 +01:00
larabr
051f5ec8cf
BigInteger: throw if modular inverse doesn't exist (#1228) 2021-02-10 14:23:59 +01:00
larabr
ca092c7cd0 Speed up decryptKey and encryptKey (#1192)
Change `openpgp.decryptKey` and `openpgp.encryptKey` to avoid deep cloning the
original key.
2021-02-09 19:25:20 +01:00
larabr
66c06dab3e Check if any (sub)key is decrypted in Key.prototype.isDecrypted (#1182)
`key.isDecrypted()` now returns true if either the primary key or any subkey
is decrypted.

Additionally, implement `SecretKeyPacket.prototype.makeDummy` for encrypted
keys.
2021-02-09 19:25:20 +01:00
larabr
c23ed58387 Require User IDs to be objects; refactor UserIDPacket (#1187)
- `openpgp.generateKey` now expects `userIds` in object format
  (strings are no longer supported)
- Remove `util.parseUserId` and `util.formatUserId`
- Replace `UserIDPacket#format` with `UserIDPacket.fromObject`
2021-02-09 19:25:20 +01:00
larabr
724775816f Add explicit key type parameter in openpgp.generateKey (#1179)
- Changes `openpgp.generateKey` to accept an explicit `type` parameter,
  instead of inferring its value from the `curve` or `rsaBits` params
- Introduces `config.minRsaBits` to set minimum key size of RSA key generation
2021-02-09 19:25:20 +01:00
larabr
92887a0948 Revert to disabling AEAD encryption by default (#1190) 2021-02-09 19:25:20 +01:00
larabr
801430f969 Revert to generating v4 keys by default (#1189) 2021-02-09 19:25:20 +01:00
larabr
2ee36c2984 Drop inconsistent boolean returns and fix type definitions (#1191)
- Remove the boolean return value of various internal functions that throw on
  error (the returned value was unused in most cases)
- Update and fix type definitions
2021-02-09 19:25:20 +01:00
larabr
89f738da45 Fix EOL in streaming tests 2021-02-09 19:25:20 +01:00
larabr
286d991265 Fix parsing of short P-521 keys and EdDSA, RSA signatures (#1185)
Also, strip leading zeros when serializing MPIs, as per the spec.
2021-02-09 19:25:20 +01:00
larabr
c34dede6de Use \n instead of \r\n for EOL when armoring (#1183) 2021-02-09 19:25:20 +01:00
larabr
4efeac3ad1 Unexport low-level key functions (#1188) 2021-02-09 19:25:20 +01:00
Tom J
c5aa647e31 Add TypeScript definitions (#1186) 2021-02-09 19:25:20 +01:00
Dan Ristea
fe51f97b79 Re-enable linting in CI (#1160) 2021-02-09 19:25:20 +01:00
Daniel Huigens
4c15724caf Appease linter 2021-02-09 19:25:20 +01:00
Daniel Huigens
c2146ce165 Fix CI for older environments 2021-02-09 19:25:20 +01:00
Daniel Huigens
1f1ffedaf4 [v5] Update asmcrypto.js; fix CI (#1178) 2021-02-09 19:25:20 +01:00
Daniel Huigens
2382482090 [v5] Unexport openpgp.util, openpgp.crypto, and low-level types (#1175) 2021-02-09 19:25:20 +01:00
larabr
479d826533 Remove armor comment and version by default (#1170) 2021-02-09 19:25:20 +01:00
Marco
ad7d654f2b Fixed description of generateSessionKey (#1165) 2021-02-09 19:25:20 +01:00
Daniel Huigens
6df714a708 Add openpgp/lightweight to npm build 2021-02-09 19:25:20 +01:00
Daniel Huigens
86238e714e Remove unused functions in tests
These functions are unused since e83bc4b4.
2021-02-09 19:25:20 +01:00
Dan Ristea
331a0c27a9 Store named signature parameters (#1158)
Also, remove the now-unnecessary MPI type.
2021-02-09 19:25:20 +01:00
Dan Ristea
d5dd247b2c Store named session key parameters (#1157)
Change session key parameter handling to mirror key parameters.
Parameters are stored as an object rather than an array. MPIs are
always stored as Uint8Arrays.
2021-02-09 19:25:20 +01:00
Dan Ristea
400ae63c5e Fix minor JSDoc and style issues (#1156) 2021-02-09 19:25:20 +01:00
Daniel Huigens
a620fc0276 Don't use unexported low-level functions in tests 2021-02-09 19:25:20 +01:00
Daniel Huigens
b3e08fdc26 Don't export default objects / namespaces
Import individual functions, instead.
2021-02-09 19:25:20 +01:00
Daniel Huigens
f276e1ef51 Export key, message, signature, cleartext functions and classes directly
Instead of as modules.

Replace *.read with read*, *.readArmored with readArmored*, etc.
Replace cleartext.readArmored with readArmoredCleartextMessage.
Replace message.fromText with Message.fromText, etc.
2021-02-09 19:25:20 +01:00
larabr
3a75eadaa0 Store named key params in key objects (#1141)
- Store private and public params separately and by name in objects,
  instead of as an array

- Do not keep params in MPI form, but convert them to Uint8Arrays when
  generating/parsing the key

- Modify low-level crypto functions to always accept and return
  Uint8Arrays instead of BigIntegers

- Move PKCS1 padding to lower level functions
2021-02-09 19:25:20 +01:00
larabr
8854b097b4 Use native BigInt when available instead of bn.js (#1119)
In the lightweight build, lazily load bn.js only when necessary.

Also, use Uint8Arrays instead of strings in PKCS1 padding functions, and
check that the leading zero is present when decoding EME-PKCS1 padding.
2021-02-09 19:25:20 +01:00
Wiktor Kwapisiewicz
fe2949f16d Allow parsing keys without User IDs (#1146) 2021-02-09 19:25:20 +01:00
larabr
8d67af729a Use higher level functions in key validation tests (#1128)
Use `key.keyPacket.validate` instead of `crypto.publicKey.validateParams`, see
https://github.com/openpgpjs/openpgpjs/pull/1116#discussion_r447781386.

Also, `key.decrypt` now only throws on error, no other value is returned.

Also, fix typo (rebase error) that caused tests to fail in Safari for p521.
2021-02-09 19:25:20 +01:00
Dan Ristea
10aa1aa5cb JSdoc types & ESLint fixes (#1132) 2021-02-09 19:25:20 +01:00
larabr
f6ee6e959e Finish merging key validation 2021-02-09 19:25:20 +01:00
Dan Ristea
b9afd26912 Fix comments on symmetric- and public-key encrypted session keys (#1120) 2021-02-09 19:25:20 +01:00
Daniel Huigens
6a607c7567 Rename SymEncryptedAEADProtectedDataPacket to AEADEncryptedDataPacket 2021-02-09 19:25:20 +01:00
Daniel Huigens
17fc32ba51 Appease linter 2021-02-09 19:25:20 +01:00
Daniel Huigens
aea7aa953a Use ES6 classes 2021-02-09 19:25:20 +01:00
Daniel Huigens
fb3d23427d Allow dead code elimination 2021-02-09 19:25:20 +01:00
Daniel Huigens
c20b75252b Add --build-only parameter to filter build outputs
Also, don't generate test bundle by default, but provide
`npm run build-test` instead.
2021-02-09 19:25:20 +01:00
Daniel Huigens
6a3d04ade6 Only produce source maps for minified dist builds 2021-02-09 19:25:20 +01:00
Daniel Huigens
6516602d7b Add shortcut to import 'openpgp/lightweight' 2021-02-09 19:25:20 +01:00
Daniel Huigens
8457639004 CI: for lightweight build, only run tests tagged 'lightweight' 2021-02-09 19:25:20 +01:00
Daniel Huigens
f3b16386dc Use dynamic import in lightweight build
Instead of dynamically loading a <script> tag.

This also removes the non-module lightweight build.
2021-02-09 19:25:20 +01:00
Daniel Huigens
7dbd393071 Remove src and test directory from npm package 2021-02-09 19:25:20 +01:00
Daniel Huigens
f936abec9d Bump Browserstack test to iOS 12 2021-02-09 19:25:20 +01:00
Daniel Huigens
4edd85be69 Drop Node.js 8 support and Travis test
It should still work, but we can no longer test it
because rollup requires Node.js 10+.

Also, remove "allowed failures".
2021-02-09 19:25:20 +01:00
Daniel Huigens
4f77990859 Polyfill globalThis 2021-02-09 19:25:20 +01:00
Daniel Huigens
89923dad17 Remove bower.json 2021-02-09 19:25:20 +01:00
Daniel Huigens
175eac5670 Remove compat polyfills 2021-02-09 19:25:20 +01:00
Daniel Huigens
ed9a029fcf Replace release.sh with npm version scripts 2021-02-09 19:25:20 +01:00
Daniel Huigens
defa1283cb Link to source code on GitHub from documentation
Instead of including the entire source code in the documentation.
2021-02-09 19:25:20 +01:00
Daniel Huigens
0c5598a0fc Replace remaining grunt tasks with npm scripts 2021-02-09 19:25:20 +01:00
Daniel Huigens
cde282d4f1 Replace 'global' with 'globalThis' 2021-02-09 19:25:20 +01:00
Daniel Huigens
5b148089c3 Switch to ES8 build of asmcrypto.js 2021-02-09 19:25:20 +01:00
Daniel Huigens
0e33e641af Switch build system to rollup
Also, default to minimized builds.
2021-02-09 19:25:20 +01:00
Daniel Huigens
c48070def6 Remove default export 2021-02-09 19:25:20 +01:00
Daniel Huigens
bdad8e3eec Remove dist folder from GitHub 2021-02-09 19:25:20 +01:00
Daniel Huigens
064e813f3f Build OpenPGP.js on local npm install 2021-02-09 19:25:20 +01:00
Ilya Chesnokov
6e648b1cbc Rename enums to use camelCase (#1093) 2021-02-09 19:25:20 +01:00
Daniel Huigens
ad33660da8 Fix lightweight build and browserstack test (#1092) 2021-02-09 19:25:20 +01:00
Ilya Chesnokov
e16807505f Switch util function names to camelCase (#1091) 2021-02-09 19:25:20 +01:00
Ilya Chesnokov
d415bc2546 Rename config option names to camelCase (#1088) 2021-02-09 19:25:20 +01:00
Daniel Huigens
63b6d215e3 Allow key.validate() to pass if it has a GNU dummy primary key
A valid signing subkey is required, in this case.
2021-02-09 19:25:20 +01:00
larabr
8823603396 Remove worker (#1072) 2021-02-09 19:25:20 +01:00
larabr
85d0358d45 Remove 3DES and CAST5 from default preferred symmetric algorithms (#1068) 2021-02-09 19:25:20 +01:00
larabr
20950e5df5 Remove SHA-1 from default preferred hash algorithms (#1067)
Also, remove SHA-1 from the (unused) KDF params constructor defaults.
2021-02-09 19:25:20 +01:00
larabr
5ad19c8da8 Generate ECC keys by default (#1065)
Also, remove the deprecated numBits options of generateKey in favor of rsaBits.
2021-02-09 19:25:20 +01:00
larabr
4c93abb9f9 Use V5 keys by default (#1063) 2021-02-09 19:25:20 +01:00
larabr
a7640bce52 Use AEAD protection by default (#1062) 2021-02-09 19:25:20 +01:00
Daniel Huigens
ec720cc096 Remove browsers that always fail from Browserstack tests 2021-02-09 19:25:20 +01:00
Daniel Huigens
2bc24f354b Return only one key in key.read[Armored], add readAll[Armored] 2021-02-09 19:25:20 +01:00
Daniel Huigens
3817cca3c6 Throw on unarmored messages with garbage data appended 2021-02-09 19:25:20 +01:00
Daniel Huigens
76a8f11780 Don't mutate key in openpgp.encryptKey/decryptKey 2021-02-09 19:25:20 +01:00
Daniel Huigens
9394fec1f4 Throw in openpgp.initWorker if worker failed to load 2021-02-09 19:25:20 +01:00
Daniel Huigens
29f29f6c6e Unit tests: Fix autoscroll with skipped tests 2021-02-09 19:25:20 +01:00
Daniel Huigens
35c13212dd Remove unnecessary calls to convertStreams() 2021-02-09 19:25:20 +01:00
Daniel Huigens
ef7c38860b Don't unnecessarily return objects in top-level functions
openpgp.encrypt, sign, encryptSessionKey, encryptKey and decryptKey now
return their result directly without wrapping it in a "result" object.

Also, remove the `detached` and `returnSessionKey` options of
openpgp.encrypt.
2021-02-09 19:25:20 +01:00
Daniel Huigens
be7b174df4 Add openpgp.generateSessionKey 2021-02-09 19:25:20 +01:00
Daniel Huigens
a9a9a90ae2 Skip test for OpenPGP.js inside an application worker in old Edge
Old Edge doesn't support crypto.getRandomValues inside a Worker.
2021-02-09 19:25:20 +01:00
Daniel Huigens
3a84442b5f Don't use native streams in old Edge 2021-02-09 19:25:20 +01:00
Daniel Huigens
2fffc76060 Don't overwrite Web Streams Polyfill to globals
Instead, use the ponyfill that's now included in web-stream-tools.
Also, convert back to native ReadableStream when we used the ponyfill.
2021-02-09 19:25:20 +01:00
Daniel Huigens
430145a8b1 Update web-stream-tools
Fixes reading Node streams in some cases.
2021-02-09 19:25:20 +01:00
Daniel Huigens
37d30c5003 Return strings in Node streams where appropriate 2021-02-09 19:25:20 +01:00
Daniel Huigens
95eb43a3c2 Return data instead of message in encryptSessionKey
Add `armor=true/false` parameter to decide whether `data` is an armored
String or an unarmored Uint8Array.
2021-02-09 19:25:20 +01:00
Daniel Huigens
08d6b276e3 Return data as string in openpgp.verify by default
Add format='utf8'/'binary' param to openpgp.verify in order to be able
to return binary data instead.
2021-02-09 19:25:20 +01:00
Daniel Huigens
7225251af8 Return Uint8Array(Stream) instead of object when armor = false 2021-02-09 19:25:20 +01:00
Daniel Huigens
1f237e6a9c Release new version 2021-01-24 16:47:40 +01:00
larabr
38ec5314d4 Fix ElGamal param range and PKCS1 decoding (#1169)
* Fix ElGamal sampling range

* Stricter PKCS1 decoding
2021-01-20 14:09:52 +01:00
Daniel Huigens
d5373ef361 Update tweetnacl-js 2021-01-20 14:09:10 +01:00
Daniel Huigens
21f4ba46f8 Release new version 2020-12-07 20:31:43 +01:00
Yarmo Mackenbach
a4b56c944a
WKD: Fix "TypeError: fetch is not a function" in Node.js environment (#1181) 2020-11-17 10:03:25 +01:00
larabr
08fc7b32ca
Fix and test dummy key conversion (#1172)
Keys converted using makeDummy() were not serialised correctly as they were
treated as unencrypted keys.
2020-11-10 17:32:44 +01:00
Chen Longhao
929b016948
Fix documentation of the HKP keyId option (#1151) 2020-09-09 12:26:03 +02:00
Daniel Huigens
aa89893773 Release new version 2020-08-28 16:42:25 +02:00
larabr
2eab8a1ebc
Add config option to allow insecure decryption with RSA signing keys (#1148) 2020-08-28 16:09:56 +02:00
larabr
cc1bdcbae8
Allow decryption with revoked keys (#1135)
However, when decrypting session keys, check that the public key
algorithm matches that of the decryption key.
2020-08-18 15:49:27 +02:00
Wiktor Kwapisiewicz
2e26509723
Add test case for unknown binary notations (#1140) 2020-08-18 13:37:36 +02:00
Wiktor Kwapisiewicz
0712e8af2d
Support non-human-readable notation values (#983)
This change adds support for binary (non-human-readable) values in
signature notations through `rawNotations` property on signature objects.
Human-readable notations will additionally appear in `notations` object
where the value of the notation will be deserialized into a string.

Additionally the check for human-readable flag was modified to check the
existence of the flag instead of comparison with the whole value.
2020-08-18 11:07:58 +02:00
larabr
25bf080871
Add SecretKey.prototype.makeDummy (#1131) 2020-08-03 15:52:50 +02:00
larabr
e29de76dc1 Use correct algorithm in ECC validation tests 2020-07-23 19:21:34 +02:00
Daniel Huigens
34b0928cca Release new version 2020-07-21 15:21:20 +02:00
larabr
14f244a80f Fix decryption tests 2020-07-17 15:14:21 +02:00
Yarmo Mackenbach
de360e200c
Handle CORS errors during WKD lookup (#1125)
Also, throw an error instead of returning null when the server returned
an error status.
2020-07-17 14:22:54 +02:00
larabr
8783caa828 Fix key validation tests 2020-07-16 22:56:06 +02:00
Yarmo Mackenbach
5801169432
Refactor WKD lookup code (#1123)
* Replace chained then by await

* Improve fetch fallback flow
2020-07-15 15:12:55 +02:00
Daniel Huigens
20c468cbd7 Release new version 2020-07-14 18:22:46 +02:00
Daniel Huigens
3218f7b7f8 Don't zero-copy transfer buffers from the worker by default 2020-07-14 18:15:08 +02:00
Daniel Huigens
1c41c72520 Release new version 2020-07-13 20:24:55 +02:00
Yarmo Mackenbach
4af9b51915
Add support for advanced WKD lookup (#1115) 2020-07-13 20:08:30 +02:00
larabr
00c5f38689
Cipher-specific key validation (#1116)
Also, check binding signatures for decryption keys.

Also, do not always fallback on Web Crypto ECC errors.
2020-07-13 19:57:33 +02:00
cpupower
6988fdfee1
Fix stream-encrypting+signing a message using the Worker (#1112)
- Include fromStream property when cloning a Message
- Restore fromStream property in packetlistCloneToMessage
2020-06-25 12:53:27 +02:00
larabr
35b0012f2f
Pass around KDF params as object (#1104) 2020-06-03 14:16:54 +02:00
Matthew Shaylor
320efc2435
Fix keyId types in JSDoc comments (#1100) 2020-05-18 12:22:31 +02:00
Roman Zechmeister
1b91d428f0
Also create issuer fingerprint subpacket for v4 keys (#1097)
Do not limit creation of signatures with issuer fingerprint subpacket to v5 keys.
2020-05-11 21:45:04 +02:00
Daniel Huigens
2c6cbc4cb2 Release new version 2020-04-22 19:28:01 +02:00
Daniel Huigens
5d71ae8691 Fix normalizing \n after \r\n
Broken in c4a7455.
2020-04-22 19:09:50 +02:00
314 changed files with 157585 additions and 172617 deletions

View File

@ -1,14 +0,0 @@
---
engines:
duplication:
enabled: true
config:
languages:
- javascript
eslint:
enabled: true
fixme:
enabled: true
ratings:
paths:
- "lib/**/*"

View File

@ -1 +1,4 @@
src/compression
dist
test/lib/
test/typescript/
docs

142
.eslintrc.cjs Normal file
View File

@ -0,0 +1,142 @@
module.exports = {
'extends': [
'airbnb-base',
'airbnb-typescript/base'
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 11,
'sourceType': 'module',
'project': 'tsconfig.json'
},
'env': {
'browser': true,
'es6': true,
'node': true
},
'plugins': [
'@typescript-eslint',
'chai-friendly',
'import',
'unicorn'
],
'settings': {
'import/resolver': {
'typescript': {}
}
},
'globals': { // TODO are all these necessary?
'globalThis': true,
'console': true,
'Promise': true,
'importScripts': true,
'process': true,
'Event': true,
'describe': true,
'it': true,
'mocha': true,
'before': true,
'beforeEach': true,
'after': true,
'afterEach': true,
'escape': true,
'unescape': true,
'resolves': true,
'rejects': true,
'TransformStream': true,
'BigInt': true
},
'rules': {
'arrow-body-style': 'off',
'arrow-parens': ['error','as-needed'],
'class-methods-use-this': 'off',
'@typescript-eslint/comma-dangle': ['error', 'never'],
'@typescript-eslint/comma-spacing': 'off',
'consistent-return': 'off',
'default-case': 'off',
'@typescript-eslint/default-param-last': 'off',
'eol-last': ['error', 'always'],
'function-call-argument-newline': 'off',
'func-names': ['error', 'never'],
'function-paren-newline': 'off',
'global-require': 'off',
'key-spacing': 'off',
'keyword-spacing': 'error',
'max-classes-per-file': 'off',
'max-len': 'off',
'newline-per-chained-call': 'off',
'no-bitwise': 'off',
'no-continue': 'off',
'no-else-return': 'off',
'no-empty': ['error', { 'allowEmptyCatch': true }],
'no-multiple-empty-lines': ['error', { 'max': 2, 'maxEOF': 1, 'maxBOF':0 }],
'no-nested-ternary': 'off',
'no-param-reassign': 'off', // TODO get rid of this
'no-plusplus': 'off',
'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'],
'object-curly-newline': 'off',
'@typescript-eslint/no-shadow': 'off', // TODO get rid of this
'object-property-newline': [
'error',
{
'allowMultiplePropertiesPerLine': true
}
],
'object-shorthand': 'off',
'operator-assignment': 'off',
'operator-linebreak': [
'error',
'after'
],
'padded-blocks': 'off',
'prefer-arrow-callback': 'off',
'prefer-destructuring': 'off',
'prefer-rest-params': 'off', // TODO get rid of this
'prefer-spread': 'off', // TODO get rid of this
'prefer-template': 'off',
'quote-props': 'off',
'quotes': ['error', 'single', { 'avoidEscape': true }],
'@typescript-eslint/space-before-function-paren': ['error', { 'anonymous': 'ignore', 'named': 'never', 'asyncArrow': 'always' }],
'spaced-comment': 'off',
'indent': 'off',
'@typescript-eslint/indent': ['error', 2, { 'SwitchCase': 1 }],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
// eslint-plugin-import rules:
'import/named': 'error',
'import/extensions': 'off', // temporary: we use them in tests (ESM compliant), but not in the lib (to limit diff)
'import/first': 'off',
'import/no-extraneous-dependencies': ['error', { 'devDependencies': true, 'optionalDependencies': false, 'peerDependencies': false }],
'import/no-unassigned-import': 'error',
'import/no-unresolved': 'error',
'import/prefer-default-export': 'off',
// Custom silencers:
'no-multi-assign': 'off',
'no-underscore-dangle': 'off',
'no-await-in-loop': 'off',
'camelcase': 'off', // snake_case used in tests, need to fix separately
'@typescript-eslint/naming-convention': 'off', // supersedes 'camelcase' rule
'@typescript-eslint/lines-between-class-members': 'off',
// Custom errors:
'@typescript-eslint/no-use-before-define': ['error', { 'functions': false, 'classes': true, 'variables': false, 'allowNamedExports': true }],
'no-constant-condition': [2, { 'checkLoops': false }],
'new-cap': [2, { 'properties': false, 'capIsNewExceptionPattern': 'EAX|OCB|GCM|CMAC|CBC|OMAC|CTR', 'newIsCapExceptionPattern': 'type|hash*' }],
'max-lines': [2, { 'max': 620, 'skipBlankLines': true, 'skipComments': true }],
'@typescript-eslint/no-unused-expressions': 0,
'chai-friendly/no-unused-expressions': [2, { 'allowShortCircuit': true }],
'unicorn/switch-case-braces': ['error', 'avoid'],
// Custom warnings:
'no-console': 1
}
};

View File

@ -1,350 +0,0 @@
module.exports = {
"extends": "airbnb-base",
"parserOptions": { "sourceType": "module" },
"env": {
"browser": true,
"es6": true,
"node": true
},
"plugins": [
"chai-friendly"
],
"globals": { // TODO are all these necessary?
"console": true,
"Promise": true,
"importScripts": true,
"process": true,
"Event": true,
"describe": true,
"it": true,
"sinon": true,
"mocha": true,
"before": true,
"beforeEach": true,
"after": true,
"afterEach": true,
"escape": true,
"unescape": true,
"postMessage": true,
"resolves": true,
"rejects": true,
"TransformStream": true
},
"rules": {
// Auto generated rules:
"accessor-pairs": "error",
"array-bracket-newline": "error",
"array-bracket-spacing": [
"error",
"never"
],
"array-callback-return": "error",
"array-element-newline": "off",
"arrow-body-style": "off",
"arrow-parens": [
"error",
"as-needed"
],
"arrow-spacing": [
"error",
{
"after": true,
"before": true
}
],
"block-spacing": [
"error",
"always"
],
"brace-style": "off",
"callback-return": "error",
"camelcase": [
"error",
{
"properties": "never"
}
],
"capitalized-comments": "off",
"class-methods-use-this": "error",
"comma-dangle": [ "error", "never" ],
"comma-spacing": "off",
"comma-style": [
"error",
"last"
],
"complexity": "off",
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": "off",
"consistent-this": "error",
"curly": "error",
"default-case": "off",
"dot-location": "error",
"dot-notation": [
"error",
{
"allowKeywords": true
}
],
"eol-last": ["error", "always"],
"eqeqeq": "error",
"for-direction": "error",
"func-call-spacing": "error",
"func-name-matching": "error",
"func-names": [
"error",
"never"
],
"func-style": "off",
"function-paren-newline": "off",
"generator-star-spacing": "error",
"getter-return": "error",
"global-require": "off",
"guard-for-in": "off",
"handle-callback-err": "error",
"id-blacklist": "error",
"id-length": "off",
"id-match": "error",
"implicit-arrow-linebreak": [
"error",
"beside"
],
"init-declarations": "off",
"jsx-quotes": "error",
"key-spacing": "off",
"keyword-spacing": "error",
"line-comment-position": "off",
"linebreak-style": [
"error",
"unix"
],
"lines-around-comment": "off",
"lines-around-directive": "error",
"lines-between-class-members": "error",
"max-depth": "off",
"max-len": "off",
"max-lines": "off",
"max-nested-callbacks": "error",
"max-params": "off",
"max-statements": "off",
"max-statements-per-line": "off",
"multiline-comment-style": "off",
"multiline-ternary": "off",
"new-parens": "error",
"newline-after-var": "off",
"newline-before-return": "off",
"newline-per-chained-call": "off",
"no-alert": "error",
"no-array-constructor": "error",
"no-bitwise": "off",
"no-buffer-constructor": "error",
"no-caller": "error",
"no-catch-shadow": "error",
"no-confusing-arrow": "error",
"no-continue": "off",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "off",
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
],
"no-empty-function": "off",
"no-eq-null": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-extra-parens": "off",
"no-floating-decimal": "error",
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-inline-comments": "off",
"no-inner-declarations": [
"error",
"functions"
],
"no-invalid-this": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-magic-numbers": "off",
"no-mixed-operators": "off",
"no-mixed-requires": "error",
"no-multi-assign": "error",
"no-multi-spaces": [
"error",
{
"ignoreEOLComments": true
}
],
"no-multi-str": "error",
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF":0 }],
"no-native-reassign": "error",
"no-negated-condition": "off",
"no-negated-in-lhs": "error",
"no-nested-ternary": "off",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-param-reassign": "off",
"no-path-concat": "error",
"no-plusplus": "off",
"no-process-env": "error",
"no-process-exit": "error",
"no-proto": "error",
"no-prototype-builtins": "off",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-modules": "error",
"no-restricted-properties": "error",
"no-restricted-syntax": "error",
"no-return-assign": "error",
"no-return-await": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-shadow": "off",
"no-shadow-restricted-names": "error",
"no-spaced-func": "error",
"no-sync": "error",
"no-tabs": "error",
"no-template-curly-in-string": "error",
"no-ternary": "off",
"no-throw-literal": "error",
"no-undef-init": "error",
"no-undefined": "off",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": [
"error",
{
"defaultAssignment": true
}
],
"no-use-before-define": "off",
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-void": "error",
"no-warning-comments": "off",
"no-whitespace-before-property": "error",
"no-with": "error",
"nonblock-statement-body-position": "error",
"object-curly-newline": "off",
"object-curly-spacing": "error",
"object-property-newline": [
"error",
{
"allowMultiplePropertiesPerLine": true
}
],
"object-shorthand": "off",
"one-var-declaration-per-line": [
"error",
"initializations"
],
"operator-assignment": "off",
"operator-linebreak": [
"error",
"after"
],
"padded-blocks": "off",
"padding-line-between-statements": "error",
"prefer-arrow-callback": "off",
"prefer-destructuring": "off",
"prefer-numeric-literals": "error",
"prefer-promise-reject-errors": "error",
"prefer-reflect": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
"prefer-template": "off",
"quote-props": "off",
"quotes": "off",
"require-await": "error",
"require-jsdoc": "off",
"semi-spacing": [
"error",
{
"after": true,
"before": false
}
],
"semi-style": [
"error",
"last"
],
"sort-imports": "off",
"sort-keys": "off",
"sort-vars": "off",
"space-before-blocks": "off",
"space-before-function-paren": "off",
"space-in-parens": [
"error",
"never"
],
"space-infix-ops": "error",
"space-unary-ops": "error",
"spaced-comment": "off",
"strict": "off",
"switch-colon-spacing": "error",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": [
"error",
"never"
],
"wrap-iife": "error",
"wrap-regex": "off",
"yield-star-spacing": "error",
"yoda": [
"error",
"never"
],
"indent": [ "error", 2, { "SwitchCase": 1 } ],
"no-buffer-constructor": "error",
"no-lonely-if": "error",
"no-unused-vars": "error",
// eslint-plugin-import rules:
"import/extensions": "never",
"import/no-extraneous-dependencies": ["error", {"devDependencies": true, "optionalDependencies": false, "peerDependencies": false}],
// Custom silencers:
"camelcase": 0,
"require-await": 0,
"no-multi-assign": 0,
"no-underscore-dangle": 0,
"no-await-in-loop": 0,
// Custom errors:
"no-undef": 2,
"no-trailing-spaces": 2,
"no-mixed-operators": [ 2, {"groups": [["&", "|", "^", "~", "<<", ">>", ">>>"], ["&&", "||"]]}],
"no-use-before-define": [ 2, { "functions": false, "classes": true, "variables": false }],
"no-constant-condition": [ 2, { "checkLoops": false } ],
"new-cap": [ 2, { "properties": false, "capIsNewExceptionPattern": "CMAC|CBC|OMAC|CTR", "newIsCapExceptionPattern": "type|hash*"}],
"max-lines": [ 2, { "max": 550, "skipBlankLines": true, "skipComments": true } ],
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": [ 2, { "allowShortCircuit": true } ],
// Custom warnings:
"no-console": 1,
}
};

10
.github/ISSUE_TEMPLATE/BUG_REPORT.md vendored Normal file
View File

@ -0,0 +1,10 @@
---
name: Bug report
about: Report an issue with this library
---
<!-- Please search existing issues and discussions to avoid creating duplicates. -->
- OpenPGP.js version:
- Affected platform (Browser or Node.js version):
<!-- Describe the bug you have encountered -->

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Feature request
url: https://github.com/openpgpjs/openpgpjs/discussions/categories/ideas
about: Suggest an idea for this project
- name: Question
url: https://github.com/openpgpjs/openpgpjs/discussions/categories/q-a
about: Please ask any questions here

33
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,33 @@
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"
allow:
- dependency-name: "playwright"
versioning-strategy: increase
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
allow:
- dependency-name: "@noble*"
- dependency-name: "fflate"
versioning-strategy: increase
groups:
# Any packages matching the pattern @noble* where the highest resolvable
# version is minor or patch will be grouped together.
# Grouping rules apply to version updates only.
noble:
applies-to: version-updates
patterns:
- "@noble*"
update-types:
- "minor"
- "patch"

39
.github/test-suite/config.json.template vendored Normal file
View File

@ -0,0 +1,39 @@
{
"drivers": [
{
"id": "sop-openpgpjs-branch",
"path": "__SOP_OPENPGPJS__",
"env": {
"OPENPGPJS_PATH": "__OPENPGPJS_BRANCH__"
}
},
{
"id": "sop-openpgpjs-main",
"path": "__SOP_OPENPGPJS__",
"env": {
"OPENPGPJS_PATH": "__OPENPGPJS_MAIN__",
"DISABLE_PROFILES": "true"
}
},
{
"path": "__SQOP__"
},
{
"path": "__GPGME_SOP__"
},
{
"id": "gosop-v2",
"path": "__GOSOP_V2__"
},
{
"path": "__RNP_SOP__"
},
{
"path": "__RSOP__"
}
],
"rlimits": {
"DATA": 1073741824
}
}

14
.github/test-suite/prepare_config.sh vendored Executable file
View File

@ -0,0 +1,14 @@
CONFIG_TEMPLATE=$1
CONFIG_OUTPUT=$2
OPENPGPJS_BRANCH=$3
OPENPGPJS_MAIN=$4
cat $CONFIG_TEMPLATE \
| sed "s@__OPENPGPJS_BRANCH__@${OPENPGPJS_BRANCH}@g" \
| sed "s@__OPENPGPJS_MAIN__@${OPENPGPJS_MAIN}@g" \
| sed "s@__SQOP__@${SQOP}@g" \
| sed "s@__GPGME_SOP__@${GPGME_SOP}@g" \
| sed "s@__GOSOP_V2__@${GOSOP_V2}@g" \
| sed "s@__SOP_OPENPGPJS__@${SOP_OPENPGPJS_V2}@g" \
| sed "s@__RNP_SOP__@${RNP_SOP}@g" \
| sed "s@__RSOP__@${RSOP}@g" \
> $CONFIG_OUTPUT

67
.github/workflows/benchmark.yml vendored Normal file
View File

@ -0,0 +1,67 @@
name: Performance Regression Test
on:
pull_request:
branches: [main]
jobs:
benchmark:
name: Time and memory usage benchmark
runs-on: ubuntu-latest
steps:
# check out pull request branch
- uses: actions/checkout@v4
with:
path: pr
# check out main branch (to compare performance)
- uses: actions/checkout@v4
with:
ref: main
path: main
- uses: actions/setup-node@v4
with:
node-version: '>=20.6.0'
- name: Run pull request time benchmark
run: cd pr && npm install && npm run --silent benchmark-time > benchmarks.txt && cat benchmarks.txt
- name: Run pull request memory usage benchmark
run: cd pr && npm run --silent benchmark-memory-usage > memory_usage.txt && cat memory_usage.txt
- name: Run time benchmark on main (baseline)
run: cd main && npm install && npm run --silent benchmark-time > benchmarks.txt && cat benchmarks.txt
- name: Run memory usage benchmark on main (baseline)
run: cd main && npm run --silent benchmark-memory-usage > memory_usage.txt && cat memory_usage.txt
- name: Compare time benchmark result
uses: openpgpjs/github-action-pull-request-benchmark@v1
with:
tool: 'benchmarkjs'
name: 'Time benchmark'
pr-benchmark-file-path: pr/benchmarks.txt
base-benchmark-file-path: main/benchmarks.txt
github-token: ${{ secrets.GITHUB_TOKEN }}
# trigger alert comment if 1.3 times slower
alert-threshold: '130%'
comment-on-alert: false
# fail workdlow if 1.5 times slower
fail-threshold: '150%'
fail-on-alert: true
file-to-annotate: ${{ github.workspace }}/test/benchmarks/time.js
- name: Compare memory usage benchmark result
uses: openpgpjs/github-action-pull-request-benchmark@v1
with:
tool: 'raw'
name: 'Memory usage benchmark'
pr-benchmark-file-path: pr/memory_usage.txt
base-benchmark-file-path: main/memory_usage.txt
github-token: ${{ secrets.GITHUB_TOKEN }}
alert-threshold: '102%'
comment-on-alert: false
fail-threshold: '110%'
fail-on-alert: true
file-to-annotate: ${{ github.workspace }}/test/benchmarks/memory_usage.js

19
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Documentation
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
name: JSDoc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci --ignore-scripts
- run: npm run docs

87
.github/workflows/sop-test-suite.yml vendored Normal file
View File

@ -0,0 +1,87 @@
name: SOP interoperability test suite
on:
pull_request:
branches: [ main ]
jobs:
test-suite:
name: Run interoperability test suite
runs-on: ubuntu-latest
container:
image: ghcr.io/protonmail/openpgp-interop-test-docker:v1.1.12
credentials:
username: ${{ github.actor }}
password: ${{ secrets.github_token }}
steps:
# check out repo for scripts
- uses: actions/checkout@v4
# check out pull request branch
- name: Checkout openpgpjs-branch
uses: actions/checkout@v4
with:
path: openpgpjs-branch
- name: Install openpgpjs-branch
run: cd openpgpjs-branch && npm install
- name: Print openpgpjs-branch version
run: $SOP_OPENPGPJS_V2 version --extended
env:
OPENPGPJS_PATH: ${{ github.workspace }}/openpgpjs-branch
# check out main branch
- name: Checkout openpgpjs-main
uses: actions/checkout@v4
with:
ref: main
path: openpgpjs-main
- name: Install openpgpjs-main
run: cd openpgpjs-main && npm install
- name: Print openpgpjs-main version
run: $SOP_OPENPGPJS_V2 version --extended
env:
OPENPGPJS_PATH: ${{ github.workspace }}/openpgpjs-main
# Run test suite
- name: Prepare test configuration
run: ./.github/test-suite/prepare_config.sh $CONFIG_TEMPLATE $CONFIG_OUTPUT $GITHUB_WORKSPACE/openpgpjs-branch $GITHUB_WORKSPACE/openpgpjs-main
env:
CONFIG_TEMPLATE: .github/test-suite/config.json.template
CONFIG_OUTPUT: .github/test-suite/config.json
- name: Display configuration
run: cat .github/test-suite/config.json
- name: Run interoperability test suite
run: cd $TEST_SUITE_DIR && $TEST_SUITE --config $GITHUB_WORKSPACE/$CONFIG --json-out $GITHUB_WORKSPACE/$RESULTS_JSON --html-out $GITHUB_WORKSPACE/$RESULTS_HTML
env:
CONFIG: .github/test-suite/config.json
RESULTS_JSON: .github/test-suite/test-suite-results.json
RESULTS_HTML: .github/test-suite/test-suite-results.html
# Upload results
- name: Upload test results json artifact
uses: actions/upload-artifact@v4
with:
name: test-suite-results.json
path: .github/test-suite/test-suite-results.json
- name: Upload test results html artifact
uses: actions/upload-artifact@v4
with:
name: test-suite-results.html
path: .github/test-suite/test-suite-results.html
compare-with-main:
name: Compare with main
runs-on: ubuntu-latest
needs: test-suite
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download test results json artifact
id: download-test-results
uses: actions/download-artifact@v4
with:
name: test-suite-results.json
- name: Compare with baseline
uses: ProtonMail/openpgp-interop-test-analyzer@v2
with:
results: ${{ steps.download-test-results.outputs.download-path }}/test-suite-results.json
output: baseline-comparison.json
baseline: sop-openpgpjs-main
target: sop-openpgpjs-branch

206
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,206 @@
name: Code Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build: # cache both dist and tests (non-lightweight only), based on commit hash
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Check for cached folders
id: cache-full
uses: actions/cache@v4
with:
path: |
dist
test/lib
key: cache-${{ github.sha }}
- name: Build dist and tests
if: steps.cache-full.outputs.cache-hit != 'true'
run: |
npm ci
npm run build-test
node:
strategy:
fail-fast: false # if tests for one version fail, continue with the rest
matrix:
node-version: [18.x, 20.x, 22.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
name: Node ${{ matrix.node-version }}
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci --ignore-scripts # for mocha
- name: Retrieve cached folders
uses: actions/cache/restore@v4
id: cache-full
with:
# test/lib is not needed, but the path must be specified fully for a cache-hit
path: |
dist
test/lib
key: cache-${{ github.sha }}
# ignore cache miss, since it was taken care of the `build` step and it should never occur here
- run: npm test
test-browsers-latest:
name: Browsers (latest)
needs: build
strategy:
fail-fast: false # if tests for one version fail, continue with the rest
matrix:
# run on all main platforms to test platform-specific code, if present
# (e.g. webkit's WebCrypto API implementation is different in macOS vs Linux)
# TODO: windows-latest fails to fetch resources from the wtr server; investigate if the problem is with path declaration or permissions
runner: ['ubuntu-latest', 'macos-latest']
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Retrieve cached built folders
uses: actions/cache/restore@v4
id: cache-full
with:
path: |
dist
test/lib
key: cache-${{ github.sha }}
- name: Install dependencies
# cannot use `--ignore-scripts` since playwright seems to use it to set ENV vars
run: |
npm pkg delete scripts.prepare
npm ci
- name: Get Playwright version and cache location
id: playwright-version
run: |
PLAYWRIGHT_VERSION=$(npm ls playwright --depth=0 | grep playwright | sed 's/.*@//')
echo "version=$PLAYWRIGHT_VERSION" >> $GITHUB_OUTPUT
PLAYWRIGHT_CACHE=${{ fromJSON('{"ubuntu-latest": "~/.cache/ms-playwright", "macos-latest": "~/Library/Caches/ms-playwright"}')[matrix.runner] }}
echo "playwright_cache=$PLAYWRIGHT_CACHE" >> $GITHUB_OUTPUT
- name: Check for cached browsers
id: cache-playwright-browsers
uses: actions/cache@v4
with:
path: ${{ steps.playwright-version.outputs.playwright_cache }}
key: playwright-browsers-${{ matrix.runner }}-${{ steps.playwright-version.outputs.version }}
- name: Install browsers
if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
run: |
npx playwright install --with-deps chromium
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
run: npm run test-browser:ci -- --static-logging
- name: Run browser tests (lightweight) # overwrite test/lib
run: |
npm run build-test --lightweight
npm run test-browser:ci -- --static-logging
test-browsers-compatibility:
name: Browsers (older, on Browserstack)
runs-on: ubuntu-latest
needs: test-browsers-latest
env: # credentials need hardcoding for now since Github secrets aren't accessible on pull requests from forks
BROWSERSTACK_USERNAME: openpgpjs_PlY4Uq885CQ
BROWSERSTACK_ACCESS_KEY: VjgBVRMxNVBj7SjJFiau
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Generate self-signed HTTPS certificates for web-test-runner server
uses: kofemann/action-create-certificate@v0.0.4
with:
hostcert: '127.0.0.1.pem'
hostkey: '127.0.0.1-key.pem'
cachain: 'ca-chain.pem'
- name: Adjust HTTPS certificates permissions
run: sudo chown runner:docker *.pem
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Retrieve cached dist folder
uses: actions/cache/restore@v4
id: cache-full
with:
path: |
dist
test/lib
key: cache-${{ github.sha }}
- name: Wait for other Browserstack tests to finish
uses: softprops/turnstyle@v1
with:
poll-interval-seconds: 30
abort-after-seconds: 900
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run browserstack tests
run: npm run test-browserstack -- --static-logging
- name: Run browserstack tests (lightweight) # overwrite test/lib
run: |
npm run build-test --lightweight
npm run test-browserstack -- --static-logging
env:
LIGHTWEIGHT: true
types:
name: Type definitions
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci --ignore-scripts # TS
- name: Retrieve cached folders
uses: actions/cache/restore@v4
id: cache-full
with:
path: |
dist
test/lib
key: cache-${{ github.sha }}
- run: npm run test-type-definitions
lint:
name: ESLint
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci --ignore-scripts # linter
- name: Retrieve cached folders
uses: actions/cache/restore@v4
id: cache-full
with:
path: |
dist
test/lib
key: cache-${{ github.sha }}
- run: npm run lint

6
.gitignore vendored
View File

@ -1,10 +1,8 @@
.DS_Store
node_modules/
npm*
src/compression/
test/lib/
test/typescript/definitions.js
dist/
openpgp.store/
doc/
browserify-cache*.json
.nyc_output/
coverage

17
.jsdocrc.cjs Normal file
View File

@ -0,0 +1,17 @@
const pkg = require('./package.json');
module.exports = {
plugins: ['plugins/markdown'],
markdown: {
idInHeadings: true
},
templates: {
default: {
includeDate: false,
outputSourceFiles: false,
externalSourceLinks: {
urlPrefix: `${pkg.repository.url}/blob/v${pkg.version}/src/`
}
}
}
};

View File

@ -1,3 +0,0 @@
module.exports = {
plugins: ['plugins/markdown']
};

6
.mocharc.json Normal file
View File

@ -0,0 +1,6 @@
{
"node-option": [
"experimental-specifier-resolution=node",
"loader=ts-node/esm"
]
}

View File

@ -1,55 +0,0 @@
sudo: false
language: node_js
cache:
directories:
- node_modules
addons:
code_climate:
repo_token: $CODECLIMATE_REPO_TOKEN
matrix:
fast_finish: true
include:
- node_js: "8"
env: OPENPGP_NODE_JS='8' OPENPGPJSTEST='unit'
- node_js: "10"
env: OPENPGP_NODE_JS='10' OPENPGPJSTEST='unit'
- node_js: "12"
env: OPENPGP_NODE_JS='12' OPENPGPJSTEST='unit'
- node_js: "10"
env: OPENPGP_NODE_JS='10' OPENPGPJSTEST='unit' LIGHTWEIGHT=1
- node_js: "9"
env: BROWSER='"firefox_26"' OPENPGPJSTEST='browserstack' COMPAT=1
- node_js: "9"
env: BROWSER='"firefox_61"' OPENPGPJSTEST='browserstack'
- node_js: "10"
env: BROWSER='"chrome_68"' OPENPGPJSTEST='browserstack' LIGHTWEIGHT=1
- node_js: "9"
env: BROWSER='"chrome_49"' OPENPGPJSTEST='browserstack' COMPAT=1
- node_js: "10"
env: BROWSER='"chrome_68"' OPENPGPJSTEST='browserstack'
- node_js: "9"
env: BROWSER='"ie_11"' OPENPGPJSTEST='browserstack' COMPAT=1
- node_js: "9"
env: BROWSER='"edge_17"' OPENPGPJSTEST='browserstack'
- node_js: "9"
env: BROWSER='"safari_9_1"' OPENPGPJSTEST='browserstack' COMPAT=1
- node_js: "9"
env: BROWSER='"safari_10_1"' OPENPGPJSTEST='browserstack' COMPAT=1
- node_js: "9"
env: BROWSER='"safari_11_1"' OPENPGPJSTEST='browserstack'
- node_js: "9"
env: BROWSER='{"os":"ios", "os_version":"10.3", "device":"iPhone 7 Plus", "real_mobile":true}' OPENPGPJSTEST='browserstack' COMPAT=1
- node_js: "9"
env: BROWSER='{"os":"ios", "os_version":"11.3", "device":"iPhone 8 Plus", "real_mobile":true}' OPENPGPJSTEST='browserstack'
allow_failures:
- node_js: "9"
before_script:
- npm install -g grunt-cli codeclimate-test-reporter browserstack-runner
script:
- $TRAVIS_BUILD_DIR/travis.sh
install: npm install
env:
global:
- BROWSERSTACK_USERNAME=danielhuigens2
- BROWSERSTACK_KEY=aW2q1ms393QRorwBnfmW

View File

@ -1,360 +0,0 @@
module.exports = function(grunt) {
const version = grunt.option('release');
const fs = require('fs');
// Project configuration.
const dev = !!grunt.option('dev');
const compat = !!grunt.option('compat');
const lightweight = !!grunt.option('lightweight');
const plugins = compat ? [
"transform-async-to-generator",
"syntax-async-functions",
"transform-regenerator",
"transform-runtime"
] : [];
const presets = [[require.resolve('babel-preset-env'), {
targets: {
browsers: compat ? [
'IE >= 11',
'Safari >= 9',
'Last 2 Chrome versions',
'Last 2 Firefox versions',
'Last 2 Edge versions'
] : [
'Last 2 Chrome versions',
'Last 2 Firefox versions',
'Last 2 Safari versions',
'Last 2 Edge versions'
]
}
}]];
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
openpgp: {
files: {
'dist/openpgp.js': ['./src/index.js']
},
options: {
browserifyOptions: {
fullPaths: dev,
debug: dev,
standalone: 'openpgp'
},
cacheFile: 'browserify-cache' + (compat ? '-compat' : '') + (lightweight ? '-lightweight' : '') + '.json',
// Don't bundle these packages with openpgp.js
external: ['crypto', 'zlib', 'node-localstorage', 'node-fetch', 'asn1.js', 'stream', 'buffer'].concat(
compat ? [] : [
'whatwg-fetch',
'core-js/fn/array/fill',
'core-js/fn/array/find',
'core-js/fn/array/includes',
'core-js/fn/array/from',
'core-js/fn/promise',
'core-js/fn/typed/uint8-array',
'core-js/fn/string/repeat',
'core-js/fn/symbol',
'core-js/fn/object/assign'
],
lightweight ? [
'elliptic',
'elliptic.min.js'
] : []
),
transform: [
["babelify", {
global: true,
// Only babelify web-streams-polyfill, web-stream-tools, asmcrypto, email-addresses and seek-bzip in node_modules
only: /^(?:.*\/node_modules\/@mattiasbuelens\/web-streams-polyfill\/|.*\/node_modules\/web-stream-tools\/|.*\/node_modules\/asmcrypto\.js\/|.*\/node_modules\/email-addresses\/|.*\/node_modules\/seek-bzip\/|(?!.*\/node_modules\/)).*$/,
ignore: ['*.min.js'],
plugins,
presets
}]
],
plugin: ['browserify-derequire']
}
},
worker: {
files: {
'dist/openpgp.worker.js': ['./src/worker/worker.js']
},
options: {
cacheFile: 'browserify-cache-worker.json'
}
},
unittests: {
files: {
'test/lib/unittests-bundle.js': ['./test/unittests.js']
},
options: {
cacheFile: 'browserify-cache-unittests.json',
external: ['buffer', 'openpgp', '../../dist/openpgp', '../../../dist/openpgp'],
transform: [
["babelify", {
global: true,
// Only babelify chai-as-promised in node_modules
only: /^(?:.*\/node_modules\/chai-as-promised\/|(?!.*\/node_modules\/)).*$/,
ignore: ['*.min.js'],
plugins,
presets
}]
]
}
}
},
nyc: {
cover: {
options: {
include: ['dist/**'],
reporter: ['text-summary'],
reportDir: 'coverage'
},
cmd: false,
args: ['grunt', 'mochaTest'],
sourceMap: true
},
report: {
options: {
reporter: 'text'
}
}
},
replace: {
openpgp: {
src: ['dist/openpgp.js'],
dest: ['dist/openpgp.js'],
replacements: [{
from: /OpenPGP.js VERSION/g,
to: 'OpenPGP.js v<%= pkg.version %>'
}]
},
openpgp_min: {
src: ['dist/openpgp.min.js'],
dest: ['dist/openpgp.min.js'],
replacements: [{
from: "openpgp.worker.js",
to: "openpgp.worker.min.js"
}]
},
worker_min: {
src: ['dist/openpgp.worker.min.js'],
dest: ['dist/openpgp.worker.min.js'],
replacements: [{
from: "openpgp.js",
to: "openpgp.min.js"
}]
},
lightweight_build: {
src: ['dist/openpgp.js'],
overwrite: true,
replacements: [
{
from: "external_indutny_elliptic: false",
to: "external_indutny_elliptic: true"
}
]
},
indutny_global: {
src: ['dist/elliptic.min.js'],
overwrite: true,
replacements: [
{
from: 'b.elliptic=a()',
to: 'b.openpgp.elliptic=a()'
}
]
}
},
terser: {
openpgp: {
files: {
'dist/openpgp.min.js' : ['dist/openpgp.js'],
'dist/openpgp.worker.min.js' : ['dist/openpgp.worker.js']
},
options: {
output: {
comments: `/^!/`
},
sourceMap: dev ? {
content: 'inline',
url: 'inline'
} : {},
safari10: true
}
}
},
header: {
openpgp: {
options: {
text: '/*! OpenPGP.js v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> - ' +
'this is LGPL licensed code, see LICENSE/our website <%= pkg.homepage %> for more information. */'
},
files: {
'dist/openpgp.js': 'dist/openpgp.js',
'dist/openpgp.worker.js': 'dist/openpgp.worker.js'
}
}
},
jsbeautifier: {
files: ['src/**/*.js'],
options: {
indent_size: 2,
preserve_newlines: true,
keep_array_indentation: false,
keep_function_indentation: false,
wrap_line_length: 120
}
},
eslint: {
target: ['src/**/*.js', './Gruntfile.js', './eslintrc.js', 'test/crypto/**/*.js'],
options: {
configFile: '.eslintrc.js',
fix: !!grunt.option('fix')
}
},
jsdoc: {
dist: {
src: ['README.md', 'src'],
options: {
configure: '.jsdocrc.js',
destination: 'doc',
recurse: true
}
}
},
mochaTest: {
unittests: {
options: {
reporter: 'spec',
timeout: 120000,
grep: lightweight ? 'lightweight' : undefined
},
src: ['test/unittests.js']
}
},
copy: {
browsertest: {
expand: true,
flatten: true,
cwd: 'node_modules/',
src: ['mocha/mocha.css', 'mocha/mocha.js'],
dest: 'test/lib/'
},
openpgp_compat: {
expand: true,
cwd: 'dist/',
src: ['*.js'],
dest: 'dist/compat/'
},
openpgp_lightweight: {
expand: true,
cwd: 'dist/',
src: ['*.js'],
dest: 'dist/lightweight/'
},
indutny_elliptic: {
expand: true,
flatten: true,
src: ['./node_modules/elliptic/dist/elliptic.min.js'],
dest: 'dist/'
}
},
clean: {
dist: ['dist/'],
js: ['dist/*.js']
},
connect: {
dev: {
options: {
port: 3001,
base: '.',
keepalive: true
}
},
test: {
options: {
port: 3000,
base: '.'
}
}
},
watch: {
src: {
files: ['src/**/*.js'],
tasks: lightweight ? ['browserify:openpgp', 'browserify:worker', 'replace:lightweight_build'] : ['browserify:openpgp', 'browserify:worker']
},
test: {
files: ['test/*.js', 'test/crypto/**/*.js', 'test/general/**/*.js', 'test/worker/**/*.js'],
tasks: ['browserify:unittests']
}
}
});
// Load the plugin(s)
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-terser');
grunt.loadNpmTasks('grunt-header');
grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-jsbeautifier');
grunt.loadNpmTasks('grunt-jsdoc');
grunt.loadNpmTasks('gruntify-eslint');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-simple-nyc');
grunt.registerTask('set_version', function() {
if (!version) {
throw new Error('You must specify the version: "--release=1.0.0"');
}
patchFile({
fileName: 'package.json',
version: version
});
patchFile({
fileName: 'package-lock.json',
version: version
});
patchFile({
fileName: 'bower.json',
version: version
});
});
function patchFile(options) {
const path = './' + options.fileName;
//eslint-disable-next-line
const file = require(path);
if (options.version) {
file.version = options.version;
}
//eslint-disable-next-line
fs.writeFileSync(path, JSON.stringify(file, null, 2) + '\n');
}
// Build tasks
grunt.registerTask('version', ['replace:openpgp']);
grunt.registerTask('replace_min', ['replace:openpgp_min', 'replace:worker_min']);
grunt.registerTask('build', function() {
if (lightweight) {
grunt.task.run(['copy:indutny_elliptic', 'browserify:openpgp', 'browserify:worker', 'replace:lightweight_build', 'replace:indutny_global', 'version', 'header', 'terser', 'replace_min']);
return;
}
grunt.task.run(['browserify:openpgp', 'browserify:worker', 'version', 'header', 'terser', 'replace_min']);
}
);
grunt.registerTask('documentation', ['jsdoc']);
grunt.registerTask('default', ['build']);
// Test/Dev tasks
grunt.registerTask('test', ['eslint', 'mochaTest']);
grunt.registerTask('coverage', ['nyc']);
grunt.registerTask('browsertest', ['build', 'browserify:unittests', 'copy:browsertest', 'connect:test', 'watch']);
};

608
README.md
View File

@ -1,28 +1,26 @@
OpenPGP.js [![Build Status](https://travis-ci.org/openpgpjs/openpgpjs.svg?branch=master)](https://travis-ci.org/openpgpjs/openpgpjs) [![BrowserStack Status](https://automate.browserstack.com/badge.svg?badge_key=eEkxVVM1TytwOGJNWEdnTjk4Y0VNUUNyR3pXcEtJUGRXOVFBRjVNT1JpUT0tLTZYUlZaMWdtQWs4Z0ROS3grRXc2bFE9PQ==--4a9cac0d6ea009d81aff66de0dbb239edd1aef3c)](https://automate.browserstack.com/public-build/eEkxVVM1TytwOGJNWEdnTjk4Y0VNUUNyR3pXcEtJUGRXOVFBRjVNT1JpUT0tLTZYUlZaMWdtQWs4Z0ROS3grRXc2bFE9PQ==--4a9cac0d6ea009d81aff66de0dbb239edd1aef3c) [![Join the chat on Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/openpgpjs/openpgpjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
OpenPGP.js [![Join the chat on Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/openpgpjs/openpgpjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
==========
[OpenPGP.js](https://openpgpjs.org/) is a JavaScript implementation of the OpenPGP protocol. This is defined in [RFC 4880](https://tools.ietf.org/html/rfc4880).
[OpenPGP.js](https://openpgpjs.org/) is a JavaScript implementation of the OpenPGP protocol. It implements [RFC 9580](https://datatracker.ietf.org/doc/rfc9580/) (superseding [RFC 4880](https://tools.ietf.org/html/rfc4880) and [RFC 4880bis](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10)).
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->
**Table of Contents**
- [OpenPGP.js](#openpgpjs)
- [Platform Support](#platform-support)
- [Performance](#performance)
- [Getting started](#getting-started)
- [Npm](#npm)
- [Bower](#bower)
- [Node.js](#nodejs)
- [Deno (experimental)](#deno-experimental)
- [Browser (webpack)](#browser-webpack)
- [Browser (plain files)](#browser-plain-files)
- [Examples](#examples)
- [Set up](#set-up)
- [Encrypt and decrypt *Uint8Array* data with a password](#encrypt-and-decrypt-uint8array-data-with-a-password)
- [Encrypt and decrypt *String* data with PGP keys](#encrypt-and-decrypt-string-data-with-pgp-keys)
- [Encrypt with compression](#encrypt-with-compression)
- [Encrypt symmetrically with compression](#encrypt-symmetrically-with-compression)
- [Streaming encrypt *Uint8Array* data with a password](#streaming-encrypt-uint8array-data-with-a-password)
- [Streaming encrypt and decrypt *String* data with PGP keys](#streaming-encrypt-and-decrypt-string-data-with-pgp-keys)
- [Generate new key pair](#generate-new-key-pair)
- [Revoke a key](#revoke-a-key)
- [Lookup public key on HKP server](#lookup-public-key-on-hkp-server)
- [Upload public key to HKP server](#upload-public-key-to-hkp-server)
- [Sign and verify cleartext messages](#sign-and-verify-cleartext-messages)
- [Create and verify *detached* signatures](#create-and-verify-detached-signatures)
- [Streaming sign and verify *Uint8Array* data](#streaming-sign-and-verify-uint8array-data)
@ -32,147 +30,183 @@ OpenPGP.js [![Build Status](https://travis-ci.org/openpgpjs/openpgpjs.svg?branch
- [Development](#development)
- [How do I get involved?](#how-do-i-get-involved)
- [License](#license)
- [Resources](#resources)
<!-- markdown-toc end -->
### Platform Support
* The `dist/openpgp.min.js` bundle works well with recent versions of Chrome, Firefox, Safari and Edge. It also works in Node.js 8+.
* The `dist/openpgp.min.js` (or `.mjs`) bundle works with recent versions of Chrome, Firefox, Edge and Safari 14+.
* The `dist/compat/openpgp.min.js` bundle also works with Internet Explorer 11 and old versions of Safari. Please note that this bundle overwrites the global `Promise` with a polyfill version even in some cases where it already exists, which may cause issues. It also adds some built-in prototype functions if they don't exist, such as `Array.prototype.includes`.
* The `dist/node/openpgp.min.mjs` (or `.cjs`) bundle works in Node.js v18+: it is used by default when you `import ... from 'openpgp'` (or `require('openpgp')`, respectively).
* If you wish, you could even load one or the other depending on which browser the user is using. However, if you're using the Web Worker, keep in mind that you also need to pass `{ path: 'compat/openpgp.worker.min.js' }` to `initWorker` whenever you load `compat/openpgp.min.js`.
* Support for the [Web Cryptography API](https://w3c.github.io/webcrypto/)'s `SubtleCrypto` is required.
* In browsers, `SubtleCrypto` is only available in [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).
* In supported versions of Node.js, `SubtleCrypto` is always available.
* Support for the [Web Streams API](https://streams.spec.whatwg.org/) is required.
* In browsers: the latest versions of Chrome, Firefox, Edge and Safari support Streams, including `TransformStream`s.
These are needed if you use the library with stream inputs.
In previous versions of OpenPGP.js, Web Streams were automatically polyfilled by the library,
but from v6 this task is left up to the library user, due to the more extensive browser support, and the
polyfilling side-effects. If you're working with [older browsers versions which do not implement e.g. TransformStreams](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream#browser_compatibility), you can manually
load the [Web Streams polyfill](https://github.com/MattiasBuelens/web-streams-polyfills).
Please note that when you load the polyfills, the global `ReadableStream` property (if it exists) gets overwritten with the polyfill version.
In some edge cases, you might need to use the native
`ReadableStream` (for example when using it to create a `Response`
object), in which case you should store a reference to it before loading
the polyfills. There is also the [web-streams-adapter](https://github.com/MattiasBuelens/web-streams-adapter)
library to convert back and forth between them.
* In Node.js: OpenPGP.js v6 no longer supports native Node `Readable` streams in inputs, and instead expects (and outputs) [Node's Web Streams](https://nodejs.org/api/webstreams.html#class-readablestream). [Node v17+ includes utilities to convert from and to Web Streams](https://nodejs.org/api/stream.html#streamreadabletowebstreamreadable-options).
* Currently, Chrome, Safari and Edge have partial implementations of the
[Streams specification](https://streams.spec.whatwg.org/), and Firefox
has a partial implementation behind feature flags. Chrome is the only
browser that implements `TransformStream`s, which we need, so we include
a [polyfill](https://github.com/MattiasBuelens/web-streams-polyfill) for
all other browsers. Please note that in those browsers, the global
`ReadableStream` property gets overwritten with the polyfill version if
it exists. In some edge cases, you might need to use the native
`ReadableStream` (for example when using it to create a `Response`
object), in which case you should store a reference to it before loading
OpenPGP.js. There is also the
[web-streams-adapter](https://github.com/MattiasBuelens/web-streams-adapter)
library to convert back and forth between them.
### Performance
* Version 3.0.0 of the library introduces support for public-key cryptography using [elliptic curves](https://wiki.gnupg.org/ECC). We use native implementations on browsers and Node.js when available or [Elliptic](https://github.com/indutny/elliptic) otherwise. Elliptic curve cryptography provides stronger security per bits of key, which allows for much faster operations. Currently the following curves are supported (* = when available):
* Version 3.0.0 of the library introduced support for public-key cryptography using [elliptic curves](https://wiki.gnupg.org/ECC). We use native implementations on browsers and Node.js when available. Compared to RSA, elliptic curve cryptography provides stronger security per bits of key, which allows for much faster operations. Currently the following curves are supported:
| Curve | Encryption | Signature | NodeCrypto | WebCrypto | Constant-Time |
|:---------------:|:----------:|:---------:|:----------:|:---------:|:-----------------:|
| curve25519 | ECDH | N/A | No | No | Algorithmically |
| ed25519 | N/A | EdDSA | No | Yes* | If native** |
| nistP256 | ECDH | ECDSA | Yes* | Yes* | If native** |
| nistP384 | ECDH | ECDSA | Yes* | Yes* | If native** |
| nistP521 | ECDH | ECDSA | Yes* | Yes* | If native** |
| brainpoolP256r1 | ECDH | ECDSA | Yes* | No | If native** |
| brainpoolP384r1 | ECDH | ECDSA | Yes* | No | If native** |
| brainpoolP512r1 | ECDH | ECDSA | Yes* | No | If native** |
| secp256k1 | ECDH | ECDSA | Yes* | No | If native** |
| Curve | Encryption | Signature | Elliptic | NodeCrypto | WebCrypto |
|:--------------- |:----------:|:---------:|:--------:|:----------:|:---------:|
| p256 | ECDH | ECDSA | Yes | Yes* | Yes* |
| p384 | ECDH | ECDSA | Yes | Yes* | Yes* |
| p521 | ECDH | ECDSA | Yes | Yes* | Yes* |
| secp256k1 | ECDH | ECDSA | Yes | Yes* | No |
| brainpoolP256r1 | ECDH | ECDSA | Yes | Yes* | No |
| brainpoolP384r1 | ECDH | ECDSA | Yes | Yes* | No |
| brainpoolP512r1 | ECDH | ECDSA | Yes | Yes* | No |
| curve25519 | ECDH | N/A | Yes | No | No |
| ed25519 | N/A | EdDSA | Yes | No | No |
\* when available
\** these curves are only constant-time if the underlying native implementation is available and constant-time
* Version 2.x of the library has been built from the ground up with Uint8Arrays. This allows for much better performance and memory usage than strings.
* The platform's [native Web Crypto API](https://w3c.github.io/webcrypto/) is used for performance. On Node.js the native [crypto module](https://nodejs.org/api/crypto.html#crypto_crypto) is also used, in cases where it offers additional functionality.
* If the user's browser supports [native WebCrypto](https://caniuse.com/#feat=cryptography) via the `window.crypto.subtle` API, this will be used. Under Node.js the native [crypto module](https://nodejs.org/api/crypto.html#crypto_crypto) is used. This can be deactivated by setting `openpgp.config.use_native = false`.
* The library implements the [IETF proposal](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07) for authenticated encryption using native AES-EAX, OCB, or GCM. This makes symmetric encryption up to 30x faster on supported platforms. Since the specification has not been finalized and other OpenPGP implementations haven't adopted it yet, the feature is currently behind a flag. **Note: activating this setting can break compatibility with other OpenPGP implementations, and also with future versions of OpenPGP.js. Don't use it with messages you want to store on disk or in a database.** You can enable it by setting `openpgp.config.aead_protect = true`.
* The library implements authenticated encryption (AEAD) as per [RFC 9580](https://datatracker.ietf.org/doc/rfc9580/) using AES-GCM, OCB, or EAX. This makes symmetric encryption faster on platforms with native implementations. However, since the specification is very recent and other OpenPGP implementations are in the process of adopting it, the feature is currently behind a flag. **Note: activating this setting can break compatibility with other OpenPGP implementations which have yet to implement the feature.** You can enable it by setting `openpgp.config.aeadProtect = true`.
Note that this setting has a different effect from the one in OpenPGP.js v5, which implemented support for a provisional version of AEAD from [RFC 4880bis](https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10), which was modified in RFC 9580.
You can change the AEAD mode by setting one of the following options:
```
openpgp.config.aead_mode = openpgp.enums.aead.eax // Default, native
openpgp.config.aead_mode = openpgp.enums.aead.ocb // Non-native
openpgp.config.aead_mode = openpgp.enums.aead.experimental_gcm // **Non-standard**, fastest
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.gcm; // Default, native in WebCrypto and Node.js
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb; // Non-native, but supported across RFC 9580 implementations
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax; // Native in Node.js
```
* For environments that don't provide native crypto, the library falls back to [asm.js](https://caniuse.com/#feat=asmjs) implementations of AES, SHA-1, and SHA-256. We use [Rusha](https://github.com/srijs/rusha) and [asmCrypto Lite](https://github.com/openpgpjs/asmcrypto-lite) (a minimal subset of asmCrypto.js built specifically for OpenPGP.js).
### Getting started
#### Npm
#### Node.js
npm install --save openpgp
Install OpenPGP.js using npm and save it in your dependencies:
#### Bower
```sh
npm install --save openpgp
```
bower install --save openpgp
And import it as an ES module, from a .mjs file:
```js
import * as openpgp from 'openpgp';
```
Or just fetch a minified build under [dist](https://github.com/openpgpjs/openpgpjs/tree/master/dist).
### Examples
Here are some examples of how to use the v2.x+ API. For more elaborate examples and working code, please check out the [public API unit tests](https://github.com/openpgpjs/openpgpjs/blob/master/test/general/openpgp.js). If you're upgrading from v1.x it might help to check out the [documentation](https://github.com/openpgpjs/openpgpjs#documentation).
#### Set up
##### Node.js
Or as a CommonJS module:
```js
const openpgp = require('openpgp');
```
##### Browser
#### Deno (experimental)
Copy `dist/openpgp.min.js` or `dist/compat/openpgp.min.js` (depending on the browser support you need, see [Platform Support](#platform-support)) to your project folder, and load it in a script tag:
Import as an ES6 module, using /dist/openpgp.mjs.
```js
import * as openpgp from './openpgpjs/dist/openpgp.mjs';
```
#### Browser (webpack)
Install OpenPGP.js using npm and save it in your devDependencies:
```sh
npm install --save-dev openpgp
```
And import it as an ES6 module:
```js
import * as openpgp from 'openpgp';
```
You can also only import the functions you need, as follows:
```js
import { readMessage, decrypt } from 'openpgp';
```
Or, if you want to use the lightweight build (which is smaller, and lazily loads non-default curves on demand):
```js
import * as openpgp from 'openpgp/lightweight';
```
To test whether the lazy loading works, try to generate a key with a non-standard curve:
```js
import { generateKey } from 'openpgp/lightweight';
await generateKey({ curve: 'brainpoolP512r1', userIDs: [{ name: 'Test', email: 'test@test.com' }] });
```
For more examples of how to generate a key, see [Generate new key pair](#generate-new-key-pair). It is recommended to use `curve25519` instead of `brainpoolP512r1` by default.
#### Browser (plain files)
Grab `openpgp.min.js` from [unpkg.com/openpgp/dist](https://unpkg.com/openpgp/dist/), and load it in a script tag:
```html
<script src="openpgp.min.js"></script>
```
If you want to use the built-in Web Worker, to offload cryptographic operations off the main thread:
```js
await openpgp.initWorker({ path: 'openpgp.worker.js' }); // set the relative web worker path
```
On logout, be sure to destroy the worker again, to clear private keys from memory:
```js
await openpgp.destroyWorker();
```
Alternatively, you can also implement a Web Worker in your application and load OpenPGP.js from there. This can be more performant if you store or fetch keys and messages directly inside the Worker, so that they don't have to be `postMessage`d there.
If you want to use the lightweight build (which is smaller, and lazily loads non-default curves on demand), copy `dist/lightweight/openpgp.min.js` and `dist/lightweight/elliptic.min.js`, load the former in a script tag, and point `openpgp.config.indutny_elliptic_path` to the latter:
Or, to load OpenPGP.js as an ES6 module, grab `openpgp.min.mjs` from [unpkg.com/openpgp/dist](https://unpkg.com/openpgp/dist/), and import it as follows:
```html
<script src="lightweight/openpgp.min.js"></script>
<script>
openpgp.config.indutny_elliptic_path = 'lightweight/elliptic.min.js';
<script type="module">
import * as openpgp from './openpgp.min.mjs';
</script>
```
To test whether the lazy loading works, try:
To offload cryptographic operations off the main thread, you can implement a Web Worker in your application and load OpenPGP.js from there. For an example Worker implementation, see `test/worker/worker_example.js`.
```js
await openpgp.generateKey({ curve: 'brainpoolP512r1', userIds: [{ name: 'Test', email: 'test@test.com' }] });
#### TypeScript
Since TS is not fully integrated in the library, TS-only dependencies are currently listed as `devDependencies`, so to compile the project youll need to add `@openpgp/web-stream-tools` manually:
```sh
npm install --save-dev @openpgp/web-stream-tools
```
For more examples of how to generate a key, see [Generate new key pair](#generate-new-key-pair). It is recommended to use `curve25519` instead of `brainpoolP512r1` by default.
If you notice missing or incorrect type definitions, feel free to open a PR.
### Examples
Here are some examples of how to use OpenPGP.js v6. For more elaborate examples and working code, please check out the [public API unit tests](https://github.com/openpgpjs/openpgpjs/blob/main/test/general/openpgp.js). If you're upgrading from v4 it might help to check out the [changelog](https://github.com/openpgpjs/openpgpjs/wiki/v6-Changelog) and [documentation](https://github.com/openpgpjs/openpgpjs#documentation).
#### Encrypt and decrypt *Uint8Array* data with a password
Encryption will use the algorithm specified in config.encryption_cipher (defaults to aes256), and decryption will use the algorithm used for encryption.
Encryption will use the algorithm specified in config.preferredSymmetricAlgorithm (defaults to aes256), and decryption will use the algorithm used for encryption.
```js
(async () => {
const { message } = await openpgp.encrypt({
message: openpgp.message.fromBinary(new Uint8Array([0x01, 0x01, 0x01])), // input as Message object
passwords: ['secret stuff'], // multiple passwords possible
armor: false // don't ASCII armor (for Uint8Array output)
const message = await openpgp.createMessage({ binary: new Uint8Array([0x01, 0x01, 0x01]) });
const encrypted = await openpgp.encrypt({
message, // input as Message object
passwords: ['secret stuff'], // multiple passwords possible
format: 'binary' // don't ASCII armor (for Uint8Array output)
});
const encrypted = message.packets.write(); // get raw encrypted packets as Uint8Array
console.log(encrypted); // Uint8Array
const encryptedMessage = await openpgp.readMessage({
binaryMessage: encrypted // parse encrypted bytes
});
const { data: decrypted } = await openpgp.decrypt({
message: await openpgp.message.read(encrypted), // parse encrypted bytes
passwords: ['secret stuff'], // decrypt with password
format: 'binary' // output as Uint8Array
message: encryptedMessage,
passwords: ['secret stuff'], // decrypt with password
format: 'binary' // output as Uint8Array
});
console.log(decrypted); // Uint8Array([0x01, 0x01, 0x01])
})();
@ -180,14 +214,12 @@ Encryption will use the algorithm specified in config.encryption_cipher (default
#### Encrypt and decrypt *String* data with PGP keys
Encryption will use the algorithm preferred by the public key (defaults to aes256 for keys generated in OpenPGP.js), and decryption will use the algorithm used for encryption.
Encryption will use the algorithm preferred by the public (encryption) key (defaults to aes256 for keys generated in OpenPGP.js), and decryption will use the algorithm used for encryption.
```js
const openpgp = require('openpgp'); // use as CommonJS, AMD, ES6 module or via window.openpgp
(async () => {
await openpgp.initWorker({ path: 'openpgp.worker.js' }); // set the relative web worker path
// put keys in backtick (``) to avoid errors caused by spaces or tabs
const publicKeyArmored = `-----BEGIN PGP PUBLIC KEY BLOCK-----
...
@ -197,25 +229,40 @@ const openpgp = require('openpgp'); // use as CommonJS, AMD, ES6 module or via w
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored);
await privateKey.decrypt(passphrase);
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
const { data: encrypted } = await openpgp.encrypt({
message: openpgp.message.fromText('Hello, World!'), // input as Message object
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, // for encryption
privateKeys: [privateKey] // for signing (optional)
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: 'Hello, World!' }), // input as Message object
encryptionKeys: publicKey,
signingKeys: privateKey // optional
});
console.log(encrypted); // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
const { data: decrypted } = await openpgp.decrypt({
message: await openpgp.message.readArmored(encrypted), // parse armored message
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, // for verification (optional)
privateKeys: [privateKey] // for decryption
const message = await openpgp.readMessage({
armoredMessage: encrypted // parse armored message
});
const { data: decrypted, signatures } = await openpgp.decrypt({
message,
verificationKeys: publicKey, // optional
decryptionKeys: privateKey
});
console.log(decrypted); // 'Hello, World!'
// check signature validity (signed messages only)
try {
await signatures[0].verified; // throws on invalid signature
console.log('Signature is valid');
} catch (e) {
throw new Error('Signature could not be verified: ' + e.message);
}
})();
```
Encrypt with multiple public keys:
Encrypt to multiple public keys:
```js
(async () => {
@ -231,49 +278,88 @@ Encrypt with multiple public keys:
...
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
const message = 'Hello, World!';
const plaintext = 'Hello, World!';
const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored);
await privateKey.decrypt(passphrase)
const publicKeys = await Promise.all(publicKeysArmored.map(armoredKey => openpgp.readKey({ armoredKey })));
const publicKeys = await Promise.all(publicKeysArmored.map(async (key) => {
return (await openpgp.key.readArmored(key)).keys[0];
}));
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readKey({ armoredKey: privateKeyArmored }),
passphrase
});
const { data: encrypted } = await openpgp.encrypt({
message: openpgp.message.fromText(message), // input as Message object
publicKeys, // for encryption
privateKeys: [privateKey] // for signing (optional)
const message = await openpgp.createMessage({ text: plaintext });
const encrypted = await openpgp.encrypt({
message, // input as Message object
encryptionKeys: publicKeys,
signingKeys: privateKey // optional
});
console.log(encrypted); // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
})();
```
#### Encrypt with compression
If you expect an encrypted message to be signed with one of the public keys you have, and do not want to trust the decrypted data otherwise, you can pass the decryption option `expectSigned = true`, so that the decryption operation will fail if no valid signature is found:
```js
(async () => {
// put keys in backtick (``) to avoid errors caused by spaces or tabs
const publicKeyArmored = `-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----`;
const privateKeyArmored = `-----BEGIN PGP PRIVATE KEY BLOCK-----
...
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
By default, `encrypt` will not use any compression. It's possible to override that behavior in two ways:
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
Either set the `compression` parameter in the options object when calling `encrypt`.
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
const encryptedAndSignedMessage = `-----BEGIN PGP MESSAGE-----
...
-----END PGP MESSAGE-----`;
const message = await openpgp.readMessage({
armoredMessage: encryptedAndSignedMessage // parse armored message
});
// decryption will fail if all signatures are invalid or missing
const { data: decrypted, signatures } = await openpgp.decrypt({
message,
decryptionKeys: privateKey,
expectSigned: true,
verificationKeys: publicKey, // mandatory with expectSigned=true
});
console.log(decrypted); // 'Hello, World!'
})();
```
#### Encrypt symmetrically with compression
By default, `encrypt` will not use any compression when encrypting symmetrically only (i.e. when no `encryptionKeys` are given).
It's possible to change that behaviour by enabling compression through the config, either for the single encryption:
```js
(async () => {
const message = await openpgp.createMessage({ binary: new Uint8Array([0x01, 0x02, 0x03]) }); // or createMessage({ text: 'string' })
const encrypted = await openpgp.encrypt({
message: openpgp.message.fromBinary(new Uint8Array([0x01, 0x02, 0x03])), // or .fromText('string')
passwords: ['secret stuff'], // multiple passwords possible
compression: openpgp.enums.compression.zip // compress the data with zip
message,
passwords: ['secret stuff'], // multiple passwords possible
config: { preferredCompressionAlgorithm: openpgp.enums.compression.zlib } // compress the data with zlib
});
})();
```
Or, override the config to enable compression:
or by changing the default global configuration:
```js
openpgp.config.compression = openpgp.enums.compression.zlib;
openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zlib
```
Where the value can be any of:
* `openpgp.enums.compression.zip`
* `openpgp.enums.compression.zlib`
* `openpgp.enums.compression.uncompressed` (default)
#### Streaming encrypt *Uint8Array* data with a password
@ -287,34 +373,24 @@ Where the value can be any of:
}
});
const { message } = await openpgp.encrypt({
message: openpgp.message.fromBinary(readableStream), // input as Message object
passwords: ['secret stuff'], // multiple passwords possible
armor: false // don't ASCII armor (for Uint8Array output)
const message = await openpgp.createMessage({ binary: readableStream });
const encrypted = await openpgp.encrypt({
message, // input as Message object
passwords: ['secret stuff'], // multiple passwords possible
format: 'binary' // don't ASCII armor (for Uint8Array output)
});
const encrypted = message.packets.write(); // get raw encrypted packets as ReadableStream<Uint8Array>
console.log(encrypted); // raw encrypted packets as ReadableStream<Uint8Array>
// Either pipe the above stream somewhere, pass it to another function,
// or read it manually as follows:
const reader = openpgp.stream.getReader(encrypted);
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log('new chunk:', value); // Uint8Array
for await (const chunk of encrypted) {
console.log('new chunk:', chunk); // Uint8Array
}
// Or, in Node.js, you can pipe the above stream as follows:
const nodeStream = openpgp.stream.webToNode(encrypted);
nodeStream.pipe(nodeWritableStream);
})();
```
For more information on creating ReadableStreams, see [the MDN Documentation on `new
ReadableStream()`](https://developer.mozilla.org/docs/Web/API/ReadableStream/ReadableStream).
For more information on reading streams using `openpgp.stream`, see the documentation of
[the web-stream-tools dependency](https://openpgpjs.org/web-stream-tools/), particularly
its [Reader class](https://openpgpjs.org/web-stream-tools/Reader.html).
For more information on using ReadableStreams (both in browsers and Node.js), see [the MDN Documentation on the
Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) .
#### Streaming encrypt and decrypt *String* data with PGP keys
@ -323,13 +399,17 @@ its [Reader class](https://openpgpjs.org/web-stream-tools/Reader.html).
const publicKeyArmored = `-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----`; // Public key
const [privateKeyArmored] = `-----BEGIN PGP PRIVATE KEY BLOCK-----
const privateKeyArmored = `-----BEGIN PGP PRIVATE KEY BLOCK-----
...
-----END PGP PRIVATE KEY BLOCK-----`; // Encrypted private key
const passphrase = `yourPassphrase`; // Password that private key is encrypted with
const privateKey = (await openpgp.key.readArmored([privateKeyArmored])).keys[0];
await privateKey.decrypt(passphrase);
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
const readableStream = new ReadableStream({
start(controller) {
@ -339,53 +419,64 @@ its [Reader class](https://openpgpjs.org/web-stream-tools/Reader.html).
});
const encrypted = await openpgp.encrypt({
message: openpgp.message.fromText(readableStream), // input as Message object
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, // for encryption
privateKeys: [privateKey] // for signing (optional)
message: await openpgp.createMessage({ text: readableStream }), // input as Message object
encryptionKeys: publicKey,
signingKeys: privateKey // optional
});
const ciphertext = encrypted.data; // ReadableStream containing '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
console.log(encrypted); // ReadableStream containing '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
const decrypted = await openpgp.decrypt({
message: await openpgp.message.readArmored(ciphertext), // parse armored message
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, // for verification (optional)
privateKeys: [privateKey] // for decryption
const message = await openpgp.readMessage({
armoredMessage: encrypted // parse armored message
});
const plaintext = await openpgp.stream.readToEnd(decrypted.data); // 'Hello, World!'
const decrypted = await openpgp.decrypt({
message,
verificationKeys: publicKey, // optional
decryptionKeys: privateKey
});
const chunks = [];
for await (const chunk of decrypted.data) {
chunks.push(chunk);
}
const plaintext = chunks.join('');
console.log(plaintext); // 'Hello, World!'
})();
```
#### Generate new key pair
ECC keys:
ECC keys (smaller and faster to generate):
Possible values for `curve` are: `curve25519`, `ed25519`, `p256`, `p384`, `p521`, `secp256k1`,
`brainpoolP256r1`, `brainpoolP384r1`, or `brainpoolP512r1`.
Possible values for `curve` are: `curve25519`, `ed25519`, `nistP256`, `nistP384`, `nistP521`,
`brainpoolP256r1`, `brainpoolP384r1`, `brainpoolP512r1`, and `secp256k1`.
Note that both the `curve25519` and `ed25519` options generate a primary key for signing using Ed25519
and a subkey for encryption using Curve25519.
```js
(async () => {
const { privateKeyArmored, publicKeyArmored, revocationCertificate } = await openpgp.generateKey({
userIds: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs
curve: 'ed25519', // ECC curve name
passphrase: 'super long and hard to guess secret' // protects the private key
const { privateKey, publicKey, revocationCertificate } = await openpgp.generateKey({
type: 'ecc', // Type of the key, defaults to ECC
curve: 'curve25519', // ECC curve name, defaults to curve25519
userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs
passphrase: 'super long and hard to guess secret', // protects the private key
format: 'armored' // output key format, defaults to 'armored' (other options: 'binary' or 'object')
});
console.log(privateKeyArmored); // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
console.log(publicKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
console.log(privateKey); // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
console.log(publicKey); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
console.log(revocationCertificate); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
})();
```
RSA keys:
RSA keys (increased compatibility):
```js
(async () => {
const key = await openpgp.generateKey({
userIds: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs
rsaBits: 4096, // RSA key size
passphrase: 'super long and hard to guess secret' // protects the private key
const { privateKey, publicKey } = await openpgp.generateKey({
type: 'rsa', // Type of the key
rsaBits: 4096, // RSA key size (defaults to 4096 bits)
userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs
passphrase: 'super long and hard to guess secret' // protects the private key
});
})();
```
@ -395,9 +486,10 @@ RSA keys:
Using a revocation certificate:
```js
(async () => {
const { publicKeyArmored: revokedKeyArmored } = await openpgp.revokeKey({
key: (await openpgp.key.readArmored(publicKeyArmored)).keys[0],
revocationCertificate
const { publicKey: revokedKeyArmored } = await openpgp.revokeKey({
key: await openpgp.readKey({ armoredKey: publicKeyArmored }),
revocationCertificate,
format: 'armored' // output armored keys
});
console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
})();
@ -406,36 +498,11 @@ Using a revocation certificate:
Using the private key:
```js
(async () => {
const { publicKeyArmored, publicKey } = await openpgp.revokeKey({
key: (await openpgp.key.readArmored(privateKeyArmored)).keys[0]
const { publicKey: revokedKeyArmored } = await openpgp.revokeKey({
key: await openpgp.readKey({ armoredKey: privateKeyArmored }),
format: 'armored' // output armored keys
});
})();
```
#### Lookup public key on HKP server
```js
(async () => {
var hkp = new openpgp.HKP(); // Defaults to https://keyserver.ubuntu.com, or pass another keyserver URL as a string
let publicKeyArmored = await hkp.lookup({
query: 'alice@example.com'
});
var { keys: [publicKey] } = await openpgp.key.readArmored(publicKeyArmored);
})();
```
#### Upload public key to HKP server
```js
(async () => {
var hkp = new openpgp.HKP('https://pgp.mit.edu');
var publicKeyArmored = `-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----`;
await hkp.upload(publicKeyArmored);
console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
})();
```
@ -451,24 +518,33 @@ Using the private key:
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored);
await privateKey.decrypt(passphrase);
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
const { data: cleartext } = await openpgp.sign({
message: openpgp.cleartext.fromText('Hello, World!'), // CleartextMessage or Message object
privateKeys: [privateKey] // for signing
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
console.log(cleartext); // '-----BEGIN PGP SIGNED MESSAGE ... END PGP SIGNATURE-----'
const verified = await openpgp.verify({
message: await openpgp.cleartext.readArmored(cleartext), // parse armored message
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys // for verification
const unsignedMessage = await openpgp.createCleartextMessage({ text: 'Hello, World!' });
const cleartextMessage = await openpgp.sign({
message: unsignedMessage, // CleartextMessage or Message object
signingKeys: privateKey
});
const { valid } = verified.signatures[0];
if (valid) {
console.log('signed by key id ' + verified.signatures[0].keyid.toHex());
} else {
throw new Error('signature could not be verified');
console.log(cleartextMessage); // '-----BEGIN PGP SIGNED MESSAGE ... END PGP SIGNATURE-----'
const signedMessage = await openpgp.readCleartextMessage({
cleartextMessage // parse armored message
});
const verificationResult = await openpgp.verify({
message: signedMessage,
verificationKeys: publicKey
});
const { verified, keyID } = verificationResult.signatures[0];
try {
await verified; // throws on invalid signature
console.log('Signed by key id ' + keyID.toHex());
} catch (e) {
throw new Error('Signature could not be verified: ' + e.message);
}
})();
```
@ -485,26 +561,35 @@ Using the private key:
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored);
await privateKey.decrypt(passphrase);
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
const { signature: detachedSignature } = await openpgp.sign({
message: openpgp.cleartext.fromText('Hello, World!'), // CleartextMessage or Message object
privateKeys: [privateKey], // for signing
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
const message = await openpgp.createMessage({ text: 'Hello, World!' });
const detachedSignature = await openpgp.sign({
message, // Message object
signingKeys: privateKey,
detached: true
});
console.log(detachedSignature);
const verified = await openpgp.verify({
message: openpgp.cleartext.fromText('Hello, World!'), // CleartextMessage or Message object
signature: await openpgp.signature.readArmored(detachedSignature), // parse detached signature
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys // for verification
const signature = await openpgp.readSignature({
armoredSignature: detachedSignature // parse detached signature
});
const { valid } = verified.signatures[0];
if (valid) {
console.log('signed by key id ' + verified.signatures[0].keyid.toHex());
} else {
throw new Error('signature could not be verified');
const verificationResult = await openpgp.verify({
message, // Message object
signature,
verificationKeys: publicKey
});
const { verified, keyID } = verificationResult.signatures[0];
try {
await verified; // throws on invalid signature
console.log('Signed by key id ' + keyID.toHex());
} catch (e) {
throw new Error('Signature could not be verified: ' + e.message);
}
})();
```
@ -528,39 +613,40 @@ Using the private key:
-----END PGP PRIVATE KEY BLOCK-----`; // encrypted private key
const passphrase = `yourPassphrase`; // what the private key is encrypted with
const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored);
await privateKey.decrypt(passphrase);
const privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase
});
const { data: signatureArmored } = await openpgp.sign({
message: openpgp.message.fromBinary(readableStream), // or .fromText(readableStream: ReadableStream<String>)
privateKeys: [privateKey] // for signing
const message = await openpgp.createMessage({ binary: readableStream }); // or createMessage({ text: ReadableStream<String> })
const signatureArmored = await openpgp.sign({
message,
signingKeys: privateKey
});
console.log(signatureArmored); // ReadableStream containing '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
const verified = await openpgp.verify({
message: await openpgp.message.readArmored(signatureArmored), // parse armored signature
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys // for verification
const verificationResult = await openpgp.verify({
message: await openpgp.readMessage({ armoredMessage: signatureArmored }), // parse armored signature
verificationKeys: await openpgp.readKey({ armoredKey: publicKeyArmored })
});
await openpgp.stream.readToEnd(verified.data);
// Note: you *have* to read `verified.data` in some way or other,
for await (const chunk of verificationResult.data) {}
// Note: you *have* to read `verificationResult.data` in some way or other,
// even if you don't need it, as that is what triggers the
// verification of the data.
const { valid } = verified.signatures[0];
if (valid) {
console.log('signed by key id ' + verified.signatures[0].keyid.toHex());
} else {
throw new Error('signature could not be verified');
try {
await verificationResult.signatures[0].verified; // throws on invalid signature
console.log('Signed by key id ' + verificationResult.signatures[0].keyID.toHex());
} catch (e) {
throw new Error('Signature could not be verified: ' + e.message);
}
})();
```
### Documentation
A jsdoc build of our code comments is available at [doc/index.html](https://openpgpjs.org/openpgpjs/doc/index.html). Public calls should generally be made through the OpenPGP object [doc/openpgp.html](https://openpgpjs.org/openpgpjs/doc/module-openpgp.html).
For the documentation of `openpgp.stream`, see the documentation of [the web-stream-tools dependency](https://openpgpjs.org/web-stream-tools/).
The full documentation is available at [openpgpjs.org](https://docs.openpgpjs.org/).
### Security Audit
@ -578,9 +664,9 @@ To create your own build of the library, just run the following command after cl
npm install && npm test
For debugging browser errors, you can open `test/unittests.html` in a browser or, after running the following command, open [`http://localhost:3000/test/unittests.html`](http://localhost:3000/test/unittests.html):
For debugging browser errors, run the following command:
grunt browsertest
npm run browsertest
### How do I get involved?
@ -589,13 +675,3 @@ You want to help, great! It's probably best to send us a message on [Gitter](htt
### License
[GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.en.html) (3.0 or any later version). Please take a look at the [LICENSE](LICENSE) file for more information.
### Resources
Below is a collection of resources, many of these were projects that were in someway a precursor to the current OpenPGP.js project. If you'd like to add your link here, please do so in a pull request or email to the list.
* [https://www.hanewin.net/encrypt/](https://www.hanewin.net/encrypt/)
* [https://github.com/seancolyer/gmail-crypt](https://github.com/seancolyer/gmail-crypt)
* [https://github.com/mete0r/jspg](https://github.com/mete0r/jspg)
* [https://github.com/GPGTools/Mobile/wiki/Introduction](https://github.com/GPGTools/Mobile/wiki/Introduction)
* [https://github.com/gmontalvoriv/mailock](https://github.com/gmontalvoriv/mailock)

7
SECURITY.md Normal file
View File

@ -0,0 +1,7 @@
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
If you believe you have found a security vulnerability in OpenPGP.js, please report it via email to [security@openpgpjs.org](mailto:security@openpgpjs.org). If possible, encrypt your message with our PGP key: it can be downloaded automatically using [WKD](https://wiki.gnupg.org/WKD), or manually on [openpgpjs.org](https://openpgpjs.org/.well-known/openpgpkey/hu/t5s8ztdbon8yzntexy6oz5y48etqsnbb?l=security).
You should receive a response within 2 working days.

View File

@ -1,37 +0,0 @@
{
"name": "openpgp",
"version": "4.10.3",
"license": "LGPL-3.0+",
"homepage": "https://openpgpjs.org/",
"authors": [
"OpenPGP Development Team <list@openpgpjs.org> (https://github.com/openpgpjs/openpgpjs/graphs/contributors)"
],
"description": "OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.",
"main": [
"dist/openpgp.js",
"dist/openpgp.worker.js"
],
"moduleType": [
"amd",
"es6",
"globals",
"node"
],
"keywords": [
"crypto",
"gpg",
"pgp",
"openpgp",
"encryption"
],
"ignore": [
"**/.*",
"dist/*.tgz",
"dist/*_debug.js",
"node_modules",
"bower_components",
"test",
"tests",
"doc"
]
}

59933
dist/compat/openpgp.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,173 +0,0 @@
/*! OpenPGP.js v4.10.3 - 2020-04-21 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (global){
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/* eslint-disable no-restricted-globals */
/* eslint-disable no-var */
/* eslint-disable vars-on-top */
/**
* @fileoverview Provides functions for communicating with workers
* @see module:openpgp.initWorker
* @see module:openpgp.getWorker
* @see module:openpgp.destroyWorker
* @see module:worker/async_proxy
* @module worker/worker
*/
importScripts('openpgp.js');
var openpgp = global.openpgp;
var randomQueue = [];
var MAX_SIZE_RANDOM_BUFFER = 60000;
/**
* Handle random buffer exhaustion by requesting more random bytes from the main window
* @returns {Promise<Object>} Empty promise whose resolution indicates that the buffer has been refilled
*/
function randomCallback() {
if (!randomQueue.length) {
self.postMessage({ event: 'request-seed', amount: MAX_SIZE_RANDOM_BUFFER });
}
return new Promise(function(resolve) {
randomQueue.push(resolve);
});
}
openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER, randomCallback);
/**
* Handle messages from the main window.
* @param {Object} event Contains event type and data
*/
self.onmessage = function(event) {
var msg = event.data || {};
switch (msg.event) {
case 'configure':
configure(msg.config);
break;
case 'seed-random':
seedRandom(msg.buf);
var queueCopy = randomQueue;
randomQueue = [];
for (var i = 0; i < queueCopy.length; i++) {
queueCopy[i]();
}
break;
default:
delegate(msg.id, msg.event, msg.options || {});
}
};
/**
* Set config from main context to worker context.
* @param {Object} config The openpgp configuration
*/
function configure(config) {
Object.keys(config).forEach(function(key) {
openpgp.config[key] = config[key];
});
}
/**
* Seed the library with entropy gathered global.crypto.getRandomValues
* as this api is only avalible in the main window.
* @param {ArrayBuffer} buffer Some random bytes
*/
function seedRandom(buffer) {
if (!(buffer instanceof Uint8Array)) {
buffer = new Uint8Array(buffer);
}
openpgp.crypto.random.randomBuffer.set(buffer);
}
const keyCache = new Map();
function getCachedKey(key) {
const armor = key.armor();
if (keyCache.has(armor)) {
return keyCache.get(armor);
}
keyCache.set(armor, key);
return key;
}
/**
* Generic proxy function that handles all commands from the public api.
* @param {String} method The public api function to be delegated to the worker thread
* @param {Object} options The api function's options
*/
function delegate(id, method, options) {
if (method === 'clear-key-cache') {
Array.from(keyCache.values()).forEach(key => {
if (key.isPrivate()) {
key.clearPrivateParams();
}
});
keyCache.clear();
response({ id, event: 'method-return' });
return;
}
if (typeof openpgp[method] !== 'function') {
response({ id:id, event:'method-return', err:'Unknown Worker Event' });
return;
}
// construct ReadableStreams from MessagePorts
openpgp.util.restoreStreams(options);
// parse cloned packets
options = openpgp.packet.clone.parseClonedPackets(options, method);
// cache keys by armor, so that we don't have to repeatedly verify self-signatures
if (options.publicKeys) {
options.publicKeys = options.publicKeys.map(getCachedKey);
}
if (options.privateKeys) {
options.privateKeys = options.privateKeys.map(getCachedKey);
}
openpgp[method](options).then(function(data) {
// clone packets (for web worker structured cloning algorithm)
response({ id:id, event:'method-return', data:openpgp.packet.clone.clonePackets(data) });
}).catch(function(e) {
openpgp.util.print_debug_error(e);
response({
id:id, event:'method-return', err:e.message, stack:e.stack
});
});
}
/**
* Respond to the main window.
* @param {Object} event Contains event type and data
*/
function response(event) {
self.postMessage(event, openpgp.util.getTransferables(event.data, true));
}
/**
* Let the main window know the worker has loaded.
*/
postMessage({ event: 'loaded' });
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[1]);

View File

@ -1,2 +0,0 @@
/*! OpenPGP.js v4.10.3 - 2020-04-21 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
!function(){return function e(n,t,r){function o(i,s){if(!t[i]){if(!n[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(a)return a(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var f=t[i]={exports:{}};n[i][0].call(f.exports,function(e){return o(n[i][1][e]||e)},f,f.exports,e,n,t,r)}return t[i].exports}for(var a="function"==typeof require&&require,i=0;i<r.length;i++)o(r[i]);return o}}()({1:[function(e,n,t){(function(e){importScripts("openpgp.min.js");var n=e.openpgp,t=[],r=6e4;n.crypto.random.randomBuffer.init(r,function(){return t.length||self.postMessage({event:"request-seed",amount:r}),new Promise(function(e){t.push(e)})}),self.onmessage=function(e){var r,s=e.data||{};switch(s.event){case"configure":r=s.config,Object.keys(r).forEach(function(e){n.config[e]=r[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));n.crypto.random.randomBuffer.set(e)}(s.buf);var u=t;t=[];for(var c=0;c<u.length;c++)u[c]();break;default:!function(e,t,r){if("clear-key-cache"===t)return Array.from(o.values()).forEach(e=>{e.isPrivate()&&e.clearPrivateParams()}),o.clear(),void i({id:e,event:"method-return"});if("function"!=typeof n[t])return void i({id:e,event:"method-return",err:"Unknown Worker Event"});n.util.restoreStreams(r),(r=n.packet.clone.parseClonedPackets(r,t)).publicKeys&&(r.publicKeys=r.publicKeys.map(a));r.privateKeys&&(r.privateKeys=r.privateKeys.map(a));n[t](r).then(function(t){i({id:e,event:"method-return",data:n.packet.clone.clonePackets(t)})}).catch(function(t){n.util.print_debug_error(t),i({id:e,event:"method-return",err:t.message,stack:t.stack})})}(s.id,s.event,s.options||{})}};const o=new Map;function a(e){const n=e.armor();return o.has(n)?o.get(n):(o.set(n,e),e)}function i(e){self.postMessage(e,n.util.getTransferables(e.data,!0))}postMessage({event:"loaded"})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1]);

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

View File

@ -1,173 +0,0 @@
/*! OpenPGP.js v4.10.3 - 2020-04-21 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (global){
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/* eslint-disable no-restricted-globals */
/* eslint-disable no-var */
/* eslint-disable vars-on-top */
/**
* @fileoverview Provides functions for communicating with workers
* @see module:openpgp.initWorker
* @see module:openpgp.getWorker
* @see module:openpgp.destroyWorker
* @see module:worker/async_proxy
* @module worker/worker
*/
importScripts('openpgp.js');
var openpgp = global.openpgp;
var randomQueue = [];
var MAX_SIZE_RANDOM_BUFFER = 60000;
/**
* Handle random buffer exhaustion by requesting more random bytes from the main window
* @returns {Promise<Object>} Empty promise whose resolution indicates that the buffer has been refilled
*/
function randomCallback() {
if (!randomQueue.length) {
self.postMessage({ event: 'request-seed', amount: MAX_SIZE_RANDOM_BUFFER });
}
return new Promise(function(resolve) {
randomQueue.push(resolve);
});
}
openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER, randomCallback);
/**
* Handle messages from the main window.
* @param {Object} event Contains event type and data
*/
self.onmessage = function(event) {
var msg = event.data || {};
switch (msg.event) {
case 'configure':
configure(msg.config);
break;
case 'seed-random':
seedRandom(msg.buf);
var queueCopy = randomQueue;
randomQueue = [];
for (var i = 0; i < queueCopy.length; i++) {
queueCopy[i]();
}
break;
default:
delegate(msg.id, msg.event, msg.options || {});
}
};
/**
* Set config from main context to worker context.
* @param {Object} config The openpgp configuration
*/
function configure(config) {
Object.keys(config).forEach(function(key) {
openpgp.config[key] = config[key];
});
}
/**
* Seed the library with entropy gathered global.crypto.getRandomValues
* as this api is only avalible in the main window.
* @param {ArrayBuffer} buffer Some random bytes
*/
function seedRandom(buffer) {
if (!(buffer instanceof Uint8Array)) {
buffer = new Uint8Array(buffer);
}
openpgp.crypto.random.randomBuffer.set(buffer);
}
const keyCache = new Map();
function getCachedKey(key) {
const armor = key.armor();
if (keyCache.has(armor)) {
return keyCache.get(armor);
}
keyCache.set(armor, key);
return key;
}
/**
* Generic proxy function that handles all commands from the public api.
* @param {String} method The public api function to be delegated to the worker thread
* @param {Object} options The api function's options
*/
function delegate(id, method, options) {
if (method === 'clear-key-cache') {
Array.from(keyCache.values()).forEach(key => {
if (key.isPrivate()) {
key.clearPrivateParams();
}
});
keyCache.clear();
response({ id, event: 'method-return' });
return;
}
if (typeof openpgp[method] !== 'function') {
response({ id:id, event:'method-return', err:'Unknown Worker Event' });
return;
}
// construct ReadableStreams from MessagePorts
openpgp.util.restoreStreams(options);
// parse cloned packets
options = openpgp.packet.clone.parseClonedPackets(options, method);
// cache keys by armor, so that we don't have to repeatedly verify self-signatures
if (options.publicKeys) {
options.publicKeys = options.publicKeys.map(getCachedKey);
}
if (options.privateKeys) {
options.privateKeys = options.privateKeys.map(getCachedKey);
}
openpgp[method](options).then(function(data) {
// clone packets (for web worker structured cloning algorithm)
response({ id:id, event:'method-return', data:openpgp.packet.clone.clonePackets(data) });
}).catch(function(e) {
openpgp.util.print_debug_error(e);
response({
id:id, event:'method-return', err:e.message, stack:e.stack
});
});
}
/**
* Respond to the main window.
* @param {Object} event Contains event type and data
*/
function response(event) {
self.postMessage(event, openpgp.util.getTransferables(event.data, true));
}
/**
* Let the main window know the worker has loaded.
*/
postMessage({ event: 'loaded' });
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[1]);

View File

@ -1,2 +0,0 @@
/*! OpenPGP.js v4.10.3 - 2020-04-21 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
!function(){return function e(n,t,r){function o(i,s){if(!t[i]){if(!n[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(a)return a(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var f=t[i]={exports:{}};n[i][0].call(f.exports,function(e){return o(n[i][1][e]||e)},f,f.exports,e,n,t,r)}return t[i].exports}for(var a="function"==typeof require&&require,i=0;i<r.length;i++)o(r[i]);return o}}()({1:[function(e,n,t){(function(e){importScripts("openpgp.min.js");var n=e.openpgp,t=[],r=6e4;n.crypto.random.randomBuffer.init(r,function(){return t.length||self.postMessage({event:"request-seed",amount:r}),new Promise(function(e){t.push(e)})}),self.onmessage=function(e){var r,s=e.data||{};switch(s.event){case"configure":r=s.config,Object.keys(r).forEach(function(e){n.config[e]=r[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));n.crypto.random.randomBuffer.set(e)}(s.buf);var u=t;t=[];for(var c=0;c<u.length;c++)u[c]();break;default:!function(e,t,r){if("clear-key-cache"===t)return Array.from(o.values()).forEach(e=>{e.isPrivate()&&e.clearPrivateParams()}),o.clear(),void i({id:e,event:"method-return"});if("function"!=typeof n[t])return void i({id:e,event:"method-return",err:"Unknown Worker Event"});n.util.restoreStreams(r),(r=n.packet.clone.parseClonedPackets(r,t)).publicKeys&&(r.publicKeys=r.publicKeys.map(a));r.privateKeys&&(r.privateKeys=r.privateKeys.map(a));n[t](r).then(function(t){i({id:e,event:"method-return",data:n.packet.clone.clonePackets(t)})}).catch(function(t){n.util.print_debug_error(t),i({id:e,event:"method-return",err:t.message,stack:t.stack})})}(s.id,s.event,s.options||{})}};const o=new Map;function a(e){const n=e.armor();return o.has(n)?o.get(n):(o.set(n,e),e)}function i(e){self.postMessage(e,n.util.getTransferables(e.data,!0))}postMessage({event:"loaded"})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1]);

43718
dist/openpgp.js vendored

File diff suppressed because one or more lines are too long

2
dist/openpgp.min.js vendored

File diff suppressed because one or more lines are too long

173
dist/openpgp.worker.js vendored
View File

@ -1,173 +0,0 @@
/*! OpenPGP.js v4.10.3 - 2020-04-21 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (global){
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/* eslint-disable no-restricted-globals */
/* eslint-disable no-var */
/* eslint-disable vars-on-top */
/**
* @fileoverview Provides functions for communicating with workers
* @see module:openpgp.initWorker
* @see module:openpgp.getWorker
* @see module:openpgp.destroyWorker
* @see module:worker/async_proxy
* @module worker/worker
*/
importScripts('openpgp.js');
var openpgp = global.openpgp;
var randomQueue = [];
var MAX_SIZE_RANDOM_BUFFER = 60000;
/**
* Handle random buffer exhaustion by requesting more random bytes from the main window
* @returns {Promise<Object>} Empty promise whose resolution indicates that the buffer has been refilled
*/
function randomCallback() {
if (!randomQueue.length) {
self.postMessage({ event: 'request-seed', amount: MAX_SIZE_RANDOM_BUFFER });
}
return new Promise(function(resolve) {
randomQueue.push(resolve);
});
}
openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER, randomCallback);
/**
* Handle messages from the main window.
* @param {Object} event Contains event type and data
*/
self.onmessage = function(event) {
var msg = event.data || {};
switch (msg.event) {
case 'configure':
configure(msg.config);
break;
case 'seed-random':
seedRandom(msg.buf);
var queueCopy = randomQueue;
randomQueue = [];
for (var i = 0; i < queueCopy.length; i++) {
queueCopy[i]();
}
break;
default:
delegate(msg.id, msg.event, msg.options || {});
}
};
/**
* Set config from main context to worker context.
* @param {Object} config The openpgp configuration
*/
function configure(config) {
Object.keys(config).forEach(function(key) {
openpgp.config[key] = config[key];
});
}
/**
* Seed the library with entropy gathered global.crypto.getRandomValues
* as this api is only avalible in the main window.
* @param {ArrayBuffer} buffer Some random bytes
*/
function seedRandom(buffer) {
if (!(buffer instanceof Uint8Array)) {
buffer = new Uint8Array(buffer);
}
openpgp.crypto.random.randomBuffer.set(buffer);
}
const keyCache = new Map();
function getCachedKey(key) {
const armor = key.armor();
if (keyCache.has(armor)) {
return keyCache.get(armor);
}
keyCache.set(armor, key);
return key;
}
/**
* Generic proxy function that handles all commands from the public api.
* @param {String} method The public api function to be delegated to the worker thread
* @param {Object} options The api function's options
*/
function delegate(id, method, options) {
if (method === 'clear-key-cache') {
Array.from(keyCache.values()).forEach(key => {
if (key.isPrivate()) {
key.clearPrivateParams();
}
});
keyCache.clear();
response({ id, event: 'method-return' });
return;
}
if (typeof openpgp[method] !== 'function') {
response({ id:id, event:'method-return', err:'Unknown Worker Event' });
return;
}
// construct ReadableStreams from MessagePorts
openpgp.util.restoreStreams(options);
// parse cloned packets
options = openpgp.packet.clone.parseClonedPackets(options, method);
// cache keys by armor, so that we don't have to repeatedly verify self-signatures
if (options.publicKeys) {
options.publicKeys = options.publicKeys.map(getCachedKey);
}
if (options.privateKeys) {
options.privateKeys = options.privateKeys.map(getCachedKey);
}
openpgp[method](options).then(function(data) {
// clone packets (for web worker structured cloning algorithm)
response({ id:id, event:'method-return', data:openpgp.packet.clone.clonePackets(data) });
}).catch(function(e) {
openpgp.util.print_debug_error(e);
response({
id:id, event:'method-return', err:e.message, stack:e.stack
});
});
}
/**
* Respond to the main window.
* @param {Object} event Contains event type and data
*/
function response(event) {
self.postMessage(event, openpgp.util.getTransferables(event.data, true));
}
/**
* Let the main window know the worker has loaded.
*/
postMessage({ event: 'loaded' });
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[1]);

View File

@ -1,2 +0,0 @@
/*! OpenPGP.js v4.10.3 - 2020-04-21 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
!function(){return function e(n,t,r){function o(i,s){if(!t[i]){if(!n[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(a)return a(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var f=t[i]={exports:{}};n[i][0].call(f.exports,function(e){return o(n[i][1][e]||e)},f,f.exports,e,n,t,r)}return t[i].exports}for(var a="function"==typeof require&&require,i=0;i<r.length;i++)o(r[i]);return o}}()({1:[function(e,n,t){(function(e){importScripts("openpgp.min.js");var n=e.openpgp,t=[],r=6e4;n.crypto.random.randomBuffer.init(r,function(){return t.length||self.postMessage({event:"request-seed",amount:r}),new Promise(function(e){t.push(e)})}),self.onmessage=function(e){var r,s=e.data||{};switch(s.event){case"configure":r=s.config,Object.keys(r).forEach(function(e){n.config[e]=r[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));n.crypto.random.randomBuffer.set(e)}(s.buf);var u=t;t=[];for(var c=0;c<u.length;c++)u[c]();break;default:!function(e,t,r){if("clear-key-cache"===t)return Array.from(o.values()).forEach(e=>{e.isPrivate()&&e.clearPrivateParams()}),o.clear(),void i({id:e,event:"method-return"});if("function"!=typeof n[t])return void i({id:e,event:"method-return",err:"Unknown Worker Event"});n.util.restoreStreams(r),(r=n.packet.clone.parseClonedPackets(r,t)).publicKeys&&(r.publicKeys=r.publicKeys.map(a));r.privateKeys&&(r.privateKeys=r.privateKeys.map(a));n[t](r).then(function(t){i({id:e,event:"method-return",data:n.packet.clone.clonePackets(t)})}).catch(function(t){n.util.print_debug_error(t),i({id:e,event:"method-return",err:t.message,stack:t.stack})})}(s.id,s.event,s.options||{})}};const o=new Map;function a(e){const n=e.armor();return o.has(n)?o.get(n):(o.set(n,e),e)}function i(e){self.postMessage(e,n.util.getTransferables(e.data,!0))}postMessage({event:"loaded"})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1]);

File diff suppressed because one or more lines are too long

986
docs/Argon2S2K.html Normal file

File diff suppressed because one or more lines are too long

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
docs.openpgpjs.org

1366
docs/CleartextMessage.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

5397
docs/Key.html Normal file

File diff suppressed because one or more lines are too long

1590
docs/LiteralDataPacket.html Normal file

File diff suppressed because one or more lines are too long

348
docs/MarkerPacket.html Normal file

File diff suppressed because one or more lines are too long

4870
docs/Message.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

1283
docs/PacketList.html Normal file

File diff suppressed because one or more lines are too long

600
docs/PaddingPacket.html Normal file

File diff suppressed because one or more lines are too long

1893
docs/PrivateKey.html Normal file

File diff suppressed because one or more lines are too long

618
docs/PublicKey.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

2472
docs/PublicKeyPacket.html Normal file

File diff suppressed because one or more lines are too long

2586
docs/PublicSubkeyPacket.html Normal file

File diff suppressed because one or more lines are too long

3852
docs/SecretKeyPacket.html Normal file

File diff suppressed because one or more lines are too long

3921
docs/SecretSubkeyPacket.html Normal file

File diff suppressed because one or more lines are too long

629
docs/Signature.html Normal file

File diff suppressed because one or more lines are too long

1848
docs/SignaturePacket.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

277
docs/TrustPacket.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

668
docs/UserIDPacket.html Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

11739
docs/global.html Normal file

File diff suppressed because one or more lines are too long

723
docs/index.html Normal file

File diff suppressed because one or more lines are too long

4015
docs/module-config.html Normal file

File diff suppressed because one or more lines are too long

184
docs/module-crypto.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

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

Some files were not shown because too many files have changed in this diff Show More