{"id":19880007,"url":"https://github.com/passbolt/gopenpgp","last_synced_at":"2025-10-20T06:56:13.531Z","repository":{"id":203048663,"uuid":"690494554","full_name":"passbolt/gopenpgp","owner":"passbolt","description":null,"archived":false,"fork":false,"pushed_at":"2023-12-12T12:20:18.000Z","size":100332,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-01T02:42:38.610Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/passbolt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2023-09-12T09:57:31.000Z","updated_at":"2023-10-04T07:55:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"d5292d63-ba90-4d77-aa54-5d7c450c956a","html_url":"https://github.com/passbolt/gopenpgp","commit_stats":null,"previous_names":["passbolt/gopenpgp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/passbolt/gopenpgp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passbolt%2Fgopenpgp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passbolt%2Fgopenpgp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passbolt%2Fgopenpgp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passbolt%2Fgopenpgp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/passbolt","download_url":"https://codeload.github.com/passbolt/gopenpgp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passbolt%2Fgopenpgp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266572391,"owners_count":23950012,"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-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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-12T17:09:59.228Z","updated_at":"2025-10-20T06:56:13.512Z","avatar_url":"https://github.com/passbolt.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GopenPGP V3\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/ProtonMail/gopenpgp/v3)](https://goreportcard.com/report/github.com/ProtonMail/gopenpgp/v3)\n[![GoDoc](https://godoc.org/github.com/ProtonMail/gopenpgp/v3?status.svg)](https://godoc.org/github.com/ProtonMail/gopenpgp/v3)\n\nGopenPGP V3 is a high-level OpenPGP library built on top of [a fork of the golang\ncrypto library](https://github.com/ProtonMail/go-crypto).\n\n**Table of Contents**\n\n\u003c!-- TOC depthFrom:2 --\u003e\n\n- [GopenPGP V3](#gopenpgp-v3)\n  - [GopenPGP V2 support](#gopenpgp-v2-support)\n  - [Download/Install](#downloadinstall)\n  - [Documentation](#documentation)\n  - [Examples](#examples)\n    - [Encrypt / Decrypt with a password](#encrypt--decrypt-with-a-password)\n    - [Encrypt / Decrypt with PGP keys](#encrypt--decrypt-with-pgp-keys)\n    - [Generate key](#generate-key)\n    - [Detached and inline signatures](#detached-and-inline-signatures)\n    - [Cleartext signed messages](#cleartext-signed-messages)\n    - [Encrypt with different outputs](#encrypt-with-different-outputs)\n  - [Using with Go Mobile](#using-with-go-mobile)\n\n\u003c!-- /TOC --\u003e\n\n##  GopenPGP V2 support\n\nWhile GopenPGP V3 introduces a new API with significant enhancements, it is not backward compatible with GopenPGP V2. \nAlthough we recommend upgrading to V3 for the latest features and improvements, we continue to support GopenPGP V2. \nOur support includes ongoing bug fixes and minor feature updates to ensure stability and functionality for existing users.\n\nGopenPGP V2 can be accessed/modified via the [v2 branch of this repository](https://github.com/ProtonMail/gopenpgp/tree/v2).\n\n## Download/Install\n\nTo use GopenPGP with [Go Modules](https://github.com/golang/go/wiki/Modules) just run \n```\ngo get github.com/ProtonMail/gopenpgp/v3\n```\nin your project folder.\n\nThen, your code can include it as follows:\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/ProtonMail/gopenpgp/v3/crypto\"\n)\n\nfunc main() {\n\tpgp := crypto.PGP()\n}\n```\n\n## Documentation\n\nA full overview of the API can be found here: https://pkg.go.dev/github.com/ProtonMail/gopenpgp/v3.\n\n## Examples\n\nA file of runnable examples can be found in [crypto_example_test.go](crypto/crypto_example_test.go).\n\n### Encrypt / Decrypt with a password\n\n```go\nimport \"github.com/ProtonMail/gopenpgp/v3/crypto\"\n\npassword := []byte(\"hunter2\")\n\npgp := crypto.PGP()\n// Encrypt data with a password\nencHandle, err := pgp.Encryption().Password(password).New()\npgpMessage, err := encHandle.Encrypt([]byte(\"my message\"))\narmored, err := pgpMessage.ArmorBytes()\n\n// Decrypt data with a password\ndecHandle, err := pgp.Decryption().Password(password).New()\ndecrypted, err := decHandle.Decrypt(armored, crypto.Armor)\nmyMessage := decrypted.Bytes()\n```\n\nTo encrypt with the [latest OpenPGP standard (RFC 9580)](https://www.rfc-editor.org/rfc/rfc9580.html):\n```go\nimport \"github.com/ProtonMail/gopenpgp/v3/profile\"\n\n// Use the latest OpenPGP standard (RFC 9580).\npgp := crypto.PGPWithProfile(profile.RFC9580())\n// The RFC9580 profile uses Argon2 for protecting encrypted keys and\n// messages encrypted using a passphrase, and uses AEAD for encryption\n// (AES-256, OCB mode).\n// Encrypt/Decrypt data with a password\n... // See code snippet above.\n```\n\nUse a custom or preset profile:\n```go\nimport \"github.com/ProtonMail/gopenpgp/v3/profile\"\n\n// RFC4880 profile\npgp4880 := crypto.PGPWithProfile(profile.RFC4880()) \n// RFC9580 profile\npgpCryptoRefresh := crypto.PGPWithProfile(profile.RFC9580())\n```\n\n### Encrypt / Decrypt with PGP keys\n\n```go\n// Put keys in backtick (``) to avoid errors caused by spaces or tabs\nconst pubkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----`\n\nconst privkey = `-----BEGIN PGP PRIVATE KEY BLOCK-----\n...\n-----END PGP PRIVATE KEY BLOCK-----` // Encrypted private key\n\nconst passphrase = []byte(`the passphrase of the private key`) // Passphrase of the privKey\npublicKey, err := crypto.NewKeyFromArmored(pubkey)\nprivateKey, err := crypto.NewPrivateKeyFromArmored(privkey, passphrase)\n\npgp := crypto.PGP()\n// Encrypt plaintext message using a public key\nencHandle, err := pgp.Encryption().Recipient(publicKey).New()\npgpMessage, err := encHandle.Encrypt([]byte(\"my message\"))\narmored, err := pgpMessage.ArmorBytes()\n\n// Decrypt armored encrypted message using the private key and obtain the plaintext\ndecHandle, err := pgp.Decryption().DecryptionKey(privateKey).New()\ndecrypted, err := decHandle.Decrypt(armored, crypto.Armor)\nmyMessage := decrypted.Bytes()\n\ndecHandle.ClearPrivateParams()\n```\n\nWith signatures:\n```go\npgp := crypto.PGP()\naliceKeyPriv, err := pgp.KeyGeneration().\n  AddUserId(\"alice\", \"alice@alice.com\").\n  New().\n  GenerateKey()\naliceKeyPub, err := aliceKeyPriv.ToPublic()\n\nbobKeyPriv, err := pgp.KeyGeneration().\n  AddUserId(\"bob\", \"bob@bob.com\").\n  New().\n  GenerateKey()\nbobKeyPub, err := bobKeyPriv.ToPublic()\n\n// Encrypt and sign plaintext message from alice to bob\nencHandle, err := pgp.Encryption().\n  Recipient(bobKeyPub).\n  SigningKey(aliceKeyPriv).\n  New()\npgpMessage, err := encHandle.Encrypt([]byte(\"my message\"))\narmored, err := pgpMessage.ArmorBytes()\n\n// Decrypt armored encrypted message using the private key and obtain plain text\ndecHandle, err := pgp.Decryption().\n  DecryptionKey(bobKeyPriv).\n  VerificationKey(aliceKeyPub).\n  New()\ndecrypted, err := decHandle.Decrypt(armored, crypto.Armor)\nif sigErr := decrypted.SignatureError(); sigErr != nil {\n  // Signature verification failed with sigErr\n}\nmyMessage := decrypted.Bytes()\n\nencHandle.ClearPrivateParams()\ndecHandle.ClearPrivateParams()\n```\nEncrypt towards multiple recipients:\n```go\nrecipients, err := crypto.NewKeyRing(bobKeyPub)\nerr = recipients.AddKey(carolKeyPub)\n// encrypt plain text message using a public key\nencHandle, err := pgp.Encryption().\n  Recipients(recipients).\n  SigningKey(aliceKeyPriv).\n  New()\npgpMessage, err := encHandle.Encrypt([]byte(\"my message\"))\narmored, err := pgpMessage.ArmorBytes()\n\nencHandle.ClearPrivateParams()\n```\n\nEncrypt towards an (anonymous) recipient:\n```go\n//...\n// The key fingerprint of bob's key is visible in the key packet and\n// is included in the signature's intended recipient list.\n// The key fingerprint of carols's key is not visible in the key packet (\"anonymous\" key packet), and\n// is not included in the signature's intended recipient list.\nencHandle, _ := pgp.Encryption().\n  Recipient(bobKeyPub).\n  HiddenRecipient(carolKeyPub).\n  SigningKey(aliceKeyPriv).\n  New()\npgpMessage, _ := encHandle.Encrypt([]byte(\"my message\"))\n\n// Decrypt checks if bobs key fingerprint is in the intended recipient list\n// of alice's signature in the message.\ndecHandleBob, _ := pgp.Decryption().\n  DecryptionKey(bobKeyPriv).\n  VerificationKey(aliceKeyPub).\n  New()\ndecryptedBob, _ := decHandleBob.Decrypt(pgpMessage.Bytes(), crypto.Bytes)\nfmt.Println(string(decryptedBob.Bytes()))\n\n// Disable intended recipient check, there is no info about carols key in the message.\n// The decryption function tries all supplied keys for decrypting the \"anonymous\" key packet.\n// If the check is not disabled, the decryption result would contain a signature error.\ndecHandleCarol, _ := pgp.Decryption().\n  DecryptionKey(carolKeyPriv).\n  VerificationKey(aliceKeyPub).\n  DisableIntendedRecipients().\n  New()\ndecryptedCarol, _ := decHandleCarol.Decrypt(pgpMessage.Bytes(), crypto.Bytes)\n```\n\nEncrypt and decrypt large messages with the streaming API:\n```go\npgp := crypto.PGP()\n// ... See key generation above\n\n// Encrypt plain text stream and write the output to a file\nencHandle, err := pgp.Encryption().\n  Recipient(bobKeyPub).\n  SigningKey(aliceKeyPriv).\n  New()\nmessageReader, err := os.Open(\"msg.txt\")\nciphertextWriter, err := os.Create(\"out.pgp\")\n\nptWriter, err := encHandle.EncryptingWriter(ciphertextWriter, crypto.Armor)\n_, err = io.Copy(ptWriter, messageReader)\nerr = ptWriter.Close()\nerr = messageReader.Close()\nerr = ciphertextWriter.Close()\n\nctFileRead, err := os.Open(\"out.pgp\")\ndefer ctFileRead.Close()\n// Decrypt stream and read the result to memory\ndecHandle, err := pgp.Decryption().\n  DecryptionKey(bobKeyPriv).\n  VerificationKey(aliceKeyPub).\n  New()\nptReader, err := decHandle.DecryptingReader(ctFileRead, crypto.Armor)\ndecResult, err := ptReader.ReadAllAndVerifySignature()\nif sigErr := decResult.SignatureError(); sigErr != nil {\n  // Handle sigErr\n}\n// Access decrypted message with decResult.Bytes()\n```\n### Generate key\nKeys are generated with the `GenerateKey` function on the pgp handle.\n```go\nimport \"github.com/ProtonMail/gopenpgp/v3/constants\"\n\nconst (\n  name = \"Max Mustermann\"\n  email = \"max.mustermann@example.com\"\n  passphrase = []byte(\"LongSecret\")\n)\n\npgpDefault := crypto.PGPWithProfile(profile.Default())\npgp4880 := crypto.PGPWithProfile(profile.RFC4880())\npgpCryptoRefresh := crypto.PGPWithProfile(profile.RFC9580())\n\n// Note that RSA keys should not be generated anymore according to\n// RFC9580.\n\nkeyGenHandle := pgp4880.KeyGeneration().AddUserId(name, email).New()\n// Generates rsa keys with 3072 bits\nrsaKey, err := keyGenHandle.GenerateKey()\n// Generates rsa keys with 4096 bits\nrsaKeyHigh, err := keyGenHandle.GenerateKeyWithSecurity(constants.HighSecurity)\n\nkeyGenHandle = pgpDefault.KeyGeneration().AddUserId(name, email).New()\n// Generates curve25519 v4 keys.\necKey, err := keyGenHandle.GenerateKey()\n\nkeyGenHandle = pgpCryptoRefresh.KeyGeneration().AddUserId(name, email).New()\n// Generates curve25519 v6 keys with RFC9580.\necKey, err = keyGenHandle.GenerateKey()\n// Generates curve448 v6 keys with RFC9580.\necKeyHigh, err = keyGenHandle.GenerateKeyWithSecurity(constants.HighSecurity)\n```\n\nEncrypt (lock) and decrypt (unlock) a secret key:\n```go\npassword := []byte(\"password\")\n\npgp := crypto.PGP()\n// Encrypt key with password\nlockedKey, err := pgp.LockKey(aliceKeyPriv, password)\n// Decrypt key with password\nunlockedKey, err := lockedKey.Unlock(password)\n```\n\n### Detached and inline signatures\n\nSign a plaintext with a private key and verify it with its public key using detached signatures: \n\n```go\npgp := crypto.PGP()\n// ... See generating keys \n\nsigningMessage := []byte(\"message to sign\")\n\nsigner, err := pgp.Sign().SigningKey(aliceKeyPriv).Detached().New()\nsignature, err := signer.Sign(signingMessage, crypto.Armor)\n\nverifier, err := pgp.Verify().VerificationKey(aliceKeyPub).New()\nverifyResult, err := verifier.VerifyDetached(signingMessage, signature, crypto.Armor)\nif sigErr := verifyResult.SignatureError(); sigErr != nil {\n  // Handle sigErr\n}\n\nsigner.ClearPrivateParams()\n```\n\n\nSign a plaintext with a private key and verify it with its public key using inline signatures: \n\n```go\npgp := crypto.PGP()\n// ... See generating keys \n\nsigningMessage := []byte(\"message to sign\")\n\nsigner, err := pgp.Sign().SigningKey(aliceKeyPriv).New()\nsignatureMessage, err := signer.Sign(signingMessage, crypto.Armor)\n\nverifier, err := pgp.Verify().VerificationKey(aliceKeyPub).New()\nverifyResult, err := verifier.VerifyInline(signatureMessage, crypto.Armor)\nif sigErr := verifyResult.SignatureError(); sigErr != nil {\n  // Handle sigErr\n}\n// Access signed data with verifyResult.Bytes()\nsigner.ClearPrivateParams()\n```\n\n\n\n### Cleartext signed messages\n```go\npgp := crypto.PGP()\n// ... See generating keys \n\nsigningMessage := []byte(\"message to sign\")\n\nsigner, err := pgp.Sign().SigningKey(aliceKeyPriv).New()\ncleartextArmored, err := signer.SignCleartext(signingMessage)\n// CleartextArmored has the form:\n// -----BEGIN PGP SIGNED MESSAGE-----\n// ...\n// -----BEGIN PGP SIGNATURE-----\n// ...\n// -----END PGP SIGNATURE-----\n\nverifier, err := pgp.Verify().VerificationKey(aliceKeyPub).New()\nverifyResult, err := verifier.VerifyCleartext(cleartextArmored)\nif sigErr := verifyResult.SignatureError(); sigErr != nil {\n  // Handle sigErr\n}\n\nsigner.ClearPrivateParams()\n```\n\n### Encrypt with different outputs\n\nSplit encrypted message into key packets and data packets \n```go\n// Non-streaming\npgpMessage, err := encHandle.Encrypt(...)\nkeyPackets := pgpMessage.BinaryKeyPacket()\ndataPackets := pgpMessage.BinaryDataPacket()\n\n// Streaming \nvar keyPackets bytes.Buffer\nvar dataPackets bytes.Buffer\nsplitWriter := crypto.NewPGPSplitWriterKeyAndData(\u0026keyPackets, \u0026dataPackets)\nptWriter, _ := encHandle.EncryptingWriter(splitWriter, crypto.Bytes)\n// ...\n// Key packets are written to keyPackets while data packets are written to dataPackets\n```\n\nProduce encrypted detached signatures instead of embedded signatures:\n```go\n// Non-streaming\nencHandle, err := pgp.Encryption().\n  Recipient(bobKeyPub).\n  SigningKey(aliceKeyPriv).\n  DetachedSignature().\n  New() // Enable the detached signature option\npgpMessage, err := encHandle.Encrypt(...)\npgpMessageEncSig, err := pgpMessage.EncryptedDetachedSignature()\n// pgpMessage.Bytes() encrypted message without an embedded signature\n// pgpMessageEncSig.Bytes() encrypted signature message\n// pgpMessage:        key packets|enc data packets\n// pgpMessageEncSig:  key packets|enc signature packet\n\n\n// Streaming \n// ...\nvar encSigDataPackets bytes.Buffer\nsplitWriter := crypto.NewPGPSplitWriter(\u0026keyPackets, \u0026dataPackets, \u0026encSigDataPackets)\nptWriter, err := encHandle.EncryptingWriter(splitWriter, crypto.Bytes)\n// ...\n// Key packets are written to keyPackets, data packets are written to dataPackets ,and\n// Data packets of the encrypted signature to encSigDataPackets\n```\n\n## Using with Go Mobile\nThis library can be compiled with [Gomobile](https://github.com/golang/go/wiki/Mobile) too.\nFirst ensure you have a working installation of gomobile:\n```bash\ngomobile version\n```\nIn case this fails, install it with:\n```bash\ngo get -u golang.org/x/mobile/cmd/gomobile\n```\nThen ensure your path env var has gomobile's binary, and it is properly init-ed:\n```bash\nexport PATH=\"$PATH:$GOPATH/bin\"\ngomobile init\n```\nThen you must ensure that the Android or iOS frameworks are installed and the respective env vars set.\n\nFinally, build the application\n```bash\nsh build.sh\n```\nThis script will build for both android and iOS at the same time,\nto filter one out you can comment out the line in the corresponding section.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpassbolt%2Fgopenpgp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpassbolt%2Fgopenpgp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpassbolt%2Fgopenpgp/lists"}