{"id":20244321,"url":"https://github.com/protonmail/pmcrypto","last_synced_at":"2025-08-21T00:31:59.696Z","repository":{"id":24409327,"uuid":"101417976","full_name":"ProtonMail/pmcrypto","owner":"ProtonMail","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-01T08:05:54.000Z","size":2783,"stargazers_count":42,"open_issues_count":5,"forks_count":21,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-08-08T21:14:53.660Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ProtonMail.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-08-25T15:36:51.000Z","updated_at":"2025-07-31T19:47:54.000Z","dependencies_parsed_at":"2023-10-02T20:02:22.810Z","dependency_job_id":"8032b0ac-ea07-4542-af39-04961c8e5d46","html_url":"https://github.com/ProtonMail/pmcrypto","commit_stats":{"total_commits":387,"total_committers":31,"mean_commits":"12.483870967741936","dds":0.7932816537467701,"last_synced_commit":"b32dc478285314e5e93e515f91eb3f04e913dc0c"},"previous_names":[],"tags_count":152,"template":false,"template_full_name":null,"purl":"pkg:github/ProtonMail/pmcrypto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fpmcrypto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fpmcrypto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fpmcrypto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fpmcrypto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ProtonMail","download_url":"https://codeload.github.com/ProtonMail/pmcrypto/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fpmcrypto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271409446,"owners_count":24754715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T09:14:27.954Z","updated_at":"2025-08-21T00:31:59.683Z","avatar_url":"https://github.com/ProtonMail.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pmcrypto\n\npmcrypto v8 introduces support for [RFC9580](https://datatracker.ietf.org/doc/rfc9580/) (via [OpenPGP.js v6](https://github.com/openpgpjs/openpgpjs/releases/tag/v6.0.0)), which standardizes new OpenPGP packets and algorithms, such as v6 keys and AEAD encryption for keys and messages. The [OpenPGP PQC RFC draft](https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/) also builds on top of RFC9580.\n\nThe new entities are not supported across Proton clients yet, and most of the library changes compared to v7 are internal, and are about ensuring we don't unexpectedly produce (or accept, e.g. for key imports), artifacts that will break some of our existing clients.\n\nAPI changes:\n\n- `checkKeyCompatibility`:\n  - reject v5 keys (breaking change: these were supported by pmcrypto v7, as they were introduced in draft RFC4880bis, but we are dropping support as they haven't been standardized)\n  - add `v6KeysAllowed` argument (defaulting to false) to accept v6 keys\n\n\n## Usage\npmcrypto must be initialized using the `init` function, to apply changes to the underlying OpenPGP.js configuration.\n\n```js\nimport { init } from 'pmcrypto';\n\ninit();\n```\n\n### Examples\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEncrypt/sign and decrypt/verify string or binary data using keys\u003c/b\u003e\u003c/summary\u003e\n\n#### Encrypt/sign and decrypt/verify string or binary data using keys\n\nTo parse and decrypt the keys\n```js\nconst recipientPublicKey = await readKey({ armoredKey: '...' }); // or `binaryKey`\nconst senderPrivateKey = await decryptKey({\n  privateKey: await readPrivateKey({ armoredKey: '...' }),\n  passphrase: 'personal key passphrase'\n});\n```\nTo encrypt and sign:\n```js\nconst { \n  message: armoredMessage,\n  encryptedSignature: armoredEncryptedSignature\n} = await encryptMessage({\n  textData: 'text data to encrypt', // or `binaryData` for Uint8Arrays\n  encryptionKeys: recipientPublicKey, // and/or `passwords`\n  signingKeys: senderPrivateKey,\n  detached: true,\n  format: 'armored' // or 'binary' to output a binary message and signature\n});\n\n// share `armoredMessage`\n```\nTo decrypt and verify (non-streamed input):\n```js\n// load the required keys\nconst senderPublicKey = await readKey(...);\nconst recipientPrivateKey = await decryptKey(...);\n\nconst { data: decryptedData, verificationStatus } = await decryptMessage({\n  message: await readMessage({ armoredMessage }), // or `binaryMessage`\n  encryptedSignature: await readMessage({ armoredMessage: armoredEncryptedSignature })\n  decryptionKeys: recipientPrivateKey // and/or 'passwords'\n  verificationKeys: senderPublicKey\n});\n```\n\n**For streamed inputs:**\nto encrypt (and/or sign), pass the stream to `textData` or `binaryData` based on the streamed data type. Similarly, to decrypt and verify, the input options are the same as the non-streaming case. However, if `armoredMessage` (or `binaryMessage`) is a stream, the decryption result needs to be handled differently:\n```js\n// explicitly loading stream polyfills for legacy browsers is required since v7.2.2\nif (!globalThis.TransformStream) {\n  await import('web-streams-polyfill/es6');\n}\n\nconst { data: dataStream, verificationStatus: verifiedPromise } = await decryptMessage({\n  message: await readMessage({ armoredMessage: streamedArmoredMessage }),\n  ... // other options\n});\n\n// you need to read `dataStream` before resolving `verifiedPromise`, even if you do not need the decrypted data\nconst decryptedData = await readToEnd(dataStream);\nconst verificationStatus = await verificationStatus;\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEncrypt/decrypt using the session key\u003c/b\u003e\u003c/summary\u003e\n\n#### Encrypt/decrypt using the session key directly\nIn v6, `encryptMessage` would return the generated session key if `options.returnSessionKey: true` was given. This option is no longer supported. Instead:\n```js\n// First generate the session key\nconst sessionKey = await generateSessionKey({ recipientKeys: recipientPublicKey });\n\n// Then encrypt the data with it\nconst { message: armoredMessage } = await encryptMessage({\n  textData: 'text data to encrypt', // or `binaryData` for Uint8Arrays\n  sessionKey,\n  encryptionKeys: recipientPublicKey, // and/or `passwords`, used to encrypt the session key\n  signingKeys: senderPrivateKey,\n});\n```\n\nTo decrypt, you can again provide the session key directly:\n```js\n\n// Then encrypt the data with it\nconst { data } = await decryptMessage({\n  message: await readMessage({ armoredMessage }),\n  sessionKeys: sessionKey,\n  verificationKeys: senderPublicKey,\n});\n```\nYou can also encrypt the session key on its own:\n```js\nconst armoredEncryptedSessionKey = await encryptSessionKey({\n  sessionKey,\n  encryptionKeys, // and/or passwords\n  format: 'armored'\n});\n\n// And decrypt it with:\nconst sessionKey = await decryptSessionKey({\n  message: await readMessage({ armoredMessage: armoredEncryptedSessionKey }),\n  decryptionsKeys // and/or passwords\n});\n\n```\n\u003c/details\u003e\n\n## Testing\nHeadless Chrome (or Chromium), Firefox and Webkit are used for the tests.\nTo install any missing browsers automatically, you can run `npx playwright install --with-deps \u003cchromium|firefox|webkit\u003e`. Alternatively, you can install them manually as you normally would on your platform.\nIf you'd like to test on a subset of browsers, use e.g. `npm test -- --browsers ChromeHeadless,FirefoxHeadless`.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprotonmail%2Fpmcrypto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprotonmail%2Fpmcrypto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprotonmail%2Fpmcrypto/lists"}